I2C EEPROM dump?

I'm trying to figure out how to write a program that will dump the entire contents of an I2C EEPROM (in this case, a 24LC16B) out to serial. From what I read in the datasheet for the EEPROM, there's an internal pointer or something on the chip, and a read will start wherever it is (random read). If you want to do a sequential read, you have to do a write first to update that pointer, then switch to reading.

Can anyone give me an idea on how to get started? I've looked at the I2E_EEPROM sample on the playground, but there's something I'm missing.

Hi, I have a 24LC256 (which I believe is similar to yours but just with a larger capacity).

To update the pointer you send the address that you want to read from using Wire.send(). There are two Wire.send() calls because the EEPROM address, which ranges from 0x0000 to 0x07FF takes 2 bytes to store. So as an example, if you wanted to start reading from the 1024th byte of the EEPROM you would do:

Wire.beginTransmission(I2C_EEPROM_ADDR);
Wire.send(0x03); // send the high byte of the EEPROM memory address
Wire.send(0xFF); // send the low byte
Wire.endTransmission();

Once the internal address pointer has been set, you need to request however many bytes you want to read. Here is an example for reading 16 bytes:

byte data[16]; // a byte array to store 16 bytes
Wire.requestFrom(I2C_EEPROM_ADDR, 16); // request 16 bytes
for (byte i = 0; i < 16; i++) {
  data[i] = Wire.receive(); // store each byte into the array
}

Do not read more than 30 bytes in one requestFrom() call because the size of the Wire library's receive buffer is 30 bytes.
When dumping your EEPROM, I recommend you use 16 bytes as its evenly divisible into 2048 bytes (the size of your EEPROM). This way you can split your EEPROM into 128 "pages" or blocks (each 16 bytes in size).

So to dump your entire EEPROM, loop through all 128 pages, incrementing the internal pointer by 16 each time. Instead of storing the result from Wire.receive() in an array you can print it directly over the serial connection.

Note: In the above code examples, I2C_EEPROM_ADDR, should be the I2C address of your EEPROM (if you leave the 3 address pins floating or connected to ground, it will be 0x50).

Hope this helps.

That's a great help, thank you! I did have one question about the WP pin though... If I have write protect enabled, is it still possible to update the internal address pointer?

If I have write protect enabled, is it still possible to update the internal address pointer?

I haven't tested it myself, however it should still work.

I tested this only a week ago, not only does it work, but even with WP enabled you can send write commands to the chip....just nothing gets written.

Something's tripping me up... the sample code on the Playground for setting the address pointer looks like this:

  Wire.send((int)(eeaddress >> 8)); // MSB
  Wire.send((int)(eeaddress & 0xFF)); // LSB

If I do some basic math and set "eeaddress" to 1023, the above lines would send "3" and "255" to the I2C bus. Should it be sending "255" for the LSB, or should it be sending "FF"? Something more like this:

  Wire.send(eeaddress >> 8, HEX); //MSB
  Wire.send(eeaddress & 0xFF, HEX); //LSB

Here's an example of what I'm looking at:

#include <Wire.h>
#define EEPROM_ADDR 0x50

void setup(){
  Wire.begin();
  Serial.begin(9600);

  int rdata = 33;
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.send(0x00); // MSB
  Wire.send(0x00); // LSB
  Wire.send(rdata);
  Wire.endTransmission();
  Serial.println(rdata);

  Wire.beginTransmission(EEPROM_ADDR);
  Wire.send(0x00);
  Wire.send(0x00);
  Wire.endTransmission(); 
  Wire.requestFrom(EEPROM_ADDR,1);
  if (Wire.available()) Serial.println(Wire.receive());
}
void loop(){
}

From what I can tell, this should open the I2C bus, move the address pointer to the first memory block, and write either the decimal value "33" or the ASCII equivalent "!" to that space. My understanding from the datasheet for the 24LC16B is that the pointer increments by 1 after every operation, so the next little piece moves back to 0x0000 and does a read. I would expect that the read would come back with either the 33 or the ! as well, but I get nothing. My serial monitor shows the 33 on one line, and that unprintable square character on the second line.

I've been doing some fiddling with my own 24LC16B, and I think I have it working.

One thing to note is the upper 3 bits of the memory location form the lower 3 bits of the device address, so to access memory location 0x12C, you use the device address 0x51, rather than 0x50.

I modified your code, and it now works for me:

#include <Wire.h>
#define EEPROM_ADDR 0x50

void setup(){
  Wire.begin();
  Serial.begin(9600);

  //Write the data
  byte rdata = 33;
  Wire.beginTransmission(EEPROM_ADDR);
  //Wire.send(0x00); // MSB
  Wire.send(0x00); // LSB
  Wire.send(rdata);
  Wire.endTransmission();
  Serial.println(rdata);
  
  delay(15);

  //Set the memory pointer
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.send(0x00);
  //Wire.send(0x00);
  Wire.endTransmission(); 
  
  //Read
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.requestFrom(EEPROM_ADDR,1);
  if (Wire.available()) Serial.println(Wire.receive());
  Wire.endTransmission();
}
void loop(){
}

To write you only pass it two values, one which specifies the lower 8 bits of the address, and one for data. Then, there needs to be a delay to allow the writing to happen, the data sheet says a max of 10ms, so 15ms might be longer than needed, but ensures it is definately written. Also, the requesting needs to go between its own set of begin/end transmission commands.

