I2C_eeprom and saving struct

Hi I’m a total newbie into into the arduino world. Trying to make a simple sketch saving/reading data structure on a 24Lc256 using the I2C_eeprom library, but it is a bit hard.
I’ve found the code writing in the internal eeprom, and tried to change it to using the external mounted on the I2C.

My code looks like:

float f = 0.00f; //Variable to store data read from EEPROM.
int eeAddress = 0; //EEPROM address to start reading from

Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

Serial.print(“Demo I2C eeprom library “);
Serial.print(I2C_EEPROM_VERSION);
Serial.println(”\n”);

Serial.println("\nTEST: 64 byte page boundary writeBlock");
/** Put is designed for use with custom structures also. **/
ee.setBlock(0,0,128);
dumpEEPROM(0, 128);

for (int t = 0; t <= maxread; t++) {
//Data to store.
MyObject customVar = {
t * 3.14f,
t,
“Working!”
};

eeAddress += 15; //Move address to the next byte after float ‘f’.

ee.writeBlock(t,customVar, 15);
dumpEEPROM(0, 128);

}

}

I’ll aprreciate som help :wink:

(deleted)

I’d appreciate if you told us what the problem is.

It would also help to use code tags, not quote tags for source code listings.

Sorry … many new things to learn…

My problem is how to save a structure on a 24lc256 ext. eeprom connected via I2C. Haven’t found any sample-code to learn from. Just found this code saving a struct in the internal eeprom:

/***
    eeprom_put example.

    This shows how to use the EEPROM.put() method.
    Also, this sketch will pre-set the EEPROM data for the
    example sketch eeprom_get.

    Note, unlike the single byte version EEPROM.write(),
    the put method will use update semantics. As in a byte
    will only be written to the EEPROM if the data is actually
    different.

    Written by Christopher Andrews 2015
    Released under MIT licence.
***/

#include <EEPROM.h>

int maxread=400;
struct MyObject {
  float field1;
  byte field2;
  char name[10];
};

void setup() {

float f = 0.00f;   //Variable to store data read from EEPROM.
int eeAddress = 0; //EEPROM address to start reading from


  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  /** Put is designed for use with custom structures also. **/
  for (int t = 0; t <= maxread; t++) {
    //Data to store.
    MyObject customVar = {
      t * 3.14f,
      t,
      "Working!"
    };

    eeAddress += 15; //Move address to the next byte after float 'f'.

    EEPROM.put(eeAddress, customVar);
  }
  Serial.print("Written custom data type! \n\nView the example sketch eeprom_get to see how you can retrieve the values!");
  secondTest();
}
void secondTest() {
//  int eeAddress = sizeof(float); //Move address to the next byte after float 'f'.
float f = 0.00f;   //Variable to store data read from EEPROM.
int eeAddress = 0; //EEPROM address to start reading from
  MyObject customVar; //Variable to store custom object read from EEPROM.
  for (int t = 0; t <= maxread; t++) {
    eeAddress +=15;

    EEPROM.get(eeAddress, customVar);

    Serial.println("Read custom object from EEPROM: ");
    Serial.println(t);
    Serial.println(customVar.field1);
    Serial.println(customVar.field2);
    Serial.println(customVar.name);
  }
}
void loop() {
  /* Empty loop */
}

There is something I’ve missed in converting the code…
error: eeprom_get-put-ext:61: error: no matching function for call to ‘I2C_eeprom::writeBlock(int&, MyObject&, int)’

#include <I2C_eeprom.h>

/***
    eeprom_put example.

    This shows how to use the EEPROM.put() method.
    Also, this sketch will pre-set the EEPROM data for the
    example sketch eeprom_get.

    Note, unlike the single byte version EEPROM.write(),
    the put method will use update semantics. As in a byte
    will only be written to the EEPROM if the data is actually
    different.

    Written by Christopher Andrews 2015
    Released under MIT licence.
***/
#include <Wire.h> //I2C library
#include <I2C_eeprom.h>

I2C_eeprom ee(0x50);

int maxread=400;
struct MyObject {
  float field1;
  byte field2;
  char name[10];
};

void setup() {

float f = 0.00f;   //Variable to store data read from EEPROM.
int eeAddress = 0; //EEPROM address to start reading from


  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
Serial.begin(115200);
Serial.print("Demo I2C eeprom library ");
Serial.print(I2C_EEPROM_VERSION);
Serial.println("\n");
Serial.println("\nTEST: 64 byte page boundary writeBlock");
  /** Put is designed for use with custom structures also. **/
 
  ee.setBlock(0,0,128);
 // dumpEEPROM(0, 128);
  
  for (int t = 0; t <= maxread; t++) {
    //Data to store.
    MyObject customVar = {
      t * 3.14f,
      t,
      "Working!"
    };

    eeAddress += 15; //Move address to the next byte after float 'f'.


  ee.writeBlock(t,customVar, 15);

  }
  Serial.print("Written custom data type! \n\nView the example sketch eeprom_get to see how you can retrieve the values!");
  secondTest();
}
void secondTest() {

float f = 0.00f;   //Variable to store data read from EEPROM.
int eeAddress = 0; //EEPROM address to start reading from
  MyObject customVar; //Variable to store custom object read from EEPROM.
  for (int t = 0; t <= maxread; t++) {
    eeAddress +=15;

    EEPROM.get(eeAddress, customVar);

    Serial.println("Read custom object from EEPROM: ");
    Serial.println(t);
    Serial.println(customVar.field1);
    Serial.println(customVar.field2);
    Serial.println(customVar.name);
  }
}
void loop() {
  /* Empty loop */
}

Hopefull this will uncover my problems…

Sincerly

Steen

Have a look how to write I2C; the internal eeprom code is not applicable, forget about it.

You can cast a struct to an array of byytes and write those bytes.

struct MYDATA
{
  ...
  ...
};

MYDATA data;


// setup used to show example of cast
void setup()
{
  Serial.begin(9600);

  // a pointer to the struct
  byte *pdata = (byte*) data.
  // size of the MYDATA struct
  int size = sizeof(MYDATA);
}

If MYDATA does not contain pointers or variable length variables, you can use it to determine how many bytes you need to write.

Hi

Ok- thanks ! I'll look into it...

Sincerly Steen

Hi sterretje

Have trying to make at sketch with your surgstions, combined with som read/write procedures found on the net.
I haven’t fully understood the programming language - getting an compliation-error:

Arduino: 1.6.8 (Windows 10), Board: “Arduino Nano, ATmega328”
F:\Steen\Dokumenter\Arduino\sketch_jun12a\sketch_jun12a.ino: In function ‘void setup()’:
sketch_jun12a:26: error: expected unqualified-id before ‘int’

  • int size = sizeof(MYDATA);*
  • ^*
    sketch_jun12a:30: error: invalid cast from type ‘MYDATA’ to type ‘byte* {aka unsigned char*}’
    i2c_eeprom_write_page(0x50, 0, (byte *)data, sizeof(MYDATA)); // write to EEPROM

The code looks like:

/*
    Use the I2C bus with EEPROM 24LC64
    Sketch:    eeprom.pde

    Author: hkhijhe
    Date: 01/10/2010


*/
#include <Wire.h> //I2C library

typedef struct { // tranmission data (6 bytes)
  uint16_t ms;
  int16_t accel;
  int16_t pres;
} MYDATA;
MYDATA data;

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

  // a pointer to the struct
  byte *pdata = (byte*) data.
 // size of the MYDATA struct
 int size = sizeof(MYDATA);


  Wire.begin(); // initialise the connection
  i2c_eeprom_write_page(0x50, 0, (byte *)data, sizeof(MYDATA)); // write to EEPROM

  delay(10); //add a small delay

  Serial.println("Memory written");
}

void loop(){}

void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
  int rdata = data;
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8)); // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(rdata);
  Wire.endTransmission();
}

// WARNING: address is a page address, 6-bit end will wrap around
// also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddresspage >> 8)); // MSB
  Wire.write((int)(eeaddresspage & 0xFF)); // LSB
  byte c;
  for ( c = 0; c < length; c++)
    Wire.write(data[c]);
  Wire.endTransmission();
}

byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
  byte rdata = 0xFF;
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8)); // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress, 1);
  if (Wire.available()) rdata = Wire.read();
  return rdata;
}

// maybe let's not read more than 30 or 32 bytes at a time!
void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8)); // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress, length);
  int c = 0;
  for ( c = 0; c < length; c++ )
    if (Wire.available()) buffer[c] = Wire.read();
}

Maybe you can help me ?

Sincerly

Steen

Semicolon?

  byte *pdata = (byte*) data.

dosen't change anyhing...

nether:

byte pdata = (byte) data.;

or:

byte pdata = (byte) data;

It sure won’t hurt anything…

If data is a MYDATA object, why are you using a byte pointer? What happens if you take:

  // a pointer to the struct
  byte *pdata = (byte*) data.
 // size of the MYDATA struct
 int size = sizeof(MYDATA);


  Wire.begin(); // initialise the connection
  i2c_eeprom_write_page(0x50, 0, (byte *)data, sizeof(MYDATA)); // write to EEPROM

and replace it with:

//  byte *pdata = (byte*) data;
  MYDATA *pdata = &data;
  
 // size of the MYDATA struct
 int size = sizeof(MYDATA);


  Wire.begin(); // initialise the connection
  i2c_eeprom_write_page(0x50, 0, (byte *)pdata, size);    // write to EEPROM

Hi

Thanks a lot !

That gave me a step in the rigth direction…

Sincerly
Steen

Sorry, mistake from my side.

The intention is to get a pointer to a byte array that you can pass to a generic write or read function for the eeprom.

This is what it should have been :frowning:

struct MYDATA
{
  ...
  ...
};

