Reading/writing from/to 24c02 eeprom

Dear fellow forum-guests,
I would like to request some hint about the reading from an 24C02EEPROM via I2C (TWI). Yes, I did read the datasheet, but it seems that I do not fully grasp some of the issues… or that my code is completely faulty.
The problem: when I write data to a “wordaddress” (that’s what the datasheet calls the address of the saved data), and I read it back: I find that it has “moved” to wordaddress+1.

My code:

#include <Wire.h>

#define device 0x50  // Address with three address pins grounded. 

void setup() {
  Wire.begin();
  Serial.begin(9600);
  delay(500);
  byte data, wordaddress;
  data = 0x01;
  wordaddress = 0x01;
  byte index;

  //write 5 bytes to the device in nice order
  for(index=0x01;index<=5;index++){
    showWrite(data,wordaddress);
    deviceWrite(data,wordaddress);
    wordaddress++;
    data++;
    delay(1500);
    };

  delay(3000);

  //read them back
  wordaddress = 0x01;
  for(index=0x01;index<=5;index++){
    data  = deviceRead(wordaddress);
    showRead(data,wordaddress);
    delay(1500);
    wordaddress++;
    };
  delay(3000);  
 
 }//end setup

void showRead(byte data, byte wordaddress){
  Serial.print("Read data: ");
  Serial.print(data,HEX);
  Serial.print(" from: ");
  Serial.println(wordaddress,HEX);
}

void showWrite(byte data, byte wordaddress){
  Serial.print("Write data: ");
  Serial.print(data,HEX);
  Serial.print(" to: ");
  Serial.println(wordaddress,HEX);
}

void deviceWrite(byte data, byte wordaddress) {
  Wire.beginTransmission(device);
  Wire.send(wordaddress);
  Wire.send(data);
  Wire.endTransmission(); 
}

byte deviceRead(byte wordaddress) {
  byte result;
  Wire.beginTransmission(device);
  Wire.send(wordaddress);
  Wire.requestFrom(device, 1);
  if(Wire.available()) {
    result = Wire.receive();
  }
  Wire.endTransmission();
  return result;
}

 void loop() {
 }

And this is what I read:

Write data: 1 to: 1
Write data: 2 to: 2
Write data: 3 to: 3
Write data: 4 to: 4
Write data: 5 to: 5

Read data: 36 from: 1 
Read data: 1 from: 2
Read data: 2 from: 3
Read data: 3 from: 4
Read data: 4 from: 5

My apologies for sending the code entirely…

Thank you for considering this issue.

if(Wire.available()) {
    result = Wire.receive();
  }

Try

while(!Wire.available()) 
 {}
result = Wire.receive();

You have to wait for the data to be available - if you miss it with your "if", that's it, you'll fall through, and return whatever happens to be in "result".

Thank you, AWOLL, for the hint. I corrected my code, recompiled, uploaded, tried… (same chip, without writing or altering data)unfortunately, the same result:

Read data: 2 from: 1
Read data: 1 from: 2
Read data: 2 from: 3
Read data: 3 from: 4
Read data: 4 from: 5

Then I did some further testing, and I try this:

  wordaddress = 0x01;
  for(index=0x01;index<=5;index++){
    data  = deviceRead(wordaddress);
    //device has, like my dog, a wooden ear: call him again:
    data  = deviceRead(wordaddress);
    showRead(data,wordaddress);
    delay(1500);
    wordaddress++;
    };

and I got that: (repeatedly)

Read data: 1 from: 1
Read data: 2 from: 2
Read data: 3 from: 3
Read data: 4 from: 4
Read data: 5 from: 5

Problem solved? Apparently, but I don’t like it at all: a bit artificial if I may say so. A better solution would be very wellcome. Thank you.

What's "artificial"?

You give the I2C device an address, and then immediately say "have you got any data"?

It hasn't (yet), so you return your unitialised variable "result", but the library kindly buffers the data from the I2C bus when it does arrive.

Next time you call the I2C read routine, you give it an address, and again immediately say "have you got any data?".

"Yes", says the libary, "I buffered this value for you. You didn't want it last time, but I saved it for you anyway."

This isn't artificial, this is how things work when your processor is clocked at 16Mhz, and the bus it is reading from is only clocked at 100kHz.

I understand perfectly your point, AWOL. And indeed, you are quit right, of course. Reading the datasheet gave me the wrong impression that I could get away with being impatient. And me not initializing the variable "result" is indeed not quite! (but with what value?...) However, I just wanted to give my impression that there seems to be little way to know for sure that the data being read was indeed correct. In the above setup, I knew it of course, as I myself wrote it. But what if the data came from some sensor or so? Wire.available() returns the number of bytes available for retrieval with receive(). But that does not make them available...just yet! Apparently, there should perhaps be some time between available() and receive() ... but how and how much, I could not find. Thus here it is: calling this function deviceRead() twice seems to be a workable tric. In this particular setup, at least. This does not take away the fact that I like my arduinos ,software and the community very much! Nice forum too. Thanks again, AWOL!

Wire.available() returns the number of bytes available for retrieval with receive(). But that does not make them available...just yet!

If that really is the case, then the problem lies with the library, but my sentiment remains - you can't simply say "if (data available) read it, otherwise return some junk that happens to be on the stack". You could try flushing the buffered data before trying a new read. [Scuttles off to find some > 15 year old I2C EEPROM interface software I wrote]

Update: I2C reading from the 24c2 EEPROM.

I just found out why I could not write and then read back from the I2C EEPROM in a consistent manner. I had the impression that "...I had to ask it twice..." This is not so: the correct sequence is:

byte deviceRead(byte wordaddress) {
  byte result;
  int i;
    Wire.beginTransmission(device);
    Wire.send(wordaddress);
    Wire.endTransmission();//RESTART OBLIGATORY
    Wire.requestFrom(device, 1);
    if(Wire.available()) {
      result = Wire.receive();
    }
    Wire.endTransmission();
  return result;
}

After the setting of the wordaddress, the master has to restart the sequence, hence: Wire.endTransmission();//RESTART OBLIGATORY Wire.requestFrom(device, 1);//RESTART And this is indeed in the datasheet.... :-[ and here: http://www.arduino.cc/playground/Code/I2CEEPROM Oh dear... I am ashamed!