Wire.read & Wire.write don't work if together in same sketch

I am using a CAT24C512 EEPROM wired to my Mega2560 via i2c bus. I can write to or read from the EEPROM using separate sketches, no problem. But when I try to write then immediately read it back, the first read always fails, although subsequent reads are all good. A similar problem happens when I try to read then write in the same sketch: the write does not change any registers in the EEPROM. Note that in all cases Wire.endTransmission() returns “0” error codes showing success.

?? Anyone know why these things happen if read and write are together ??

#include <Wire.h>

const int CAT24 = B1010101;  // CAT24C512 base address is 1010, my device is 101
const unsigned int MEM = 0;  // base memory address for this test
const unsigned int BYTES = 4;  // number of bytes used in this test, starting at "mem"

void setup()  {
    Wire.begin();
    Serial.begin(57600);        
    raw_write(MEM);
    delay(1000); 
} 

void loop()  {  
	raw_read(MEM);
	delay(5000);
}

void raw_write(unsigned int mem_loc)  { 
	byte lsb = byte(lowByte(mem_loc));
	byte msb = byte(highByte(mem_loc));
	Wire.beginTransmission(CAT24);  // send the slave's 7-bit address & a "0" for write
	Wire.write(msb);  // msb  A8 to A15
	Wire.write(lsb);  // lsb  A0 to A7
	for(int i=0; i<BYTES; i++)  {  
		Wire.write(10*i+3);    // queue bytes into write buffer
		Serial.print("  w_mem =");
		Serial.print(i);
		Serial.print("  =  ");
		Serial.println(10*i+3);
	}
	Serial.print("w_endTransmission =  ");
	Serial.println(Wire.endTransmission());  // send all bytes plus a stop bit, return "0" if OK
}

void raw_read(unsigned int mem_loc)  {
	byte lsb = byte(lowByte(mem_loc));
	byte msb = byte(highByte(mem_loc));
	 // dummy write as described in datasheet
	Wire.beginTransmission(CAT24);  // send the 7-bit memory address followed by a 0 for "write"
	Wire.write(msb);  // msb  A8 to A15
	Wire.write(lsb);  // lsb  A0 to A7
	 // end of dummy write
	Wire.requestFrom(CAT24,BYTES);  // sends 7-bit address, a 1 for "read" & sends a stop bit
	for(int i=0; i<BYTES; i++)  {
		Serial.print("  r_mem= ");
		Serial.print(i);
		Serial.print("  =  ");
		Serial.println(Wire.read());  // queue bytes into read buffer
	}
	Serial.print("r_endTransmission =  ");
	Serial.println(Wire.endTransmission());  // send all bytes plus a stop bit
}

Running that code gives this serial output:

w_mem =0 = 3
w_mem =1 = 13 <— bytes written to EEPROM in setup.
w_mem =2 = 23
w_mem =3 = 33
w_endTransmission = 0 <— returned OK
r_mem= 0 = 43
r_mem= 1 = 53
r_mem= 2 = 63 <— the first read gives bad data
r_mem= 3 = 73
r_endTransmission = 0
r_mem= 0 = 3
r_mem= 1 = 13
r_mem= 2 = 23 <— second and subsequent reads all give good data
r_mem= 3 = 33
r_endTransmission = 0
r_mem= 0 = 3
r_mem= 1 = 13
r_mem= 2 = 23
r_mem= 3 = 33
r_endTransmission = 0
.
.
.

Correction.
The statement: “A similar problem happens when I try to read then write in the same sketch: the write does not change any registers in the EEPROM.” is not true.

The basic problem is reading back what was just written.

In the raw_read function, add a Wire.endTransmission() statement to access the correct eeprom memory location before requesting the data. It’s not a “dummy write”, it is setting the the location for the read and needs to be transmitted before the Wire.RequestFrom(). I’m not sure why the subsequent reads wind up in the correct location.

void raw_read(unsigned int mem_loc)  {
	byte lsb = byte(lowByte(mem_loc));
	byte msb = byte(highByte(mem_loc));
	 // dummy write as described in datasheet
	Wire.beginTransmission(CAT24);  // send the 7-bit memory address followed by a 0 for "write"
	Wire.write(msb);  // msb  A8 to A15
	Wire.write(lsb);  // lsb  A0 to A7
        Wire.endTransmission(); //add this here
	 // end of dummy write
	Wire.requestFrom(CAT24,BYTES);  // sends 7-bit address, a 1 for "read" & sends a stop bit
	for(int i=0; i<BYTES; i++)  {
		Serial.print("  r_mem= ");
		Serial.print(i);
		Serial.print("  =  ");
		Serial.println(Wire.read());  // queue bytes into read buffer
	}
	Serial.print("r_endTransmission =  ");
	Serial.println(Wire.endTransmission());  // send all bytes plus a stop bit
}

You should not do a requestFrom between a beginTransmission and endTransmission.

There's your problem.

http://www.gammon.com.au/i2c

Nick--

Do you understand why all reads after the first seemed to be correct?

Generally speaking, I don't try to explain why incorrect code fails in a certain way. :slight_smile:

The I2C library has a number of buffers. Probably doing a beginTransmission before doing a requestFrom caused some sort of buffer confusion.

That was it. Thanks Nick and cattledog for the help - especially for the link to Gammon's forums.