MYDATA data;

void setup() {

  byte *pdata = (byte*) &data;    // <----
  int size = sizeof(MYDATA);

}

void loop() {
  // put your main code here, to run repeatedly:

}

Note the ampersand in front of data.

Hi sterretje

Thanks for your help. I've got the writing running (I'll hope) - Now struckling to read the contense that I'd wrote. :confused:

Sincerly Steen

I don't know if your above code is still up-to-date. But the below should take the address of data and not data itself.

  i2c_eeprom_write_page(0x50, 0, (byte *)data, sizeof(MYDATA)); // write to EEPROM

Change it to

  i2c_eeprom_write_page(0x50, 0, (byte *)&data, sizeof(MYDATA)); // write to EEPROM
                                         ^
                                         |

The reading should be straight forward; use i2c_eeprom_read_buffer. The buffer will be a pointer as above

// variable to store data retrieved from eeprom
MYDATA retrievedData;
// byte pointer
byte *pData = (byte*)&retrievedData;

i2c_eeprom_read_buffer(0x50, 0, pData, sizeof(MYDATA));

No option to test this.

Hi sterretje

Thanks for your help.

My code is now like this:

/*
    Use the I2C bus with EEPROM 24LC64
    Sketch:    eeprom.pde

    Author: hkhijhe
    Date: 01/10/2010


*/
#include <Wire.h> //I2C library

typedef struct { // tranmission data (6 bytes)
  uint16_t ms;
  int16_t accel;
  int16_t pres;
} MYDATA;
MYDATA data;

int maxread = 15;

void setup()
{

  int eeAddress = 0;
  Serial.begin(9600);
  Wire.begin(); // initialise the connection

  //  byte *pdata = (byte*) data;
  MYDATA *pdata = &data;
  // size of the MYDATA struct
  int size = sizeof(MYDATA);
  /** Put is designed for use with custom structures also. **/
  for (int t = 0; t <= maxread; t++) {

    // Some Data to store.
    MYDATA data = {
      t * 3,
      t - 2,
      t  + 10
    };
  //  Serial.println("Rsead custom object from EEPROM: ");
  //  Serial.println(t);
  //  Serial.println(data.ms);
  //  Serial.println(data.accel);
  //  Serial.println(data.pres);
    i2c_eeprom_write_page(0x50, eeAddress, (byte *)pdata, size);    // write to EEPROM
    eeAddress += 15; //Move address to the next byte after float 'f'.
  }
  delay(10); //add a small delay

  Serial.println("Memory written");
  secondTest();
  Serial.print("End of reading ");
}

void loop() {
//  Serial.println("DONE !");
}

void secondTest() {

  Serial.begin(9600);
  Wire.begin(); // initialise the connection
  int eeAddress = 0; //EEPROM address to start reading from
  MYDATA *pdata = &data;
  // size of the MYDATA struct

  // variable to store data retrieved from eeprom
  MYDATA retrievedData;
  // byte pointer
  byte *pData = (byte*)&retrievedData;

  for (int t = 0; t <= maxread; t++) {
    i2c_eeprom_read_buffer(0x50, eeAddress, pData, sizeof(MYDATA));    // write to EEPROM

    Serial.println("Read custom object from EEPROM: ");
    Serial.println(t);
    Serial.println(retrievedData.ms);
    Serial.println(retrievedData.accel);
    Serial.println(retrievedData.pres);
    eeAddress += 15;
  }
  Serial.println("End of reading ");
}
void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
  int rdata = data;
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8)); // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(rdata);
  Wire.endTransmission();
}

// WARNING: address is a page address, 6-bit end will wrap around
// also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddresspage >> 8)); // MSB
  Wire.write((int)(eeaddresspage & 0xFF)); // LSB
  byte c;
  for ( c = 0; c < length; c++)
    Wire.write(data[c]);
  Wire.endTransmission();
}

byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
  byte rdata = 0xFF;
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8)); // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress, 1);
  if (Wire.available()) rdata = Wire.read();
  return rdata;
}

// maybe let's not read more than 30 or 32 bytes at a time!
void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8)); // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress, length);
  int c = 0;
  for ( c = 0; c < length; c++ )
    if (Wire.available()) buffer[c] = Wire.read();
}

Result is all reading is “0” - I’ve checked all the writings and they look allright. What did I miss ?

Sincerly
Steen

Hi again

Ok - found out - the small delay wat to be inside the for-look, to insure the writing finishing...

Sincerly Steen

So, working now?

YES! working.

Any thing to be aware of ? I've read the eeprom have pages. Do this read/write functions handle this ?

I'm curious and want to learn and understand these lines:

  //  byte *pdata = (byte*) data;
  MYDATA *pdata = &data;
  // size of the MYDATA struct
  int size = sizeof(MYDATA);

Where do I find some kind of a tutorial for newbies about this ?

Thanks for your help! I've appreciate it a lot !

Sincerly Steen