Arduino EEPROM Programmer: Burning a ROM image

Hi,
I was working on a little electronics project: a z80 computer, while I was doing that I needed to program an EEPROM, after seeing the price of a universal programmer, I decided to make my own using an arduino.

So far I managed to read the EEPROM and to erase it using my Arduino, here you can see my code for writing 0's to the EEPROM. Now I want to burn a binary image, let's call it "data.rom", to the EEPROM. I was thinking of using serial communication and then use some sort of script that reads data.rom and that passes byte per byte to the arduino through the serial monitor. The arduino then stores the byte in "D" (see code) and then writes that byte, and then wait for a new byte and so on.

But I'm not so familiar with coding for the arduino, neither with serial communication, so I was hoping someone could help me.

/*
 EEPROM Programmer
*/
#define memsize 8192

int STS   = 13;  // Status Indicator

// The pins that are used for the address bus
int AP[13] = {24,26,30,32,36,38,42,44,48,50,47,51,53};
// Used by the code to decode an address
int AD[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
// The pins used for the Data bus
int DP[8]  = {23,25,29,31,35,37,41,43};
// Used by the code to decode a byte
int DD[8]  = {0,0,0,0,0,0,0,0};

// Pins used for the control bus
int CE  = 6;
int OE  = 4;
int WE  = 2;

int i;          // Used by for-loops
int A;         // Used to store the current address in the main loop
int D;         // Used to store the byte that will be written in that cycle to address A

void setup()
{

  Serial.begin(9600);
  Serial.println("Writing EEPROM...");
  
  // Led that shows activity
  pinMode(STS,   OUTPUT);
  
  // Setup Address Pins 
  for (i=0;i<16;i++)
  {
    pinMode(AP[i],OUTPUT);
  }
  
  // Setup Data Pins
  for (i=0;i<8;i++)
  {
    pinMode(DP[i],OUTPUT);
  }
  
  // Setup Control Pins
  pinMode(CE, OUTPUT);
  pinMode(WE, OUTPUT);
  pinMode(OE, OUTPUT);
  
  // Setup Chip
  digitalWrite(CE, LOW);
  digitalWrite(WE, LOW);
  digitalWrite(OE, HIGH);


  // Loop that writes Byte per byte
  for (A=0;A<memsize;A++)
  {
    // D is the Byte that will be written to the current address(A).
    D=0;
    digitalWrite(STS,HIGH);  //Signal that we're writing.

    // Setup Address Pins
    for (i=0;i<13;i++) 
    {
      if((A&bit(i))>0) 
      {
        AD[i]=HIGH;
      } else {
        AD[i]=LOW;
      }      
      digitalWrite(AP[i],AD[i]);
    }
    
    // Setup Control bus
    digitalWrite(OE,LOW);   // Reads Disabled
    delay(1);               // Give the EEPROM some time to catch up
    digitalWrite(CE,HIGH);  // Chip Enable
    digitalWrite(WE,HIGH);  // Write Enabled
    
    // Setup Data Pins
    for (i=0;i<8;i++)
    {
      if((D&bit(i))>0)
      {
        DD[i]=HIGH;
      } else {
        DD[i]=LOW;
      }      
      digitalWrite(DP[i],DD[i]);
    }
    
    // Write data (D)
    digitalWrite(WE,LOW);      // Write Disabled
    digitalWrite(CE,LOW);      // Chip Disabled
    digitalWrite(OE,HIGH);     // Reads Enabled
    delay(1);
    
   digitalWrite(STS,LOW);      // Signal that we're waiting
   
  }
  
    // We got through the loop, signal that the write was succesfull
    Serial.println("Done...");
}

void loop() {
  // Small loop to show that data was written and device can be removed
  digitalWrite(STS, HIGH);   
  delay(1000);              
  digitalWrite(STS, LOW);    
  delay(1000);              
}

Hi,

I'm not familiar with programming EEPROMs, but seems to me you're almost there.
First I would recommend replacing this:

      if((A&bit(i))>0) 
      {
        AD[i]=HIGH;
      } else {
        AD[i]=LOW;
      }      
      digitalWrite(AP[i],AD[i]);

with:

      digitalWrite(AP[i], bitRead(A,i));

and losing the AD array all together.
Same can be done with the D loop and DD array.

As for reading serial data, you've already managed to use Serial communications, so all you would need (besides from perhaps something like error correction) would be replacing the line:

    D=0;

with something like:

    while (Serial.available()==0) delay(1);
    D = Serial.read();

That would assume you would always send the full content of the EEPROM (8192 bytes) through the serial port.

Good luck!

Regards Dennis

Thanks for the reply!

I did what you told me and I added the following code:D = Serial.read() - '0';  // "-0" to convert ASSCI to the actual data But for some reason the program does this:
-It asks my data, I pass it for example 0
-It stores that data at the current address A
-But then it also stores 0xDD and 0xDA at addresses (A+1) and (A+2)
After a bit of think I realized what was wrong: The serial monitor first sends D, but I also passed "\n" and '\r' so it passes that too, :slight_smile: So if anyone else has this problem, in the serial monitor there's a small box saying something like also send newline and carriage return set that to no newline.
Thanks for all the help, but I still got 1 question: Is it possible to write some sort of program that sends the data that it reads from some file through the serial port so that I don't have to type all the data in the serial monitor because that could save me a lot of time.

Is it possible to write some sort of program that sends the data that it reads from some file through the serial port so that I don't have to type all the data in the serial monitor because that could save me a lot of time.

Of course it is. What OS are you using? What language(s) are you familiar with? Depending on OS and language, this ranges from nearly trivial (C# on Win7 could be used (by me, anyway) to create such a program in under an hour) to challenging.

I'm using windows 7 64 bit and I'm familiar with C, but I don't know anything about sending data through a serial port... I can make a program that reads a file and all, but how do I send a byte over a serial port in C? I'm using Codeblocks with MinGW compiler

Have you looked here?
http://arduino.cc/playground/Main/InterfacingWithSoftware

No, I hadn't looked there yet :s

Thanks i finally got an EEPROM programmer and I didn't spend hundred dollar :smiley:

Here's the code if someone is interested:

#define ARDUINO_WAIT_TIME 2000

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

class Serial
{
    private:
        //Serial comm handler
        HANDLE hSerial;
        //Connection status
        bool connected;
        //Get various information about the connection
        COMSTAT status;
        //Keep track of last error
        DWORD errors;

    public:
        //Initialize Serial communication with the given COM port
        Serial(char *portName);
        //Close the connection
        //NOTA: for some reason you can't connect again before exiting
        //the program and running it again
        ~Serial();
        //Read data in a buffer, if nbChar is greater than the
        //maximum number of bytes available, it will return only the
        //bytes available. The function return -1 when nothing could
        //be read, the number of bytes actually read.
        int ReadData(char *buffer, unsigned int nbChar);
        //Writes data from a buffer through the Serial connection
        //return true on success.
        bool WriteData(char *buffer, unsigned int nbChar);
        //Check if we are actually connected
        bool IsConnected();


};

Serial::Serial(char *portName)
{
    //We're not yet connected
    this->connected = false;

    //Try to connect to the given port throuh CreateFile
    this->hSerial = CreateFile(portName,
            GENERIC_READ | GENERIC_WRITE,
            0,
            NULL,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            NULL);

    //Check if the connection was successfull
    if(this->hSerial==INVALID_HANDLE_VALUE)
    {
        //If not success full display an Error
        if(GetLastError()==ERROR_FILE_NOT_FOUND){

            //Print Error if neccessary
            printf("ERROR: Handle was not attached. Reason: %s not available.\n", portName);

        }
        else
        {
            printf("ERROR!!!");
        }
    }
    else
    {
        //If connected we try to set the comm parameters
        DCB dcbSerialParams = {0};

        //Try to get the current
        if (!GetCommState(this->hSerial, &dcbSerialParams))
        {
            //If impossible, show an error
            printf("failed to get current serial parameters!");
        }
        else
        {
            //Define serial connection parameters for the arduino board
            dcbSerialParams.BaudRate=CBR_9600;
            dcbSerialParams.ByteSize=8;
            dcbSerialParams.StopBits=ONESTOPBIT;
            dcbSerialParams.Parity=NOPARITY;

             //Set the parameters and check for their proper application
             if(!SetCommState(hSerial, &dcbSerialParams))
             {
                printf("ALERT: Could not set Serial Port parameters");
             }
             else
             {
                 //If everything went fine we're connected
                 this->connected = true;
                 //We wait 2s as the arduino board will be reseting
                 Sleep(ARDUINO_WAIT_TIME);
             }
        }
    }

}

Serial::~Serial()
{
    //Check if we are connected before trying to disconnect
    if(this->connected)
    {
        //We're no longer connected
        this->connected = false;
        //Close the serial handler
        CloseHandle(this->hSerial);
    }
}

int Serial::ReadData(char *buffer, unsigned int nbChar)
{
    //Number of bytes we'll have read
    DWORD bytesRead;
    //Number of bytes we'll really ask to read
    unsigned int toRead;

    //Use the ClearCommError function to get status info on the Serial port
    ClearCommError(this->hSerial, &this->errors, &this->status);

    //Check if there is something to read
    if(this->status.cbInQue>0)
    {
        //If there is we check if there is enough data to read the required number
        //of characters, if not we'll read only the available characters to prevent
        //locking of the application.
        if(this->status.cbInQue>nbChar)
        {
            toRead = nbChar;
        }
        else
        {
            toRead = this->status.cbInQue;
        }

        //Try to read the require number of chars, and return the number of read bytes on success
        if(ReadFile(this->hSerial, buffer, toRead, &bytesRead, NULL) && bytesRead != 0)
        {
            return bytesRead;
        }

    }

    //If nothing has been read, or that an error was detected return -1
    return -1;

}


bool Serial::WriteData(char *buffer, unsigned int nbChar)
{
    DWORD bytesSend;

    //Try to write the buffer on the Serial port
    if(!WriteFile(this->hSerial, (void *)buffer, nbChar, &bytesSend, 0))
    {
        //In case it don't work get comm error and return false
        ClearCommError(this->hSerial, &this->errors, &this->status);

        return false;
    }
    else
        return true;
}

bool Serial::IsConnected()
{
    //Simply return the connection status
    return this->connected;
}

int main (void)
{
    int sz;
    char *buffer;

    Serial serial("COM3");// Change this to your COM port

    FILE *fp;
    fp=fopen("rom.bin", "r");
    fseek(fp, 0L, SEEK_END);
    sz = ftell(fp);
    fseek(fp, 0L, SEEK_SET);

    buffer = (char *)malloc(sz);
    fread (buffer, 1, sz, fp);

    int i, n, r;
    n = sz/50;
    r = sz%50;
    for(i=0; i<n; i++)
    {
    serial.WriteData((char*)(buffer + (i*50)), 50);
    Sleep(1000);//Buffer overflow protection
    }
    serial.WriteData((char*)(buffer + (n*50)), r);


    printf("Done writing to serial port.\nSize: %d bytes", sz);
    return 0;
}

Thanks for sharing!

Can you post the final Arduino code too?
Can tell what EEPROM's you can write and how you connected them?

Nice that you figured it out yourself!
You need to indeed just send the raw binary data.

A couple of simple dos commands would have also sufficed:

mode COMXX: 9600,n,8,1
copy /b [FILE] COMXX:

Where you would replace [FILE] with your file and COMXX with your com port.

Or you could create a batch file, on which you can drag the ROM image (not tested, but you get the idea):

@echo off
mode COMXX: 9600,n,8,1
copy /b %1 COMXX:

robtillaart:
Thanks for sharing!

Can you post the final Arduino code too?
Can tell what EEPROM's you can write and how you connected them?

I used an Atmel AT28C64, but using a datasheet you should be able to modify the code to make it work with any other parallel EEPROM. The connections are pretty simple just check my code, one important detail: I added a pull-up resistor to WE because when the Arduino resets the i/O pins go to a high impedance state and the WE pin will pick up noise and you might end up using data loss (Not sure if this explanation is correct, but adding a pull up resistor somehow fixed the weird data corruption when resetting the arduino). For the rest it is just direcly connecting the pins of the EEPROM to the arduino pins(check my code)

Here's the full read and write code, but before you use it, download a datasheet and try it out yourself, you'll learn a lot and it'll give you a feeling of accomplishment.

/*
 EEPROM Chip Reader
*/

#define memsize 8192

int STS   = 13;  // Status Indicator

int AP[13] = {24,26,30,32,36,38,42,44,48,50,47,51,53};
int AD[13] = {0,0,0,0,0,0,0,0,0,0,0,0,0};
int DP[8]  = {23,25,29,31,35,37,41,43};
int DD[8]  = {0,0,0,0,0,0,0,0};

int CE  = 6;
int OE  = 4;
int WE  = 2;

int i;
int j;
int D;
int A;

void setup() 
{
  Serial.begin(9600);
  D=0;
  for (i=0;i<8;i++)
  {
   DD[i] = 0;
  }
  // Setup Control Pins
  pinMode(CE, OUTPUT);
  pinMode(WE, OUTPUT);
  pinMode(OE, OUTPUT);
  
  // Disable Chip, and disable read and write.
  digitalWrite(WE, HIGH);
  digitalWrite(CE, LOW);
  digitalWrite(OE, HIGH);

  
  
  Serial.println("Reading EEPROM...");
  
  pinMode(STS,   OUTPUT);
  digitalWrite(STS,HIGH);
  
  // Setup Address Pins 
  for (i=0;i<16;i++)
  {
    pinMode(AP[i],OUTPUT);
  }
  
  // Setup Data Pins
  for (i=0;i<8;i++)
  {
    pinMode(DP[i],INPUT);
  }

  delay(100);
  
  for (A=0;A<memsize;) {
    
    if (A<4096) Serial.print("0");
    if (A<256)  Serial.print("0");
    if (A<16)   Serial.print("0");
    Serial.print(A,HEX);
    Serial.print(" ");

    for (j=0;j<16;j++) {
    
      // Setup Address Pins
      for (i=0;i<16;i++) {
        if((A&bit(i))>0) {
          AD[i]=HIGH;
        } else {
          AD[i]=LOW;
        }      
        digitalWrite(AP[i],AD[i]);
      }
    
      delay(10);
      digitalWrite(OE,LOW);      // Read Enabled
      delay(10);
    
      // Read Data Pins
      D=0;
      for (i=0;i<8;i++) {
        DD[i]=digitalRead(DP[i]);
        D=D+bit(i)*DD[i];
      }
    
      if (D<16) Serial.print("0");
      Serial.print(D,HEX);
      Serial.print(" ");
      
      A++;
    }
    
    Serial.println();
    
  }
  
}

void loop() {
  while (Serial.available()==0) delay(1);
  Serial.print(Serial.read());
  digitalWrite(STS, HIGH);   // set the LED on
  delay(500);              // wait for a second
  digitalWrite(STS, LOW);    // set the LED off
  delay(500);              // wait for a second
}
/*
 EEPROM Programmer
*/

#define memsize 8192

int STS   = 13;  // Status Indicator

int AP[13] = {24,26,30,32,36,38,42,44,48,50,47,51,53};
int AD[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int DP[8]  = {23,25,29,31,35,37,41,43};
int DD[8]  = {0,0,0,0,0,0,0,0};

int CE  = 6;
int OE  = 4;
int WE  = 2;

int i;
int A;
char D;

void setup() {

  Serial.begin(9600);
  Serial.println("Writing EEPROM...");
  
  
  // Led that shows activity
  pinMode(STS,   OUTPUT);
  
  // Setup Address Pins 
  for (i=0;i<16;i++)
  {
    pinMode(AP[i],OUTPUT);
  }
  
  // Setup Data Pins
  for (i=0;i<8;i++)
  {
    pinMode(DP[i],OUTPUT);
  }
  
  // Setup Control Pins
  pinMode(CE, OUTPUT);
  pinMode(WE, OUTPUT);
  pinMode(OE, OUTPUT);
  
  // Setup Chip
  digitalWrite(CE, LOW);
  digitalWrite(WE, LOW);
  digitalWrite(OE, HIGH);


  // Loop that writes Byte per byte
  for (A=0;A<memsize;A++)
  {
    while (Serial.available()==0) delay(1);
    D = Serial.read();
    Serial.print(D,HEX);
    Serial.println("");
    digitalWrite(STS,HIGH);  //Signal that we're writing.

    // Setup Address Pins
    for (i=0;i<13;i++) 
    {
       digitalWrite(AP[i], bitRead(A,i));
    }
    
    // Setup Control bus
    digitalWrite(OE,LOW);   // Reads Disabled
    delay(1);               // Give the EEPROM some time to catch up
    digitalWrite(CE,HIGH);  // Chip Enable
    digitalWrite(WE,HIGH);  // Write Enabled
    
    // Setup Data Pins
    for (i=0;i<8;i++)
    {
      digitalWrite(DP[i], bitRead(D,i));
    }
    
    // Write data (D)
    digitalWrite(WE,LOW);      // Write Disabled
    digitalWrite(CE,LOW);      // Chip Disabled
    digitalWrite(OE,HIGH);     // Reads Enabled
    delay(1);
    
   digitalWrite(STS,LOW);      // Signal that we're waiting
   
  }
  
    // We got through the loop, signal that the write was successful
    Serial.println("Done...");
}

void loop() {
  // Small loop to show that data was written and device can be removed
  digitalWrite(STS, HIGH);   
  delay(1000);              
  digitalWrite(STS, LOW);    
  delay(1000);              
}

I'll probably make a post somewhere on this website explaining exactly what I did, but first I want to solder it and sadly I don't have time for that until Christmas.

Here's the full read and write code, but before you use it, download a datasheet and try it out yourself, you'll learn a lot and it'll give you a feeling of accomplishment.

maybe I will :slight_smile:

Excellent topic! I recommend this brilliant blog posthttp://www.nycresistor.com/2012/07/07/stick-a-straw-in-its-brain-and-suck-how-to-read-a-rom/

I'm planning to use Dave's (Legendmythe) sketch. He used a Linux script to send the hex file over serial. I want to use Max MSP, since it can read hex files and send them over serial very easily. However I'm not sure about the speed. There a module in Max which acts as a metronome (called 'metro'). The bytes are sent every time metro sends a trigger signal. The time is specified in milliseconds. How many bytes can I send per second?

It seems to me that a writing cycle consists of 5 pulses (switching the control pins on and off). Would 5 ms be sufficient between sending each byte?

Answer found: Dave in the blog post clearly explains that he sent 64 bytes at once with 1 second between each 'burst'.