Here's a simple method I wrote to dump the whole EEPROM for a project of mine:

void dump()
{
  Wire.beginTransmission(ADDRESS);  
  Wire.send(0);
  Wire.endTransmission();
  
  for ( byte upper=0; upper<=8; upper++ )
  {
    for ( int i=0; i<32; i++)
    {
      Wire.beginTransmission(ADDRESS+upper);
      Wire.send(i*8);
      Wire.endTransmission();

      Wire.beginTransmission(ADDRESS+upper);
      
      Wire.requestFrom(ADDRESS+upper, 8);
  
      //Wait till we get all the bytes
      while ( Wire.available()<8 ) {};
      
      printInt(upper); Serial.print("-");
      printInt(i*8); Serial.print(":     ");
  
      for ( int j=0; j<8; j++ )
      {
        printInt(Wire.receive()); Serial.print("     ");
      }
        
      Serial.println();   
      Wire.endTransmission(); 
    }
  }
}
void printInt(int i)
{
  Serial.print("0x");
  
  if ( i<16 )
    Serial.print("0");
    
  Serial.print(i, HEX);
}

HTH

I must still be doing something wrong... when I run the code that agib listed above, I get this:

0x00-0x00: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00-0x08: 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00-0x10: 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00-0x18: 0x18 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00-0x20: 0x20 0x00 0x00 0x00 0x00 0x00 0x00 0x00

and so on, down to 0x08-0xF8. I get the same results with two different chips, which is why I think something isn't right. One of them is a brand new engineering sample, delivered from Taiwan earlier this week. The other was removed from a device (motorcycle dash) that was produced in 2003.

I'm using a Sparkfun Wee, attached to an FTID TTL-232R cable. I've got pins A0, A1, A2, and Vss on the EEPROM wired to GND on the Wee, Vcc wired to 3.3V, WP jumpered over to Vcc (which should enable WP), SCL to pin 5, and SDA to pin 4.

I must still be doing something wrong... when I run the code that agib listed above, I get this:

0x00-0x00: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00-0x08: 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00-0x10: 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00-0x18: 0x18 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00-0x20: 0x20 0x00 0x00 0x00 0x00 0x00 0x00 0x00

and so on, down to 0x08-0xF8. I get the same results with two different chips, which is why I think something isn't right. One of them is a brand new engineering sample, delivered from Taiwan earlier this week. The other was removed from a device (motorcycle dash) that was produced in 2003.

I'm using a Sparkfun Wee, attached to an FTID TTL-232R cable. I've got pins A0, A1, A2, and Vss on the EEPROM wired to GND on the Wee, Vcc wired to 3.3V, WP jumpered over to Vcc (which should enable WP), SCL to pin 5, and SDA to pin 4.

I'd check your power connections, I get exactly that output when I remove the chip from the circuit.

Power looks good (at least according to my Fluke)... 5 Volts at Vcc. With A0-A2 connected to GND and WP connected to Vcc, does the address change? I've tried both 0x50 and 0x51 with the same results.

A0-2 don't matter as they're not used internally, as such assuming you have the 24LC16B the address has to be 0x50 (plus the upper 3 bytes of the memory address)

WP needs to be tied to Vss to be able to write to the eeprom, but you should still be able to read with it tied to Vcc, maybe you could try switching it?

I am a beginner, and probably don't know what I am talking about, but I have been having problems interfacing with I2C and a sparkfun wee. I was wondering if pin 4 is still sda and pin 5 is scl on that board.

I must still be doing something wrong... when I run the code that agib listed above, I get this:

0x00-0x00: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00-0x08: 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00-0x10: 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00-0x18: 0x18 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00-0x20: 0x20 0x00 0x00 0x00 0x00 0x00 0x00 0x00

and so on, down to 0x08-0xF8. I get the same results with two different chips, which is why I think something isn't right. One of them is a brand new engineering sample, delivered from Taiwan earlier this week. The other was removed from a device (motorcycle dash) that was produced in 2003.

I'm using a Sparkfun Wee, attached to an FTID TTL-232R cable. I've got pins A0, A1, A2, and Vss on the EEPROM wired to GND on the Wee, Vcc wired to 3.3V, WP jumpered over to Vcc (which should enable WP), SCL to pin 5, and SDA to pin 4.

Just to clarify....do you have it connecte to pin 4 & 5 digital or analog - I2C bus is pins 4 & 5 of the Analog inputs. I've seen quite a few people get this mixed up.

The sparkfun wee doesn't have analog pins 4 and 5.

Bingo! I was using digital pins 4 and 5. And yes, the Wee does have A4 and A5... but the labels for them are on the bottom. They're the two holes between A1-A2-A3 and the Atmega in the center of the board.

Thank you everyone for your help!

I'm having a bit of a problem with the code examples given above... I'm using

byte rdata = 33;
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.send(0x00); // MSB
  Wire.send(0x00); // LSB
  Wire.send(rdata);
  Wire.endTransmission();
  Serial.println(rdata);
  
  delay(15);

I reinstated the MSB line and it works (it did not work for me when I had the MSB line commented out like the example given. This works when I increment the LSB until 0x08, when it ceases working entirely, and I no longer see my byte 33 written anywhere in my dump. I'm sure there's something in the addressing that I'm not understanding. Any thoughts?