Go Down

Topic: Arduino EEPROM Programmer: Burning a ROM image (Read 7237 times) previous topic - next topic

legendmythe

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.

Code: [Select]
/*
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);             
}

gateway

Hi,

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

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

with:
Code: [Select]

      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:
Code: [Select]

    D=0;

with something like:
Code: [Select]

    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

legendmythe

#2
Oct 29, 2012, 09:15 am Last Edit: Oct 29, 2012, 09:30 am by legendmythe Reason: 1
Thanks for the reply!

I did what you told me and I added the following code:
Code: [Select]
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, :) 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.

PaulS

Quote
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.

legendmythe

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


legendmythe

#6
Oct 29, 2012, 04:16 pm Last Edit: Oct 29, 2012, 05:55 pm by legendmythe Reason: 1
No, I hadn't looked there yet :s

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

Here's the code if someone is interested:
Code: [Select]

#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;
}

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?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

gateway

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):
Code: [Select]

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

legendmythe

#9
Oct 29, 2012, 11:02 pm Last Edit: Oct 29, 2012, 11:05 pm by legendmythe Reason: 1

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.
Code: [Select]

/*
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
}

Code: [Select]

/*
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.

robtillaart

Quote
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 :)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)


alkopop79

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?

alkopop79

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?

alkopop79

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

http://z80dave.blogspot.co.uk/2011/09/21-building-eeprom-programmer-part-2.html

Go Up