8
\$\begingroup\$

I am working on a Z80 computer and needed to write data to an EEPROM. I am using the Xicor 28C64AP-25 chip (datasheet). I wrote a program for the Arduino Uno that writes data to the first 4 addresses and then reads the data back. Since I am only using the first three address pins, the rest are tied low. Here is my code, sorry if it seems too cluttered:

#define WE 11
#define OE 12
#define CE 13
#define NUM_ADDR 3
int DP[8] = {A0, A1, A2, A3, A4, A5, 2, 3};
int AP[] = {4, 5, 6};
byte data[] = {0x3E, 0xAA, 0xD3, 0x00, 0xC3, 0x00, 0x00};
void setupDataBus(int mode) {
 for (int i = 0; i < 8; i++) {
 pinMode(DP[i], mode);
 } 
}
void setupControlPins(int mode) {
 pinMode(WE, mode);
 pinMode(OE, mode);
 pinMode(CE, mode);
}
void setupAddressBus(int mode) {
 for (int i = 0; i < NUM_ADDR; i++) {
 pinMode(AP[i], mode);
 } 
}
void writeByte(int address, byte data) {
 setupDataBus(OUTPUT);
 setupAddressBus(OUTPUT);
 setupControlPins(OUTPUT);
 Serial.print("Write Byte: ");
 for (int b = 0; b < 7; b++) {
 digitalWrite(AP[b], bitRead(address, b));
 } 
 Serial.print(address, HEX);
 Serial.print(", ");
 Serial.print(data, HEX);
 Serial.println();
 delay(1);
 // Enable write
 digitalWrite(OE, HIGH);
 delay(1);
 digitalWrite(CE, LOW);
 delay(1);
 delay(10);
 for (int b = 0; b < 8; b++) {
 digitalWrite(DP[b], bitRead(data, b));
 }
 unsigned long time_i, time_f;
 time_i = micros();
 // Start write
 digitalWrite(WE, LOW);
 // End write
 digitalWrite(WE, HIGH);
 time= micros();
 Serial.println(time_f-time_i, DEC);
 delay(1);
 digitalWrite(OE, LOW);
 delay(1);
 digitalWrite(CE, HIGH);
 delay(1);
}
byte readByte(int address) {
 setupDataBus(INPUT);
 setupAddressBus(OUTPUT);
 setupControlPins(OUTPUT);
 byte val;
 digitalWrite(WE, HIGH);
 delay(1);
 digitalWrite(CE, HIGH);
 delay(1);
 digitalWrite(OE, HIGH);
 delay(1);
 Serial.print("Read Byte: ");
 for (int b = 0; b < 7; b++) {
 digitalWrite(AP[b], bitRead(address, b));
 }
 Serial.print(address, HEX); 
 Serial.print(", ");
 delay(1);
 digitalWrite(WE, HIGH);
 delay(1);
 digitalWrite(CE, LOW);
 delay(1);
 digitalWrite(OE, LOW);
 delay(1);
 for (int b = 0; b < 8; b++) {
 bitWrite(val, b, digitalRead(DP[b]));
 } 
 Serial.print(val, HEX);
 delay(1);
 digitalWrite(OE, HIGH);
 delay(1);
 digitalWrite(CE, HIGH);
 delay(1);
 digitalWrite(WE, HIGH);
 Serial.println();
 return val;
}
void setup() {
 setupDataBus(OUTPUT);
 setupAddressBus(OUTPUT);
 pinMode(WE, OUTPUT);
 pinMode(OE, OUTPUT);
 pinMode(CE, OUTPUT);
 Serial.begin(9600);
 }
 void loop() {
 // init
 digitalWrite(OE, HIGH);
 digitalWrite(CE, HIGH);
 digitalWrite(WE, HIGH);
 Serial.println("Initializing pins for write...");
 delay(1000);
 for (int i = 0; i < sizeof(data); i++) {
 writeByte(i, data[i]);
 }
 for (int i = 0; i < sizeof(data); i++) {
 readByte(i);
 }
 while(true);
}

All those delays are just to make sure I'm not going too fast for the EEPROM. I can tell via some LEDs that the Arduino is outputing the right data onto the I/O pins of the EEPROM, but when I read the data back, all I get is 0xFF. Here is the serial output.

Initializing pins for write...
Write Byte: 0, 3E
/WE enable time: 12
Write Byte: 1, AA
/WE enable time: 12
Write Byte: 2, D3
/WE enable time: 12
Write Byte: 3, 0
/WE enable time: 12
Write Byte: 4, C3
/WE enable time: 12
Write Byte: 5, 0
/WE enable time: 12
Write Byte: 6, 0
/WE enable time: 12
Read Byte: 0, FF
Read Byte: 1, FF
Read Byte: 2, FF
Read Byte: 3, FF
Read Byte: 4, FF
Read Byte: 5, FF
Read Byte: 6, FF

