WebbotLib AVR library
WebbotLib It just does it
  C++ documentation  C documentation

<avr/eeprom.h>

Most AVR micro controllers contain some 'on-chip' EEPROM. This is memory that remembers its content even after the power is switched off.
This makes it a useful option if:
1. You have some configuration settings that you want to restore each time the robot is turned on
2. You are using a neural network and you want to retain what has been 'learned'
3. Or simply because you are running out of regular memory and want to move some of your variables or tables into EEPROM to free up some standard memory.
So in some regards you can think of it as a small, on-board, hard drive.
If you need more persistent storage than your micro processor contains then WebbotLib also supports the addition of external EEPROMs and sdCards via Storage
As well as the above benefits there are, of course, some down sides to using EEPROM memory.
1. It is slower to access than standard memory
2. To use data from EEPROM it first needs to be read into some standard memory. Then if you change its value you must remember to save it back out to EEPROM in order to preserve the value between power ups.
3. There are times (see later) when you don't want your program to restart with the old values
So how do I use EEPROM? Well first I should say that the code documented here is supplied with the compiler and wasn't written by me. All my library does is to automatically include this support if you are compiling for a device that contains any EEPROM. The functions detailed in this section have only been included to make the documentation more complete.
The first thing you need to do is decide which variables you want to store in EEPROM and then add the keyword EEMEM. For example:-
int8_t EEMEM myVar = 10;
This tells the compiler to make space for your variable in the EEPROM but you then have to change every place where you read or write to the variable.
To access the variable you must read it into a memory variable using 'eeprom_read_byte' or 'eeprom_read_word' (see details of these calls in the following pages). If you modify the value and want to write it back into EEPROM so that it is remembered you must then call the matching 'eeprom_write_byte' or 'eeprom_write_word'.
That covers simple numeric types but what about things like arrays and strings? These can be defined in the same way by pre-fixing their definition with EEMEM but you need to use the 'eeprom_read_block' and 'eeprom_write_block' calls.
Now that we have a basic understanding of how to access the EEPROM data we will now look at some of the potential pitfalls and suggest some better ways of working.
Assuming that you are storing more than one variable in EEPROM then you have to be very carefull when you are modifying your program. When the compiler finds data you want storing in EEPROM that it assigns them a location in the order that it comes across them. So assuming your program contains the following variables:-
int8_t EEMEM myVar1 = 10;
int8_t EEMEM myVar2 = 20;
These initial values will be placed into your hex file and assuming that your programmer is set up to transfer the eeprom data then these variables will all have been loaded into the EEPROM and all is ok.
Now lets add a new variable in the middle:-
int8_t EEMEM myVar1 = 10;
int8_t EEMEM myVar3 = 30;
int8_t EEMEM myVar2 = 20;
When you send this to your programmer, and it is set up to transfer the EEPROM data, then the new variables will be transferred across successfully but any changes to myVar1 and myVar2 will be lost.
The big problem happens when you don't send the new EEPROM data across (say because you wanted to keep the values of myVar1 and myVar2 from the last time you ran the program). The problem is that the new myVar3 is occupying the slot in EEPROM that used to be occupied by myVar2 and so will pickup its last written value. Equally: myVar2 is now in a previously unused location and so will pickup some random value.
So the lesson is that you add, edit, or delete any EEPROM variables then you will need to re-program the new EEPROM data into the micro controller and lose the previous values.
Some developers choose to write routines that save and restore all of the EEPROM variables in one go. They do this because it can be a bit of a pain to remember that for each EEMEM you have to change every access to the variable and also because if the variables are accessed frequently it can slow the program down. The easiest way of doing this is to create a structure or 'struct' (google is your friend!) that defines the data you want saving to EEPROM. So we could change the previous code to look like this:-
Step 1 - create a new data type called 'SAVED_DATA' that contains the data that needs to be held in eeprom:-
typedef struct s_eeprom {
    int8_t myVar1;
    int8_t myVar2;
    int8_t myVar3;
} SAVED_DATA;
Step 2 - create an EEMEM variable so that space is allocated in EEPROM along with initial values
SAVED_DATA EEMEM eeprom = { 10,30, 20};
Step 3 - create your standard memory variables as you would do normally:-
int8_t myVar1;
int8_t myVar2;
int8_t myVar3;
Step 4 - write a routine to read the data out of EEPROM and then unpack it into your variables:-
void restore(void){
    // Create a memory block with the same structure as the eeprom
    SAVED_DATA temp;
    // Read the data from eeprom into the 'temp' version in memory
    eeprom_read_block( &temp, &eeprom, sizeof(SAVED_DATA));
    // Now copy the variables out into their proper slots
    myVar1 = temp.myVar1;
    myVar2 = temp.myVar2;
    myVar3 = temp.myVar3;
}
Step 5 - write a routine to write the data to EEPROM:-
void save(void){
    // Create a memory block with the same structure as the eeprom
    SAVED_DATA temp;
    // Gather all variables to be saved into the structure
    temp.myVar1 = myVar1;
    temp.myVar2 = myVar2;
    temp.myVar3 = myVar3;
    // Now write the block out to eeprom
    eeprom_write_block(&temp, &eeprom, sizeof(SAVED_DATA));
}
The benefit of this approach is that you can write your program as if there was no EEPROM at all. Once you decide that a given variable needs to be stored in EEPROM you can just add it to the SAVED_DATA definition and add a line of code to each of save and restore to move the variable. Obviously in order for this to work you will need to call the 'restore' function somewhere at the start of your code to get the values from EEPROM. The program then runs at full speed with these variables in standard memory. It is up to you as to when you choose to save the values to EEPROM and you could do this in your main loop every 20 seconds say or when an event occurs such as a button being pressed.
Thats just one strategy you could use - its certainly not the only strategy - and you may have a better one!
Note that this file is automatically included if your micro processor has some on-board EEPROM.

 

