Saving int arrays to EEPROM?

Hi, recently build an array of relays which is controlled by a midi foot controller. I'm currently in the works of implementing presets. So far i have it so that you can create a preset, which is an int array containing 8 values. Each of these values control's a relay. Now that i can create presets, i would like to save them into EEPROM.

I've been playing around with eeprom and have found that you can only really store one byte (i think.) I'm unable to save an array of 8 values. I've tried using "EEPROMAnything" which is a library that claims to allow you to save arrays. But I have found that it only lets you save 1 array or for me, preset. My goal is to be able to save multiple presets (arrays) into EEPROM.

Does anybody have any experience or ideas on how to do this? Any advice is appreciated!

Thanks so much!

wfs123:
Hi, recently build an array of relays which is controlled by a midi foot controller. I'm currently in the works of implementing presets. So far i have it so that you can create a preset, which is an int array containing 8 values. Each of these values control's a relay. Now that i can create presets, i would like to save them into EEPROM.

I've been playing around with eeprom and have found that you can only really store one byte (i think.) I'm unable to save an array of 8 values. I've tried using "EEPROMAnything" which is a library that claims to allow you to save arrays. But I have found that it only lets you save 1 array or for me, preset. My goal is to be able to save multiple presets (arrays) into EEPROM.

Does anybody have any experience or ideas on how to do this? Any advice is appreciated!

Thanks so much!

Why do you need to save them to EEPROM? Are you trying to preserve a state that will survive a power cycle or do you just want access to the extra space?

Why do you need to save them to EEPROM? Are you trying to preserve a state that will survive a power cycle or do you just want access to the extra space?

This project is actually for my guitar rig. It's to control the effect pedals. So it's very important that i can save presets and access after a reboot, allowing the presets to be preserved.

also, if you are concerned about doing a lot of read/writes, you can use a circular buffer to minimize the impact on a any one location.

I attached an example sketch I did with a circular EEPROM buffer, here are the highlights:

#define STATE_LOCATION 513 // stay away from EEPROM used with a library
#define EEPROM_BUFFER 514  // location of the EEPROM circular buffer
#define BUFFER_LENGTH 121

in setup() i retrieve the saved values:

state = EEPROM.read(STATE_LOCATION);
  for (int i = 0; i < BUFFER_LENGTH; i++)
  {
    byte locator = EEPROM.read(EEPROM_BUFFER + i);
    if (locator == 0xFF)
    {
      eepromIndex = EEPROM_BUFFER + i;
      loadRainArray(eepromIndex);
      Serial.println(eepromIndex);
      break;
    }
  }

get EEPROM function:

void loadRainArray(int value)
{
  for (int i = 0; i < BUFFER_LENGTH - 1; i++)
   {
     value--;
     Serial.println(value);
     if (value < EEPROM_BUFFER) 
       {
         value = EEPROM_BUFFER + BUFFER_LENGTH;
       }
     byte rainValue = EEPROM.read(value);
     Serial.println(rainValue);
     if (rainValue < 255)
     {
       rainBucket[i] = rainValue;
     }
     else
     {
       rainBucket [i] = 0;
     }
   }
}

and save to EEPROM programmatically by advancing the index and saving on its location

Serial.println("one hour elapsed");
    //EEPROM write last value
    EEPROM.write(eepromIndex, rainBucket[0]);
    eepromIndex++;
    if (eepromIndex > EEPROM_BUFFER + BUFFER_LENGTH) eepromIndex = EEPROM_BUFFER;
    Serial.println(eepromIndex);
    EEPROM.write(eepromIndex, 0xFF);
    //

state is changed ad hoc programmatically and reads/writes to the same location. The frequency of writes is at least an order of magnitude less than writes to the buffer.

RainGauge.ino (8.36 KB)

Here is a simple sketch which writes multiple integer arrays to EEPROM. The write and read functions write/read to an address and an address +1. The number of EEPROM addresses required for an array will be 2x the size of the array.

Please pay attention to the computation of the EEPROM address from the array number and element.

