Wednesday, June 14, 2017

TTL Brainfuck Computer Part 7 - EEPROM woes

Another week, another head scratcher. I briefly mentioned past troubles getting an EEPROM writer going with my Arduino. I had another read of the data sheet, and went about rewriting much of the code. I didn't notice any glaring mistakes along the way, but did gain much more confidence that my code was doing what it should be.

Arduino Mega2560 connected to EEPROM

Alas, I still was unable to get any successful data writes onto the chip. I decided to try moving it over to a breadboard with some dip switches for addressing. The address pins are pulled down through 100K resistors, and the other side of the switch is pulled up through 10K resistors. These values should work fine since this is a CMOS chip and I'm not after super fast speeds. They just need to act as a voltage divider not a current source/sink, and I have verified that the voltages are around 4.5 for the high level and 0.3 for the low level.

The I/O pins are connected to one of my LED modules to show the output of the ROM, and to an 8-bit dip switch for entering data. The output enable and chip enable pins are the blue & yellow jumper wires, respectively, which I manually connect to ground or Vdd.

The load signal is connected to the common pole of a DPST switch (tucked above the LEDs next to the ROM), with the normally closed position connected to Vdd and normally open connected to ground.

Manual EEPROM reader/writer after some fixes

The pinout for the EEPROM identical to the RAM chips I'm using (the difference in address line numbers should be immaterial). According to the data sheet, doing a single byte write should have the same steps, as well: Disable output (set OE high), enable the chip (set CE low), and pulse the the Load input low. When the load input goes low, the address is latched; when the load input goes high again, the data is latched.

The main difference with the RAM chip is the timings. When you issue a write, you have to wait ~5ms for the operation to complete before the data will be readable (and before doing another single-byte write). That's definitely not an issue here since I'm doing this all by hand. Unlike the EEPROM in Ben Eater's computer, this one does not specify a maximum pulse width for the write cycle, so I just have a small RC filter to compensate for switch bounce.

Enabling output shows the expected 1s everywhere in the factory-fresh ROM. Before I had the data dip switch, to do a write I would:

Disable the ROM output

Move the I/O lines from the LED array to ground

Press and release the LOAD button

Move the I/O lines back to the LED array

Enable ROM output

This always resulted in a full bank of lit LEDs, suggesting the write failed. There were no signs of floating inputs to suggest it was rapidly changing addresses. To rule out connection issues, I swapped out the EEPROM for one of the RAM chips. Everything worked as expected.

By this point I was at a complete loss. I'd gone over the data sheet another few times. I added some bypass capacitors across the power strips near where the ROM connects to power & ground, I made sure the voltages make sense on the address pins and control signals. I used the dip switches to control the output enable pin to verify that the ROM senses the dip switch signals correctly.

The fact that 2 different software/microcontroller attempts failed, as well as the manual attempts described above, and with the successful test with a RAM chip, it became hard to stand by the "poor craftsman blames his tools" principle... Maybe the data sheet incorrectly omitted a maximum time for the write pulse? Maybe I got a bad batch? Maybe I zapped all four of them them with static? (not likely; I have a grounding strap I touch every time I sit down and have never even noticed a tickle).

Nearly ready to give up rolling my own, I started googling around for existing Arduino X28C256 EEPROM programming code. I came across a forum thread where someone said the chips come software write-protected from the supplier, despite the data sheet saying "The X28C256 is shipped from Xicor with the software data protection NOT ENABLED" (emphasis in original).

The Software Data protection feature requires sub-millisecond timing, so I headed back to my Arduino code, refactored things a bit, and set it up to send the unlock signal. It did not work. The data was still all 1s. In a desperate attempt to avoid an even more intense rage face, I gave up for the night.

The next day it hit me... While the order of the address and data lines is immaterial for normal usage, it is absolutely critical for sending the magic values to do the software unlock. I rearranged the address lines so that they match the pinout (the data already did) and re-ran the unlock. It still failed!

I need to clarify what I mean by "failing" here: The code that writes some test data reads it back and validates it against the test data. It turns on the Arduino built-in LED if it finds a mismatch. That light came on. I assumed this meant the write failed. Thinking that was a dead end, I put the ROM chip into my manual programmer to do some more investigation.

Lo and behold, when I enabled the chip, some of the bits were off! Not only that, but they seem to be the correct bits for the capital T in my test data: "This is ...". The next 3 addresses had the telltale "lower case" bit set, and the 5th address in the ROM had only the 32 bit set, which is a space. Apparently my write succeeded but my verification failed.

After one more pass over my code I finally realized what happened: the test data string in the original version called itself 64 bytes, but it was actually only 60 bytes. Apparently the 3 bytes beyond the end of the string are used for global variables. The writer would write whatever happened to be in those cells to the ROM, then failed verification when it read that value back but the Arduino's memory had changed. Here is the current code for the EEPROM programmer after fixing that issue.

I can now reliably unlock and write data to the EEPROM, and the unlocked chip works as expected in the manual programmer. Some further improvements I want to make are to use buttons to control the writing/unlocking and add a lock feature. This way it won't clobber the ROM every time it turns on, and I'll be able to use it to easily lock the chips once I have them programmed to avoid any unintended writes.

Until then, I've used my manual programmer to write the first program that will run on this computer: