Unable to work with 1Mbit EEPROM

Hello all. I'm asking help for a problem that's driving me crazy. I'd like to use a 1Mbit EEPROM in a project. I'm using Microchip's 24FC1026, which contains 2 blocks of 64Kbytes of EEPROM memory. According to the datasheet, it's possible to address the lower or the upper block by setting B0 bit on the first byte of I2C communication. It should be a trivial task, but I can't address the upper 64K bytes of the memory. What I do is simply writing a byte at address bigger than 65536 and read it after. But I always read the value in the lower bank. It seems the memory ignores the B0 value, not allowing to write (or read? I can't see if the problem resides on writing or reading from the location) on the upper 64Kbytes block. I tried to replace the memory: same behavior over 3 changed. I also tried to use all the available Arduino libraries onthe net... nothing. All libraries and all sketches failed in write/verify each memory location between 65536 and 131072 addresses... I know it should be a very simple task to accomplish, but I can't figure out where the problem could be... Any suggestions? Lot ot thanks for your help. Gabriele

I can't address the upper 64K bytes of the memory

You can't be setting the B0 bit correctly so post an example of your code which tries to address the upper 64k - in [code] [/code] tags please.

Pete

I've just updated an EEPROM library that I wrote a while back, now it should work with EEPROMs from 2k bits to 2048k bits. I'm still testing it but all seems well so far. If you'd like to give it a try, I'd appreciate the additional testing. Be sure to get the dev branch.

Haven't written the documentation yet :blush: but there's just a constructor, begin(), read() and write() functions. Should be pretty obvious from the .h file, but if you have questions let me know.

Thanks el_supremo and Jack for your prompt reply. One of the libraries I used is E24C1024: http://playground.arduino.cc/Code/I2CEEPROM24C1024 And running the example application will give errors from location 65536 to 131072 (upper bank). Going more in deep in the code, I see that, on E24C1024.cpp:

void E24C1024::write(unsigned long dataAddress, uint8_t data)
{
   Wire.beginTransmission((uint8_t)((0x500000 | dataAddress) >> 16)); // B1010xxx
   Wire.write((uint8_t)((dataAddress & WORD_MASK) >> 8)); // MSB
   Wire.write((uint8_t)(dataAddress & 0xFF)); // LSB
   Wire.write(data);
   Wire.endTransmission();
   delay(5);
}