Function

 


uint8_t eeprom_read_byte (const uint8_t *__p)

Read a byte from EEPROM.
Assuming you have a global variable declared as:-
uint8_t EEMEM myVar;
Then you can read its current value into memory inside a function by calling:-
uint8_t currentValue = eeprom_read_byte(&myVar);

eeprom_write_byte (uint8_t *__p, uint8_t __value)

Writes a byte to EEPROM.
Assuming you have a global variable declared as:-
uint8_t EEMEM myVar;
Then you can assign it a value of 10 by calling:-
eeprom_write_byte(&myVar, 10);

uint16_t eeprom_read_word(const uint16_t* __p)

Read a word (ie a 16 bit number) from EEPROM.
Assuming you have a global variable declared as:-
uint16_t EEMEM myVar;
Then you can read its current value into memory inside a function by calling:-
uint16_t currentValue = eeprom_read_word(&myVar);

eeprom_write_word(uint16_t* __p, uint16_t __value)

Writes a word (ie a 16 bit number) to EEPROM.
Assuming you have a global variable declared as:-
uint16_t EEMEM myVar;
Then you can assign it a value of 10 by calling:-
eeprom_write_word(&myVar, 10);

uint32_t eeprom_read_dword(const uint32_t* __p)

Read a double word (ie a 32 bit number) from EEPROM.
Assuming you have a global variable declared as:-
uint32_t EEMEM myVar;
Then you can read its current value into memory inside a function by calling:-
uint32_t currentValue = eeprom_read_dword(&myVar);

eeprom_write_dword(uint32_t* __p, uint32_t __value)

Writes a double word (ie a 32 bit number) to EEPROM.
Assuming you have a global variable declared as:-
uint32_t EEMEM myVar;
Then you can assign it a value of 10 by calling:-
eeprom_write_dword(&myVar, 10);

eeprom_read_block (void *__dst, const void *__src, size_t __n)

Read a block of data from EEPROM into standard memory.
The first parameter is the address in standard memory that you want to read the data to, and the second parameter is the address of the EEPROM variable. The third parameter is the number of bytes to be copied.
Note that since these are both memory addresses then they are normally prefixed with an '&' symbol.
For example if you had a string variable declared as follows:-
char EEMEM eepromString[10];
Then you could read it into memory inside a function as follows:-
char ramString[10];
eeprom_read_block( &ramString[0], &eepromString[0], 10);

eeprom_write_block (const void * __src, void *__dst, size_t __n)

Writes a block of data to EEPROM from standard memory.
The first parameter is the address in standard memory of the data you want to write, and the second parameter is the address of the EEPROM area that you want to write to. The third parameter is the number of bytes to be copied.
Note that since these are both memory addresses then they are normally prefixed with an '&' symbol.
For example if you had a string variable declared as follows:-
char EEMEM eepromString[10];
Then you could write the EEPROM with the value 'Webbot' as follows:-
eeprom_write_block( "Webbot", &eepromString[0], 10);

Valid XHTML 1.0 Transitional