An array element's EEPROM address is 2the array element _+ 2 the number of elements in the array*the array number[j] + Offset._
Array numbers and elements start at 0.
```
*#include <EEPROM.h>

int my2dArray[2][8] =
{
 {0x8888, 0x9999, 0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF},
 {0x9999, 0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF, 0x8888}
};

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

int address;

Serial.println ("Writing data.....");

for(int j=0; j<2; j++){

Serial.println();

for(int i=0; i<8; i++){

EEPROMWriteInt(address= ((2i)+(j16)+50), my2dArray[j][i]);//+50 to not start at 0
     Serial.println(address);
     
   }
 }
 Serial.println();
 Serial.println();
 Serial.println ("Reading data.....");

for(int j=0; j<2; j++){

Serial.println();

for(int i=0; i<8; i++){

unsigned int value= EEPROMReadInt(address=(2i)+(j16)+50);//+50 to not start at 0
     Serial.print(address);
     Serial.print('\t');
     Serial.println(value,HEX);

}
 }
}

void loop(){
}

//integer read/write functions found at http://forum.arduino.cc/index.php/topic,37470.0.html
//This function will write a 2 byte integer to the eeprom at the specified address and address + 1

void EEPROMWriteInt(int p_address, int p_value)
{
 byte lowByte = ((p_value >> 0) & 0xFF);
 byte highByte = ((p_value >> 8) & 0xFF);

EEPROM.write(p_address, lowByte);
 EEPROM.write(p_address + 1, highByte);
}

//This function will read a 2 byte integer from the eeprom at the specified address and address + 1
unsigned int EEPROMReadInt(int p_address)
{
 byte lowByte = EEPROM.read(p_address);
 byte highByte = EEPROM.read(p_address + 1);
 return ((lowByte << 0) & 0xFF) + ((highByte << 8)& 0xFF00);

}*
```

I have an entirely rational aversion to magic numbers.
(Uncompiled, untested)

#include <EEPROM.h>

const byte ROWS = 2;
const byte COLS = 8;
const int ADDRESS_OFFSET = 50;

int my2dArray[ROWS][COLS] = 
{
  {0x8888, 0x9999, 0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF},
  {0x9999, 0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF, 0x8888}
};

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

  int address;

  Serial.println ("Writing data.....");

  for(int j=0; j<ROWS; j++){

    Serial.println();

    for(int i=0; i<COLS; i++){

      EEPROMWriteInt(address= ((ROWS*i)+(j * COLS * sizeof (my2dArray [0][0]))+ ADDRESS_OFFSET), my2dArray[j][i]);
      Serial.println(address);
      
    }
  }
  Serial.println();
  Serial.println();
  Serial.println ("Reading data.....");

  for(int j=0; j<ROWS; j++){

    Serial.println();

    for(int i=0; i<COLS; i++){

      unsigned int value= EEPROMReadInt(address=(ROWS*i)+(j*COLS*sizeof (my2dArray [0][0]))+ADDRESS_OFFSET);
      Serial.print(address);
      Serial.print('\t'); 
      Serial.println(value,HEX);

    }
  }
}

void loop(){
}

//integer read/write functions found at http://forum.arduino.cc/index.php/topic,37470.0.html
//This function will write a 2 byte integer to the eeprom at the specified address and address + 1

void EEPROMWriteInt(int p_address, int p_value)
{
  byte lowByte = ((p_value >> 0) & 0xFF);
  byte highByte = ((p_value >> 8) & 0xFF);

  EEPROM.write(p_address, lowByte);
  EEPROM.write(p_address + 1, highByte);
}

//This function will read a 2 byte integer from the eeprom at the specified address and address + 1
unsigned int EEPROMReadInt(int p_address)
{
  byte lowByte = EEPROM.read(p_address); 
  byte highByte = EEPROM.read(p_address + 1);
  return ((lowByte << 0) & 0xFF) + ((highByte << 8)& 0xFF00);

}

Thanks for the push.

Here it is with out the magic numbers (compiled and tested). The magic 2 was from the number of bytes in an int and not the number of rows. Thanks for showing me that sizeof (array[0]0]) gives the element size of 2 bytes in an int which is the address increment.

#include <EEPROM.h>

const byte ROWS = 3;
const byte COLS = 8;
const int ADDRESS_OFFSET = 50;
//const byte ADDRESS_INCREMENT = 2;  //use sizeof(my2dArray[0][0]) instead

int my2dArray[ROWS][COLS] = 
{
  {0x8888, 0x9999, 0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF},
  {0x9999, 0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF, 0x8888},
  {0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF, 0x8888, 0x9999}
};

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

  int address;

  Serial.println ("Writing data.....");

  for(int j=0; j<ROWS; j++){

    Serial.println();

    for(int i=0; i<COLS; i++){

      EEPROMWriteInt(address= ((sizeof(my2dArray[0][0])*i)+(j*COLS*(sizeof (my2dArray[0][0])) + ADDRESS_OFFSET)), my2dArray[j][i]);
      Serial.println(address);
      
    }
  }
  Serial.println();
  Serial.println();
  Serial.println ("Reading data.....");

  for(int j=0; j<ROWS; j++){

    Serial.println();

    for(int i=0; i<COLS; i++){

      unsigned int value= EEPROMReadInt(address=((sizeof(my2dArray[0][0])*i))+(j*COLS*(sizeof (my2dArray[0][0])))+ADDRESS_OFFSET);
      Serial.print(address);
      Serial.print('\t'); 
      Serial.println(value,HEX);

    }
  }
}

