5

I have this program in which I can store a single value in EEPROM. Can I store an array of values in EEPROM? How?

    #include <avr/io.h>
    #include <avr/eeprom.h>

    // macro for easier usage
    #define read_eeprom_word(address) eeprom_read_word ((const uint16_t*)address)
    #define write_eeprom_word(address,value) eeprom_write_word ((uint16_t*)address,(uint16_t)value)

    //declare an eeprom variable
    unsigned int EEMEM   my_eeprom_word;

    int main(void)
   {

    write_eeprom_word(&my_eeprom_word,OCR1A);       // store value in eeprom

    OCR1A = read_eeprom_word(&my_eeprom_word);     // restore from eeprom

    while(1)
    {

    }
    }
JYelton
  • 32,302
  • 33
  • 134
  • 249
user3052614
  • 77
  • 1
  • 1
  • 7
  • On a side note, you might like this tutorial [PDF]: http://deans-avr-tutorials.googlecode.com/svn/trunk/EEPROM/Output/EEPROM.pdf – Chris Laplante Feb 25 '14 at 18:42

1 Answers1

6

You can declare an eeprom array and write individual positions. Note that unlike the ram array you can only read write to the eeprom array using the read/write eeprom macro.

The code below is to read/write 16bit unsigned values

#include <avr/io.h>
#include <avr/eeprom.h>

// macro for easier usage
#define read_eeprom_word(address) eeprom_read_word ((const uint16_t*)address)
#define write_eeprom_word(address,value) eeprom_write_word ((uint16_t*)address,(uint16_t)value)
#define update_eeprom_word(address,value) eeprom_update_word ((uint16_t*)address,(uint16_t)value)

//declare an eeprom array
unsigned int EEMEM  my_eeprom_array[10];

// declare a ram array
unsigned int my_ram_array[10];

int main(void)

{    
    // write to eeprom array
    write_eeprom_word(&my_eeprom_array[0], 1);  // write value 1 to position 0 of the eeprom array
    write_eeprom_word(&my_eeprom_array[1], 2);  // write value 2 to position 1 of the eeprom array
    write_eeprom_word(&my_eeprom_array[2], 3);  // write value 3 to position 2 of the eeprom array

    // read from eeprom array
    my_ram_array[0] = read_eeprom_word(&my_eeprom_array[0]);   // read value from position 0 of the eeprom array to ram array position 0
    my_ram_array[1] = read_eeprom_word(&my_eeprom_array[1]);   // read value from position 1 of the eeprom array to ram array position 1
    my_ram_array[2] = read_eeprom_word(&my_eeprom_array[2]);   // read value from position 2 of the eeprom array to ram array position 2

    while(1);    
}

An alternative is to use update instead of write. This function checks the content of the eeprom cell and only writes the data if it is different from the existing value in order to reduce unneeded writes and reduce the eeprom wear.

 // update eeprom array
    update_eeprom_word(&my_eeprom_array[0], 1);  // write value 1 to position 0 of the eeprom array only if it differs
    update_eeprom_word(&my_eeprom_array[1], 2);  // write value 2 to position 1 of the eeprom array only if it differs
    update_eeprom_word(&my_eeprom_array[2], 3);  // write value 3 to position 2 of the eeprom array only if it differs

The AVR eeprom handling routines are listed http://www.nongnu.org/avr-libc/user-manual/group__avr__eeprom.html


There is another alternative that can copy the entire ram array to the eeprom array and vice-versa, it uses the block write:

#include <avr/io.h>
#include <avr/eeprom.h>

// macro for easier usage
#define read_eeprom_array(address,value_p,length) eeprom_read_block ((void *)value_p, (const void *)address, length)
#define write_eeprom_array(address,value_p,length) eeprom_write_block ((const void *)value_p, (void *)address, length)


//declare an eeprom array
unsigned int EEMEM  my_eeprom_array[10];

// declare a ram array and initialize
unsigned int my_ram_array[10]={1,2,3,4,5,6,7,8,9};

// declare another ram array
unsigned int my_other_ram_array[10];

int main(void)

{    
    // Copy data from my_ram_array to eeprom array
    write_eeprom_array(my_eeprom_array,my_ram_array,sizeof(my_eeprom_array));

    // restore to my_other_ram_array from eeprom
    read_eeprom_array(my_eeprom_array,my_other_ram_array,sizeof(my_eeprom_array));

    while(1);    
}

The last parameter in the block write is how many bytes to write. In the example above the array length is 10 16bit integers which means 10 * 2bytes=20 bytes.
Instead of using

write_eeprom_array(my_eeprom_array,my_ram_array,20);

I have used the sizeof() function that returns the byte length of the array so it doesn't need to be changed every time the array size is changed

write_eeprom_array(my_eeprom_array,my_ram_array,sizeof(my_eeprom_array));

If you want you can use that value to manipulate the write/read length, for example you can write the first 3 values only

write_eeprom_array(my_eeprom_array,my_ram_array,3);

or values my_ram_array[3], my_ram_array[4] ,my_ram_array[5]

write_eeprom_array(&my_eeprom_array[3],&my_ram_array[3],3);
alexan_e
  • 11,070
  • 1
  • 28
  • 62
  • While everything you say is correct, I consider those function macros bad practice. It helps to avoid a cast here and there, but it hides the actual implementation and being able to pass anything to the macro parameters without getting a warning is error prone. Using explicit casts makes it clear, that it was the actual intention of the programmer to pass that variable in that way. – Rev Feb 26 '14 at 08:24
  • @Rev1.0 The macro only saves the need for additional typing of the typecast (it doesn't avoid it) so I don't see how it makes a difference regarding compiler warnings. After all the function call is exactly the same so if one way is going to give the warning so does the other. Using macros is a matter of preference, the correct type for each function (that also applies to the macro) is described in the manual so users are supposed to refer to it before they use them. – alexan_e Feb 26 '14 at 08:47
  • 2
    I am aware of that. Its just that the macro hides the explicit cast from the programmers perspective. When calling the macro, the programmer has no motivation to think about the expected type and doesn't even notice if he passes a unintended type. This may be a matter of preference, I just wanted to point out that I think it looks little bit dirty to me and may lead to sloppy programming. – Rev Feb 26 '14 at 09:36