I have tested an earlier version of the above program with a static RAM chip and everything works great. It just doesn't work with the EEPROM.

Any help would be much appreciated.

asked Mar 26, 2013 at 21:22
\$\endgroup\$
1
  • \$\begingroup\$ One thing that is missing is on page 7 of the datasheet, it states that you need to write a sequence of codes to disable write-protection. \$\endgroup\$ Commented Aug 21, 2016 at 20:46

4 Answers 4

4
\$\begingroup\$

The device has 13 address pins, which should specify an address in binary from 0x0000 to 0x1FFF. You have not indicated that you are doing anything with them?

Also, I would suggest that you should write a writebyte procedure which sets all address and data wires to output and puts proper values on them, ensures WE and OE are deasserted, asserts CE, asserts and release WE, and releases CE, and a readbyte procedure which sets all address wires to output and puts proper values on them, sets all data wires to input, asserts CE and OE, samples all the data wires, and releases CE and OE. That will make the remainder of your code much more readable.

answered Mar 26, 2013 at 21:34
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the response, @supercat. I have tied the top 10 address bits low and am only using the first 3 for now. I have edited my question. I understand the benefits of separating the code into subroutines and will probably do this, but for now I am just trying to get the byte write working. \$\endgroup\$ Commented Mar 26, 2013 at 22:04
1
\$\begingroup\$

Looking at the datasheet on page 12 it shows a timing diagram and Chip Enable Access Time can be up to 250nS. If using an AVR with a clock>= 4MHz you may be under this time and need a few small delays in your read code, for a start maybe even try long delays like you've done with the write code until you know it's working.

The same diagram shows CE being asserted followed by OE for a read cycle. I'd recommend following that same sequence and also change your write sequence to follow the diagram on the following page.

answered Mar 27, 2013 at 12:12
\$\endgroup\$
11
  • \$\begingroup\$ I added 500ms delays between every control pin change and made sure the order was consistent with the datasheet, but still no luck. Do EEPROMs require precise timing, meaning that I could now be going to slow for the chip? Thanks. \$\endgroup\$ Commented Mar 27, 2013 at 13:18
  • \$\begingroup\$ @MatthewR.: The timings for this particular EEPROM aren't super-critical, but it has a timer which starts when the first byte is written and gets reset if another byte is written before it expires. When the timer expires, an internal write cycle is triggered and additional writes before it completes. It's possible the device gets "unhappy" if /WE goes low and stays low for the entire duration of the timer. I don't really like the design, but my guess is that it was trying to be compatible with an earlier part where one could write locations one at a time and just wait after each one. \$\endgroup\$ Commented Mar 27, 2013 at 16:38
  • \$\begingroup\$ @MatthewR.: BTW, if the chips are equipment pulls as opposed to new parts, it's possible that the "software protection" feature has previously been enabled. If it has, you'll need to wire up all your address wires in order to disable it. \$\endgroup\$ Commented Mar 27, 2013 at 16:41
  • \$\begingroup\$ @supercat: Thanks for the info. The chips are new, and I actually have two from two different manufacturers. All behave the same. \$\endgroup\$ Commented Mar 27, 2013 at 20:46
  • \$\begingroup\$ @MatthewR.: I'd suggest you test what happens if you don't leave the /WE line asserted for more than a couple microseconds or so at a time. That might help things. \$\endgroup\$ Commented Mar 27, 2013 at 21:18
0
\$\begingroup\$

You should check out Ben Eater's Arduino Nano based EEPROM programmer. I have built it twice now for my own use. And I have my own software now which allows me to more easily copy in the code on the virtual terminal (TeraTerm, which is bad, because it cannot handle XON/XOFF flow control, but it's the only choice I have the patience to put up with).

