Offline
Newbie
Karma: 1
Posts: 7
|
 |
« on: October 28, 2012, 02:06:35 pm » |
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); }
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 1
Posts: 13
|
 |
« Reply #1 on: October 28, 2012, 03:50:41 pm » |
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
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 1
Posts: 7
|
 |
« Reply #2 on: October 29, 2012, 03:15:27 am » |
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,  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.
|
|
|
|
« Last Edit: October 29, 2012, 03:30:11 am by legendmythe »
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 311
Posts: 35470
Seattle, WA USA
|
 |
« Reply #3 on: October 29, 2012, 08:14:42 am » |
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.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 1
Posts: 7
|
 |
« Reply #4 on: October 29, 2012, 09:07:44 am » |
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
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 311
Posts: 35470
Seattle, WA USA
|
 |
« Reply #5 on: October 29, 2012, 09:09:53 am » |
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 1
Posts: 7
|
 |
« Reply #6 on: October 29, 2012, 10:16:44 am » |
No, I hadn't looked there yet :s Thanks i finally got an EEPROM programmer and I didn't spend hundred dollar  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; }
|
|
|
|
« Last Edit: October 29, 2012, 11:55:11 am by legendmythe »
|
Logged
|
|
|
|
|
Netherlands
Online
Tesla Member
Karma: 87
Posts: 9383
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #7 on: October 29, 2012, 02:01:28 pm » |
Thanks for sharing!
Can you post the final Arduino code too? Can tell what EEPROM's you can write and how you connected them?
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 1
Posts: 13
|
 |
« Reply #8 on: October 29, 2012, 02:41:00 pm » |
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:
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 1
Posts: 7
|
 |
« Reply #9 on: October 29, 2012, 05:02:35 pm » |
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.
|
|
|
|
« Last Edit: October 29, 2012, 05:05:56 pm by legendmythe »
|
Logged
|
|
|
|
|
Netherlands
Online
Tesla Member
Karma: 87
Posts: 9383
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #10 on: October 30, 2012, 03:20:16 pm » |
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 
|
|
|
|
|
Logged
|
|
|
|
|
London
Offline
Full Member
Karma: 0
Posts: 192
Yes, we can (solder)!
|
 |
« Reply #11 on: November 06, 2012, 06:16:05 pm » |
|
|
|
|
|
Logged
|
|
|
|
|
London
Offline
Full Member
Karma: 0
Posts: 192
Yes, we can (solder)!
|
 |
« Reply #12 on: November 23, 2012, 11:15:52 pm » |
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?
|
|
|
|
|
Logged
|
|
|
|
|
London
Offline
Full Member
Karma: 0
Posts: 192
Yes, we can (solder)!
|
 |
« Reply #13 on: November 24, 2012, 06:52:18 am » |
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?
|
|
|
|
|
Logged
|
|
|
|
|
|
|
|