void loop(){
}

//integer read/write functions found at http://forum.arduino.cc/index.php/topic,37470.0.html
//This function will write a 2 byte integer to the eeprom at the specified address and address + 1

void EEPROMWriteInt(int p_address, int p_value)
{
  byte lowByte = ((p_value >> 0) & 0xFF);
  byte highByte = ((p_value >> 8) & 0xFF);

  EEPROM.write(p_address, lowByte);
  EEPROM.write(p_address + 1, highByte);
}

//This function will read a 2 byte integer from the eeprom at the specified address and address + 1
unsigned int EEPROMReadInt(int p_address)
{
  byte lowByte = EEPROM.read(p_address); 
  byte highByte = EEPROM.read(p_address + 1);
  return ((lowByte << 0) & 0xFF) + ((highByte << 8)& 0xFF00);

}

It's an unfortunate coincidence that the number of rows is the same as the number of bytes in an int in your first example.

I like the eeprom_read and eeprom_write functions in AVR Libc. These work with several different data types and the eeprom_update function save on EEPROM wear, only writing a value if it has changed. (Using the eeprom_update functions may require an upgrade to a later version of AVR Libc than that which comes with the IDE. This is fairly straightforward and is described elsewhere on the forum.)

The basic technique is to define the variables (an array in this case) twice, once with the EEMEM attribute, then use the eeprom_read and eeprom_write functions to move data back and forth between the variables in EEPROM and those in SRAM. The nice thing is that it does away with having to track the addresses in EEPROM yourself. The compiler takes care of that and data in EEPROM is just dealt with as variables.

Simple example here:
http://forum.arduino.cc/index.php?topic=227994.msg1647324#msg1647324

I followed up on Jack's recommendation and decided to play around with avr/eeprom.h.

I rewrote the previous 2d integer array sketch to use that library, and as he says its pretty straightforward and powerful.

#include <avr/eeprom.h>

const int rows = 3;
const int cols = 8;

uint16_t my2dArray[rows][cols]= // arrays in SRAM

{
  {0x8888, 0x9999, 0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF},
  {0x9999, 0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF, 0x8888},
  {0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF, 0x8888, 0x9999}
};

const int len = sizeof(my2dArray[0][0])*cols;

uint16_t EEMEM  save1[len],save2[len],save3[len];//array destinations in eeprom


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

  Serial.println("Arrays read into eeprom");

  for(int j=0; j<rows; j++){

    Serial.println();

    Serial.print("my2dArray[");
    Serial.print(j);
    Serial.print ("]  ");

    for(int i=0; i<cols; i++){

      Serial.print(my2dArray[j][i],HEX);
      Serial.print('\t');

    }
  }
  Serial.println();

  eeprom_write_block(my2dArray[0], save3, len);
  eeprom_write_block(my2dArray[1], save2, len); 
  eeprom_write_block(my2dArray[2], save1, len);


  eeprom_read_block(my2dArray[0], save1, len);
  eeprom_read_block(my2dArray[1], save2, len);
  eeprom_read_block(my2dArray[2], save3, len);


  Serial.println();   
  Serial.println("Arrays read out of eeprom, new values");

  for(int j=0; j<rows; j++){

    Serial.println();

    Serial.print("my2dArray[");
    Serial.print(j);
    Serial.print ("]  ");

    for(int i=0; i<cols; i++){

      Serial.print(my2dArray[j][i],HEX);
      Serial.print('\t');

    }
  }
}

void loop(void)
{
}

I suppose that the data in EEPROM could also have been defined as

uint16_t EEMEM eeArray[rows][cols];

or even as a single block,

uint8_t EEMEM eeArray[rows * cols * 2];

Just different approaches. Glad it worked out for you.

Can't we use simply EEPROM.put() for doing this ?

safaenet:
Can't we use simply EEPROM.put() for doing this ?

Yes, but was that available 3 years ago ?

I know this is really, really late, but theres actually the undocumented function "void eeprom_update_block (void *__src, const void *__dst, size_t __n);" for that kind of stuff. Haven't tested it but compiler does not have any problems compiling it; for more info just google "eeprom.h source" and you'll find all the undocumented eeprom functions

Greetings, all

Can this method be used to write an array to an external EEPROM? Or is this limited to the onboard EEPROM?

For instance, can I use this method by just replacing every "EEPROM.write()" with "Wire.send()"?

Thank you