Sections

Saturday, February 9, 2013

Dumping an EPROM using an ATMEGA MCU

I recently built a development board using an ATMEGA 1284-PU microcontroller and some spare components I had lying around. Since then, I searched for fun & cool things to do with it: there are the usual sensors reading/LED matrix lighting/graphic LCD drawing/motor controlling experiments available, but my interest lies in data preservation so, as a first task, I decided dump a few EPROMs that dwelt undisturbed in my junk box for too long.
This mess of wires actually works as an EPROM dumper!

First of all, a small intro on EPROMs. Their name is an acronym and it stands for Erasable Programmable Read Only Memory, which almost says it all: they're a bank of memory which can normally be only read (ROM) and is erased (E) by exposing the enclosed die to UV light (and that is why there usually is a sticker covering it: to prevent accidental erasure by ambient light!). When empty, it can be electronically programmed (P).
EPROM with die exposed, courtesy of Wikipedia
As with every kind of computer memory, to make any use of it we need to be able to address it: that is, we need a way to compose the address corresponding to the memory block we want to access. On an EPROM we do that by setting the address lines and then reading the data lines to get the information. The count and location of data and address lines on the IC depends on the specific model, and the model I'm trying to read is an AM27C1024 by AMD.

Am AM27C1024 chip and its pinout
Looking at the pinout we notice a bunch of lines which share a similar name, minus the numbers at the end: DQ and A. The A lines are the address lines, the DQ are data lines: the memory address is composed on the address lines, and the data lines are toggled by the IC in a way that reflects the stored information. Another thing we notice is that this chip has 16 address lines and 16 data lines: this info (coupled with a superficial reading of the datasheet) tell us that this particular EPROM model stores the information in 16 bit words (one data wire for each bit).

So, how much information can be stored inside here, at most? Let's do some simple math. We have 16 address lines, which can be toggled either HIGH or LOW (two states): a total of all the possible combinations we can make with them is 2^16 = 65536. So, we have roughly 65K addresses available and at each address we have a 16 bit word: 65536 * 16 = 1048576 bits or 131072 bytes (8 bits = 1 byte) or 128Kb (1024 bytes = 1Kb). Lots of space huh? :-)

Ok, we need to toggle 16 lines to form the address, and read 16 other lines to get the data: that's 32 lines in total. The 1284 MCU on my devboard has a total of 32 I/O lines, which would suffice if we did't have to send the data to another computer! This takes away from us two lines that we have to use for serial communication (the receive and transmission lines): we need an external help to get enough I/O lines back! My solution was to wire up a MCP23S17 port expander. The MCP23S17 adds two 8 bits I/O ports and is driven using the SPI bus (4 wires), this means I now have a total of 42 free I/O lines (32 - 2 for serial - 4 for SPI + 16 from the expander): more than enough!

Let's see how I wired up everything:
If you look at the scheme above, you can see that the data lines are connected to port A and port B on the MCP23S17 chip, and the address lines are connected to port A and port C on the ATMEGA (A word of warning: the diagram above does NOT show how I wired up the rest of the circuit for the ATMEGA, you can refer to this for the minimal circuit and this for the MAX232 serial converter, should you need one).

On both the MCP23S17 and AM27C1024 there are lines directly connected to +5v and GND, let's see what's this all about. First of all, after some pin labels there is a '#' symbol (or a black line above the label): this means that the line is of the ACTIVE LOW type, or that it gets enabled when connected to GND and disabled when connected to Vcc.
As for the MCP23S17, the interesting lines are RESET# (speaks for itself), which being active low we have to connect to +5v (so the chip does NOT reset), and A0-2: these are address lines, and can be used to connect more than one port expander to the same SPI bus on the microcontroller. I did not need to do this, so all the address lines went to GND, meaning the address for this expander is 0.
As for the AM27C1024, we have the PGM# pin (which is the line that enables programming of data on the chip: we need to disable this, thus we wire it to +5v), the CE# (Chip Enable) and the OE# (Output Enable) pins. Both CE# and OE# needs to be enabled, which means connected to GND.

We're set! Now we need to program the MCU (I use avrdude and upload the code through the serial port, thanks to the avr-xboot bootloader) with something that iterates through all the addresses, reading the data lines using the MCP23S17. You can find my code HERE on github: it uses a SPI library taken from here and serial communication code from here. The comments are inside the code.
The MCU will output the read data on the first serial port (pins PD0 and PD1) in this format:
0x0000 : 0x80 0x60
0x0001 : 0xF0 0xAA
...
0xFFFF : 0x00 0x00
All you have to do is save the output from your serial terminal emulation software (with minicom use the -C switch) and use it to regenerate the binary file. You can do it with a really simple snippet of C code: here is a quick & dirty version.
int main(void) {
 FILE *input = fopen("./input.txt", "r");
 FILE *output = fopen("./output.txt", "w");

 unsigned int b1, b2;
 unsigned int addr;

 while (fscanf(input, "%X : %X %X\n", &addr, &b1, &b2) != EOF) {
  uint8_t msb = b2;
  uint8_t lsb = b1;

  fwrite(&msb, 1, 1, output);
  fwrite(&lsb, 1, 1, output);
 }

 fclose(input);
 fclose(output);

 return 1;
}
Now we can go pulling EPROMs out of everything and go into a dumping spree! (And remember to check the datasheets for correct wiring!).

No comments:

Post a Comment