So, shifting left the address of 16 bits should result in an address command: 1010 A2 A1 B0, where the B0 is the bank bit that should select the upper bank in address > 65535... So, looking at the code, nothing seems wrong (it's a public domain library), but I still have the problem... Any hints? Thanks again for your support.

@Jack: I'll try your library asap and I'll let you know! Thanks again.

@Gabriele,

I’ve just wrapped up testing my library with the EEPROMs I have on hand, 2kbits, 256kbits and 2Mbits.

For what it’s worth, below is a sketch I used for testing, although I’d still be interested in hearing results from whatever method you are using as well.

Thanks!

//test updated extEEPROM library
//writes the EEPROM full of 32-bit integers and reads them back to verify
//09Jul2014

#include <Streaming.h>    //http://arduiniana.org/libraries/streaming/
#include <Wire.h>
#include <extEEPROM.h>    //http://github.com/JChristensen/extEEPROM/tree/dev

//24FC1026
const uint32_t totalKBytes = 128;          //for read and write test functions
extEEPROM eep(kbits_1024, 1, 128);         //device size, number of devices, page size

const uint8_t btnStart = 6;                //start button

void setup(void)
{
    pinMode(btnStart, INPUT_PULLUP);
    Serial.begin(57600);
    uint8_t eepStatus = eep.begin(twiClock400kHz);
    Serial << endl << F("EEPROM begin status=") << eepStatus << endl << "TWBR=" << TWBR << endl << F("Press button to start...") << endl;
    while (digitalRead(btnStart) == HIGH) delay(25);    //wait for button push

    uint8_t chunk = 64;
//    eeErase(chunk, 0, totalKBytes * 1024 - 1);
    eeWrite(chunk);
    eeRead(chunk);

    dump(0, 1);
    dump(65520, 1);
    dump(65536, 1);
    dump(131056, 1);
}

void loop(void)
{
}

//write test data (32-bit integers) to eeprom, "chunk" bytes at a time
void eeWrite(uint8_t chunk)
{
    chunk &= 0xFC;                //force chunk to be a multiple of 4
    uint8_t data[chunk];
    uint32_t val = 0;
    Serial << F("Writing...") << endl;
    uint32_t msStart = millis();
    
    for (uint32_t addr = 0; addr < totalKBytes * 1024; addr += chunk) {
        if ( (addr &0xFFF) == 0 ) Serial << addr << endl;
        for (uint8_t c = 0; c < chunk; c += 4) {
            data[c+0] = val >> 24;
            data[c+1] = val >> 16;
            data[c+2] = val >> 8;
            data[c+3] = val;
            ++val;
        }
        eep.write(addr, data, chunk);
    }
    uint32_t msLapse = millis() - msStart;
    Serial << "Write lapse: " << msLapse << " ms" << endl;
}

//read test data (32-bit integers) from eeprom, "chunk" bytes at a time
void eeRead(uint8_t chunk)
{
    chunk &= 0xFC;                //force chunk to be a multiple of 4
    uint8_t data[chunk];
    uint32_t val = 0, testVal;
    Serial << F("Reading...") << endl;
    uint32_t msStart = millis();
    
    for (uint32_t addr = 0; addr < totalKBytes * 1024; addr += chunk) {
        eep.read(addr, data, chunk);
        for (uint8_t c = 0; c < chunk; c += 4) {
            testVal =  ((uint32_t)data[c+0] << 24) + ((uint32_t)data[c+1] << 16) + ((uint32_t)data[c+2] << 8) + (uint32_t)data[c+3];
            if (testVal != val) Serial << F("Error @ addr ") << addr+c << F(" Expected ") << val << F(" Read ") << testVal << F(" 0x") << _HEX(testVal) << endl;
            ++val;
        }
    }
    uint32_t msLapse = millis() - msStart;
    Serial << "Last value: " << --val << " Read lapse: " << msLapse << " ms" << endl;
}

//write 0xFF to eeprom, "chunk" bytes at a time
void eeErase(uint8_t chunk, uint32_t startAddr, uint32_t endAddr)
{
    chunk &= 0xFC;                //force chunk to be a multiple of 4
    uint8_t data[chunk];
    Serial << F("Erasing...") << endl;
    for (int i = 0; i < chunk; i++) data[i] = 0xFF;
    uint32_t msStart = millis();
    
    for (uint32_t a = startAddr; a <= endAddr; a += chunk) {
        eep.write(a, data, chunk);
    }
    uint32_t msLapse = millis() - msStart;
    Serial << "Erase lapse: " << msLapse << " ms" << endl;
}

//dump eeprom contents, 16 bytes at a time.
//always dumps a multiple of 16 bytes.
void dump(uint32_t startAddr, uint32_t nBytes)
{
    Serial << endl << F("EEPROM DUMP 0x") << _HEX(startAddr) << F(" 0x") << _HEX(nBytes) << ' ' << startAddr << ' ' << nBytes << endl << endl;
    uint32_t nRows = (nBytes + 15) >> 4;

    uint8_t d[16];
    for (uint32_t r = 0; r < nRows; r++) {
        uint32_t a = startAddr + 16 * r;
        eep.read(a, d, 16);
        Serial << "0x";
        if ( a < 16 * 16 * 16 ) Serial << '0';
        if ( a < 16 * 16 ) Serial << '0';
        if ( a < 16 ) Serial << '0';
        Serial << _HEX(a) << ' ';
        for ( int c = 0; c < 16; c++ ) {
            if ( d[c] < 16 ) Serial << '0';
            Serial << _HEX( d[c] ) << ( c == 7 ? "  " : " " );
        }
        Serial << endl;
    }
}

Many thanks Jack for your work. Your code is very well written and works like a charm! Here's the output proving that it's working like it should: [cut] 126976 Write lapse: 31442 ms Reading... Last value: 32767 Read lapse: 5093 ms EEPROM DUMP 0x0 0x1 0 1 0x0000 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00 03 EEPROM DUMP 0xFFF0 0x1 65520 1 0xFFF0 00 00 3F FC 00 00 3F FD 00 00 3F FE 00 00 3F FF EEPROM DUMP 0x10000 0x1 65536 1 0x10000 00 00 40 00 00 00 40 01 00 00 40 02 00 00 40 03 EEPROM DUMP 0x1FFF0 0x1 131056 1 0x1FFF0 00 00 7F FC 00 00 7F FD 00 00 7F FE 00 00 7F FF

I'll probably use your code on my sketch, but I still can't figure out why all the other code is simply failing on this. I noticed the difference between 24XX1026 (where the control byte format is 1 0 1 0 A2 A1 B0) and 24XX1025 (where the control byte format is instead 1 0 1 0 B0 A2 A1). Anyway, I tried all the combination of the 3 bits following the 1 0 1 0 sequence, hoping to find 2 banks out of 8 available to write into/read from, but without any luck.

@Gabriele, excellent! Glad it works for you and I very much appreciate the testing. I'll add 24FC1026 to the list of devices tested.

I had a look at the E24C1024 library, and the write code looks OK to me (without doing any testing) but I think the problem is in the read code:

uint8_t E24C1024::read(unsigned long dataAddress)
{
   uint8_t data = 0x00;
   Wire.beginTransmission((uint8_t)((0x500000 | dataAddress) >> 16)); // B1010xxx
   Wire.send((uint8_t)((dataAddress & WORD_MASK) >> 8)); // MSB
   Wire.send((uint8_t)(dataAddress & 0xFF)); // LSB
   Wire.endTransmission();
   Wire.requestFrom(0x50,1);
   if (Wire.available()) data = Wire.receive();
   return data;
}

Note the statement Wire.requestFrom(0x50,1); will always have the bits A2 = A1 = B0 = 0. Changing it to the same expression as used in Wire.beginTransmission() should fix it.

I did notice the funny addressing for the 24xx1025 when doing research for the library. Not sure why they'd do that, but I decided not to worry about it; my library will not work with that chip.

Thanks again!

PS: I raised an issue with the arduino-at24c1024 library.

I made final changes to my library and pushed it to GitHub (master branch now), http://github.com/JChristensen/extEEPROM

Added single-byte write and read functions and even added documentation :open_mouth:

Gave you creds for testing 24FC1026, if you're uncomfortable with that just say the word.