Your Arduino Nano is short on pins, despite having more than Ben Eater realized (19 usable digital pins actually, but still not enough even for a half-kB 11A + 8D + /WE so you need to push the address lines at least out with a pair of serial to parallel shit registers (74HC595).

You don't need to control the /CE with your Arduino. Just tie it low.

You probably need a little delay between /WE low and /WE high to stay in the 100 ns - 1000 ns range (and not less).

answered Aug 20, 2022 at 18:36
\$\endgroup\$
0
\$\begingroup\$

I did the same thing with 28C64 abut write an 8x 64b LUT instead. My code works perfect but you need to tweak it to your needs. Also I use a "shield" board for Arduino Mega which I plugged on top of the board. So you don't need to control the LEDs. The LUTs are read back and plotted with serial plotter to check if everything is fine.

#define WE 27
#define OE 37
#define CE 41
#define NUM_ADDR 9
#define LED_WRITE 22 // Definicja pinu dla diody RED
#define LED_READ 53 // Definicja pinu dla diody GREEN
int DP[8] = { 44, 46, 48, 51, 49, 47, 45, 43 };
int AP[] = {
 42,
 40,
 38,
 36,
 34,
 32,
 30,
 28,
 31,
};
byte saw[] = { 0x00, 0x04, 0x08, 0x0B, //sawtooth_wave
 0x0F, 0x14, 0x16, 0x1C,
 0x1E, 0x23, 0x28, 0x2A,
 0x2F, 0x32, 0x37, 0x3A,
 0x3F, 0x43, 0x46, 0x4B,
 0x4E, 0x53, 0x57, 0x5B,
 0x5F, 0x63, 0x67, 0x6B,
 0x6F, 0x73, 0x77, 0x7B,
 0x7E, 0x83, 0x86, 0x8B,
 0x8E, 0x93, 0x97, 0x9A,
 0x9F, 0xA2, 0xA7, 0xAB,
 0xAE, 0xB3, 0xB6, 0xBB,
 0xBE, 0xC3, 0xC6, 0xCB,
 0xCE, 0xD3, 0xD7, 0xDA,
 0xDF, 0xE2, 0xE7, 0xEA,
 0xEF, 0xF2, 0xF7, 0xFA,
 0x80, 0x8C, 0x99, 0xA5, //sine_wave
 0xB1, 0xBC, 0xC7, 0xD1,
 0xDA, 0xE2, 0xEA, 0xF0,
 0xF5, 0xFA, 0xFD, 0xFE,
 0xFF, 0xFE, 0xFD, 0xFA,
 0xF5, 0xF0, 0xEA, 0xE2,
 0xDA, 0xD1, 0xC7, 0xBC,
 0xB1, 0xA5, 0x99, 0x8C,
 0x80, 0x74, 0x67, 0x5B,
 0x4F, 0x44, 0x39, 0x2F,
 0x26, 0x1E, 0x16, 0x10,
 0x0B, 0x06, 0x03, 0x02,
 0x01, 0x02, 0x03, 0x06,
 0x0B, 0x10, 0x16, 0x1E,
 0x26, 0x2F, 0x39, 0x44,
 0x4F, 0x5B, 0x67, 0x74,
 0x00, 0x08, 0x10, 0x18, //triangle_wave
 0x20, 0x28, 0x30, 0x38,
 0x40, 0x48, 0x50, 0x58,
 0x60, 0x68, 0x70, 0x78,
 0x80, 0x88, 0x90, 0x98,
 0xA0, 0xA8, 0xB0, 0xB8,
 0xC0, 0xC8, 0xD0, 0xD8,
 0xE0, 0xE8, 0xF0, 0xF8,
 0xFF, 0xF8, 0xF0, 0xE8,
 0xE0, 0xD8, 0xD0, 0xC8,
 0xC0, 0xB8, 0xB0, 0xA8,
 0xA0, 0x98, 0x90, 0x88,
 0x80, 0x78, 0x70, 0x68,
 0x60, 0x58, 0x50, 0x48,
 0x40, 0x38, 0x30, 0x28,
 0x20, 0x18, 0x10, 0x08,
 0x00, 0x0B, 0x18, 0x24, //sineflip_wave
 0x30, 0x3C, 0x46, 0x51,
 0x59, 0x62, 0x69, 0x70,
 0x75, 0x7A, 0x7C, 0x7F,
 0x7E, 0x7F, 0x7C, 0x7A,
 0x75, 0x70, 0x6A, 0x61,
 0x5A, 0x50, 0x47, 0x3B,
 0x31, 0x25, 0x18, 0x0C,
 0xFF, 0xF3, 0xE6, 0xDA,
 0xCE, 0xC3, 0xB8, 0xAD,
 0xA5, 0x9C, 0x95, 0x8E,
 0x88, 0x85, 0x81, 0x80,
 0x80, 0x80, 0x81, 0x85,
 0x89, 0x8E, 0x95, 0x9C,
 0xA5, 0xAD, 0xB8, 0xC2,
 0xCE, 0xD9, 0xE6, 0xF3,
 0x3E, 0x58, 0x6E, 0x7F, //swirl_wave
 0x8E, 0x99, 0xA5, 0xAD,
 0xB7, 0xBF, 0xC5, 0xCF,
 0xD6, 0xE0, 0xE9, 0xF2,
 0xFF, 0xD2, 0xB6, 0x9F,
 0x90, 0x88, 0x82, 0x82,
 0x82, 0x87, 0x88, 0x8E,
 0x91, 0x94, 0x99, 0x99,
 0x9C, 0x9A, 0x9A, 0x97,
 0x93, 0x8E, 0x87, 0x7F,
 0x76, 0x6A, 0x5F, 0x51,
 0x44, 0x33, 0x25, 0x13,
 0x00, 0x24, 0x3C, 0x4A,
 0x55, 0x55, 0x55, 0x50,
 0x48, 0x3F, 0x38, 0x2D,
 0x25, 0x1C, 0x16, 0x0F,
 0x80, 0x80, 0x80, 0x86, //wahwah_wave
 0x90, 0x9D, 0xAD, 0xB7,
 0xBD, 0xBE, 0xBF, 0xC7,
 0xD0, 0xDE, 0xE8, 0xF1,
 0xF5, 0xF9, 0xFC, 0xFB,
 0xF2, 0xDF, 0xCA, 0xBA,
 0xB5, 0xBA, 0xBE, 0xBA,
 0xAD, 0x9B, 0x8C, 0x83,
 0x83, 0x81, 0x7E, 0x74,
 0x66, 0x5C, 0x53, 0x4D,
 0x4A, 0x43, 0x3C, 0x31,
 0x28, 0x20, 0x18, 0x13,
 0x0C, 0x05, 0x00, 0x00,
 0x0C, 0x21, 0x37, 0x46,
 0x49, 0x43, 0x40, 0x44,
 0x53, 0x64, 0x74, 0x7A,
 0x80, 0x99, 0xB5, 0xCF, //trapezoid_wave
 0xEB, 0xFF, 0xFF, 0xFF,
 0xFF, 0xFF, 0xFF, 0xFF,
 0xFF, 0xFF, 0xFF, 0xFF,
 0xFF, 0xFF, 0xFF, 0xFF,
 0xFF, 0xFF, 0xFF, 0xFF,
 0xFF, 0xFF, 0xFF, 0xFF,
 0xEA, 0xD0, 0xB5, 0x9B,
 0x80, 0x64, 0x4A, 0x2E,
 0x14, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00,
 0x13, 0x2E, 0x49, 0x63,
 0x80, 0x87, 0x90, 0x97, //triblade_wave
 0x9F, 0xA7, 0xAE, 0xB8,
 0xBE, 0xC8, 0xCE, 0xD7,
 0x20, 0x18, 0x10, 0x08,
 0x00, 0x07, 0x0F, 0x16,
 0xE0, 0xD7, 0xD0, 0xC7,
 0xC0, 0xB7, 0xB0, 0xA8,
 0x9F, 0x98, 0x8F, 0x88,
 0x7F, 0x78, 0x6F, 0x68,
 0x5F, 0x58, 0x50, 0x47,
 0x40, 0x38, 0x2F, 0x28,
 0xDE, 0xE7, 0xEF, 0xF6,
 0xFF, 0xF7, 0xF0, 0xE8,
 0x1E, 0x27, 0x2E, 0x37,
 0x3E, 0x47, 0x4F, 0x56,
 0x5F, 0x66, 0x6F, 0x76,
 }; /// 8 tablic 64x 8-bit
//------------------------ Init ----------------------------
void setupDataBus(int mode) {
 for (int i = 0; i < 8; i++) {
 pinMode(DP[i], mode);
 }
}
void setupControlPins(int mode) {
 pinMode(WE, mode);
 pinMode(OE, mode);
 pinMode(CE, mode);
 pinMode(LED_WRITE, OUTPUT); // Konfiguracja pinu diody jako wyjście
}
void setupAddressBus(int mode) {
 for (int i = 0; i < NUM_ADDR; i++) {
 pinMode(AP[i], mode);
 }
// Wyłączenie nieaktywnych pinów adresowych
pinMode(33, OUTPUT);
digitalWrite(33, LOW); // A9
pinMode(39, OUTPUT);
digitalWrite(39, LOW); // A10
pinMode(35, OUTPUT);
digitalWrite(35, LOW); // A11
pinMode(26, OUTPUT);
digitalWrite(26, LOW); // A12
}
//------------------------ Write Byte ----------------------
void writeByte(int address, byte data) {
 digitalWrite(LED_WRITE, HIGH); // Zapalenie diody na początku zapisu danych
 setupDataBus(OUTPUT);
 setupAddressBus(OUTPUT);
 setupControlPins(OUTPUT);
 Serial.print("Write Byte: ");
 for (int b = 0; b < NUM_ADDR; b++) {
 digitalWrite(AP[b], bitRead(address, b));
 }
 delay(1);
 // Enable write
 digitalWrite(OE, HIGH);
 delay(1);
 digitalWrite(CE, LOW);
 delay(1);
 delay(10);
 for (int b = 0; b < 8; b++) {
 digitalWrite(DP[b], bitRead(data, b));
 }
 unsigned long time_i, time_f, time;
 time_i = micros();
 // Start write
 digitalWrite(WE, LOW);
 // End write
 digitalWrite(WE, HIGH);
 digitalWrite(LED_WRITE, LOW); // Wyłączenie diody po zakończeniu zapisu
 time = micros();
 //Serial.println(time_f - time_i, DEC);
 delay(1);
 digitalWrite(OE, LOW);
 delay(1);
 digitalWrite(CE, HIGH);
 delay(1);
}
//------------------------ Read Byte ----------------------
byte readByte(int address) {
 digitalWrite(LED_READ, HIGH); // Zapalenie diody odczytu
 setupDataBus(INPUT);
 setupAddressBus(OUTPUT);
 setupControlPins(OUTPUT);
 byte val;
 digitalWrite(WE, HIGH);
 delay(1);
 digitalWrite(CE, HIGH);
 delay(1);
 digitalWrite(OE, HIGH);
 delay(1);
 //Serial.print("Read Byte: ");
 for (int b = 0; b < NUM_ADDR; b++) {
 digitalWrite(AP[b], bitRead(address, b));
 }
 // Serial.print(address, HEX); /// print Address
 //Serial.print(", ");
 delay(1);
 digitalWrite(WE, HIGH);
 delay(1);
 digitalWrite(CE, LOW);
 delay(1);
 digitalWrite(OE, LOW);
 delay(1);
 for (int b = 0; b < 8; b++) {
 bitWrite(val, b, digitalRead(DP[b]));
 }
 // Serial.print(val, HEX); /// print Bit
 delay(1);
 digitalWrite(OE, HIGH);
 delay(1);
 digitalWrite(CE, HIGH);
 digitalWrite(LED_READ, LOW); // Zgaszenie diody odczytu
 delay(1);
 digitalWrite(WE, HIGH);
 Serial.println();
 return val;
}
//------------------------ SETUP ----------------------
void setup() {
 setupDataBus(OUTPUT);
 setupAddressBus(OUTPUT);
 pinMode(WE, OUTPUT);
 pinMode(OE, OUTPUT);
 pinMode(CE, OUTPUT);
 pinMode(LED_READ, OUTPUT); // Ustawienie pinu diody odczytu jako wyjście
 pinMode(LED_WRITE, OUTPUT); // Ustawienie pinu diody zapisu jako wyjście
 Serial.begin(9600);
}
//------------------------ LOOP -----------------------
void loop() {
 // init
 digitalWrite(OE, HIGH);
 digitalWrite(CE, HIGH);
 digitalWrite(WE, HIGH);
 Serial.println("Initializing pins for write...");
 delay(1000);
 for (int i = 0; i < sizeof(saw); i++) {
 writeByte(i, saw[i]);
 }
 for (int i = 0; i < 5; i++) {
 for (int i = 0; i < 65; i++) {
 // readByte(i);
 Serial.println(readByte(i));
 }
 }
 for (int i = 0; i < 5; i++) {
 for (int i = 65; i < 128; i++) {
 // readByte(i);
 Serial.println(readByte(i));
 }
 }
 for (int i = 0; i < 5; i++) {
 for (int i = 128; i < 192; i++) {
 // readByte(i);
 Serial.println(readByte(i));
 }
 }
 for (int i = 0; i < 5; i++) {
 for (int i = 192; i < 256; i++) {
 // readByte(i);
 Serial.println(readByte(i));
 }
 }
 for (int i = 0; i < 5; i++) {
 for (int i = 256; i < 320; i++) {
 // readByte(i);
 Serial.println(readByte(i));
 }
 }
 for (int i = 0; i < 5; i++) {
 for (int i = 320; i < 384; i++) {
 // readByte(i);
 Serial.println(readByte(i));
 }
 }
 for (int i = 0; i < 5; i++) {
 for (int i = 384; i < 448; i++) {
 // readByte(i);
 Serial.println(readByte(i));
 }
 }
 for (int i = 0; i < 5; i++) {
 for (int i = 448; i < 512; i++) {
 // readByte(i);
 Serial.println(readByte(i));
 }
 }
 while (true);
}
answered Aug 19, 2024 at 7:59
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.