For my ongoing clock project, I want to persistently store some data. That is, store data that is retained after turning off the Arduino. The processor on the Arduino board comes with on-board EEPROM. In the case of the Arduino Uno, the processor is the Atmega328, equipped with 1 glorious KByte of EEPROM memory.
The AVR libraries that come with the ATmega implements a relatively broad set of functions for reading, writing and management of the EEPROM (for a description see the AVR user manual). However, the Arduino standard EEPROM library exposes only functionality for reading and writing a single byte, as described here.
This is why I wrote the EEPROMex library, an extension of the standard Arduino EEPROM library. It writes and reads basic types like bytes, longs, ints, floats & doubles. It can also read/write single bits, arbitrary data-formats and arrays. It adds debug functionality to identify and stop writing outside of the EEPROM memory size and excessive writing to prevent memory wear.
The library
First of all, the library can be downloaded here:
The library starts by implementing the functions as present in the default EEPROM library, so it is fully compatible. You only need to change #include <EEPROM.h>
to #include <EEPROMex.h>
. The following example will work with both the standard and extended EEPROM library:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <EEPROMex.h> int address = 0; byte input = 100; byte output = 0; void setup() { Serial.begin(9600); EEPROM.write(address, input); output = EEPROM.read(address); Serial.print(address); Serial.print("\t"); Serial.print(output); Serial.println(); } void loop() { // Nothing to do during loop } |
Writing different data formats
The aim of the library is to also support other standard data types: it currently implements writing and reading to int
, long
, float
and double
.
For reading:
uint8_t read(int address);
uint8_t readByte(int address);
uint16_t readInt(int address);
uint32_t readLong(int address);
float readFloat(int address);
double readDouble(int address);
Where address is the starting position in EEPROM, and the return value the value read from EEPROM. For writing:
bool write(int address, uint8_t value);
bool writeByte(int address, uint8_t value);
bool writeInt(int address, uint16_t value);
bool writeLong(int address, uint32_t value);
bool writeFloat(int address, float value);
bool writeDouble(int address, double value);
Where the return value indicates if the write has been successful. Note that readByte
and writeByte
are the same as read
and write
and have only been added for naming consistency. So let us now try the following example :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
int address = 0; double input = 101.101; double output = 0; void setup() { Serial.begin(9600); EEPROM.writeDouble(address, input); output = EEPROM.readDouble(address); Serial.print(address); Serial.print("\t"); Serial.print(output); Serial.println(); } void loop() {} |
Update data
The write function of the AVR library that we are using will always overwrite the existing EEPROM value, even if it is equal to the one already present. Overwriting this cell has no practical use, but will increase EEPROM wear. To solve this, I added update functionality. The update functions are different from the write functions, in that they will check per byte if the current value differs and only update the the cell with a different value. This will not only reduce wear, and can also significantly reduce write time.
bool update(int address, uint8_t value);
bool updateByte(int address, uint8_t value);
bool updateInt(int address, uint16_t value);
bool updateLong(int address, uint32_t value);
bool updateFloat(int address, float value);
bool updateDouble(int address, double);
Efficient storage, writing single bits
Depending on your requirements, you may want to be more efficient in the way you store certain values. This is particularly relevant if you want to store Boolean values: As you need only one bit to store Boolean, you can store 8 Booleans in a single byte.
The following functions implements reading and writing single bits:
bool readBit(int address, byte bit)
Where bit
is the write position in the byte, ranging from [0..7], with bit 0 being the right-most. The return value is the read bit.
bool writeBit(int address, uint8_t bit, bool value)
bool updateBit(int address, uint8_t bit, bool value)
Writing data blocks
We can generalize our writing and reading functions so that they can handle any kind of data structure :
int readBlock(int address, const T& value)
int writeBlock(int address, const T& value)
int updateBlock(int address, const T& value)
where T is the type of the data to read/write/update. This can be a basic type, but also a more complex type like a struct. The return value gives the number of bytes that have been read, written or updated.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#include int address = 0; struct keyValuePair { int key; float value; }; keyValuePair keyValueInput; keyValuePair keyValueOutput; void setup() { Serial.begin(9600); keyValueInput.key = 4; keyValueInput.value = 8.8; EEPROM.writeBlock(address, keyValueInput); EEPROM.readBlock(address, keyValueOutput); Serial.print(keyValueOutput.key); Serial.print("\t"); Serial.print(keyValueOutput.value); Serial.println(); } void loop() {} |
The library also supports reading and writing of arrays of a any kind of data structure. We can, for exampe, write an arrays of chars (a string), but we can also read/write, for example, arrays of structs.
int readBlock(int address, const T[]; value, int items)
int writeBlock(int address, const T[]; value, int items)
int updateBlock(int address, const T[]; value, int items)
Let’s have a look at the following example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include int address = 0; struct keyValuePair { int key; float value; }; keyValuePair keyValueInput[2]; keyValuePair keyValueOutput[2]; void setup() { Serial.begin(9600); keyValueInput[0].key = 2; keyValueInput[0].value = 4.4; keyValueInput[1].key = 4; keyValueInput[1].value = 8.8; EEPROM.writeBlock(address, keyValueInput,2); EEPROM.readBlock(address, keyValueOutput,2); Serial.print(keyValueOutput[0].key); Serial.print("\t"); Serial.println(keyValueOutput[0].value); Serial.print(keyValueOutput[1].key); Serial.print("\t"); Serial.println(keyValueOutput[1].value); } void loop() { } |
Address allocation
Typically, we write and store data to the EEPROM using fixed addresses, and it often proves to be a hassle to maintain them properly, such that there are not overwrites nor gaps. To simplify bookkeeping of addresses you can use the following function.
int getAddress(int noOfBytes);
The input noOfBytes
indicates how many bytes your data structure are needed, the output is the first address available for writing in EEPROM. As long as you use this function to assign addresses to your variables, there will be no overlap between variables. This function is not much more than an every increasing counter and it differs from a malloc call in that there is no way to free memory. It is, however completely deterministic, which means that if acquire your address at the start of your applications, before any loops or conditional statements, every memory pointer will be the same after each reboot of the board.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <EEPROMex.h> int address = 0; void setup() { Serial.begin(9600); Serial.println(); // Always get the adresses first and in the same order int addressByte = EEPROM.getAddress(sizeof(byte)); int addressInt = EEPROM.getAddress(sizeof(int)); int addressLong = EEPROM.getAddress(sizeof(long)); int addressFloat = EEPROM.getAddress(sizeof(float)); int addressDouble = EEPROM.getAddress(sizeof(double)); int addressByteArray = EEPROM.getAddress(sizeof(byte)*7); int addressCharArray = EEPROM.getAddress(sizeof(char)*7); Serial.println("-----------------------------------"); Serial.println("Following adresses have been issued"); Serial.println("-----------------------------------"); Serial.println("begin adress \t\t size"); Serial.print(addressByte); Serial.print(" \t\t\t "); Serial.print(sizeof(byte)); Serial.println(" (byte)"); Serial.print(addressInt); Serial.print(" \t\t\t "); Serial.print(sizeof(int)); Serial.println(" (int)"); Serial.print(addressLong); Serial.print(" \t\t\t "); Serial.print(sizeof(long)); Serial.println(" (long)"); Serial.print(addressFloat); Serial.print(" \t\t\t "); Serial.print(sizeof(float)); Serial.println(" (float)"); Serial.print(addressDouble); Serial.print(" \t\t\t "); Serial.print(sizeof(double)); Serial.println(" (double)"); Serial.print(addressByteArray); Serial.print(" \t\t\t "); Serial.print(sizeof(byte)*7); Serial.println(" (array of 7 bytes)"); Serial.print(addressCharArray); Serial.print(" \t\t\t "); Serial.print(sizeof(char)*7); Serial.println(" (array of 7 chars)"); } void loop() { } |
Debugging options
The processor documentation (which can be found here , section 8.4) says the following about EEPROM:
The ATmega48A/PA/88A/PA/168A/PA/328/P contains 256/512/512/1Kbytes of data EEPROM memory. It is organized as a separate data space, in which single bytes can be read and written. The EEPROM has an endurance of at least 100,000 write/erase cycles.
This is may sound like a large number, but in theory you could burn out a memory cell in a few minutes: a write/erase cycle takes approximately 4 ms, so writing 100.000 times to a single cell takes 6 1/2 min. While there are some tests show much more writes before failure, they do not take into account reduction of retention time (see this article on EEPROM failure in space).
Notice how the documentation talks about write/erase rather than write. EEPROM programming consists of erasing a block (in our case a block of 8 bits, 1 byte), which means setting all bits to 0, and subsequently writing the bits that should become 1. It is the erase step that causes wear to the memory. This means that in theory we can separate the two, and overwriting an EEPROM value from 170, in bit format 10101010 to 235, in bit format 11101011 would only require writing the 2 specific bits, without erasing and causing wear. While this is possible (see the manual, section 8.6.3) it has not been implemented in the AVR function underpinning this library. (This library does not implement it either, but delivers similar functionality on byte scale using the update functions).
As said, it is easy to burn out a memory cell in few minutes, so while debugging your application it would be very useful to limit the number of allowed writes. It is easy to put a bracket at the wrong location, and placing an EEPROM write inside of a loop, rather than outside, and introduce extensive writing causing wear. The following function helps limit the number of writes.
setMaxAllowedWrites(int allowedWrites);
More writes than allowed will be refused and result in an error message. You can also set the address range used by the library:
setMemPool(int base, int memSize);
The lower value is used by the getAddress
function, the upper value is used for setting the EEPROM size. Writing outside the maximum size will result in an error message. The following EEPROM sizes are predefined
Based on processor:
EEPROMSizeATmega168
EEPROMSizeATmega328
EEPROMSizeATmega1280
Based on board:
EEPROMSizeUno
EEPROMSizeUnoSMD
EEPROMSizeLilypad
EEPROMSizeDuemilanove
EEPROMSizeMega
EEPROMSizeDiecimila
EEPROMSizeNano
Note that these errors will only occur when _EEPROMex_DEBUG is enabled in EEPROMex.cpp. if not enabled, the checks will be optimized away during compilation. This reduced the performance overhead and memory usage of the library, so it is encouraged to disable the function after debugging.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#include <EEPROMex.h> int address; const int maxAllowedWrites = 10; const int memBase = 350; void setup() { // Note: Be sure that _EEPROMex_DEBUG is enabled in EEPROMex.h, to enable error checking Serial.begin(9600); Serial.println(); // Always get the adress(es) first address = EEPROM.getAddress(sizeof(byte)); // start reading from position memBase (address 0) of the EEPROM. Set maximumSize to EEPROMSizeUno // Writes before membase or beyond EEPROMSizeUno will only give errors when _EEPROMex_DEBUG is set EEPROM.setMemPool(memBase, EEPROMSizeUno); // Set maximum allowed writes to maxAllowedWrites. // More writes will only give errors when _EEPROMex_DEBUG is set EEPROM.setMaxAllowedWrites(maxAllowedWrites); Serial.println("-------------------------------------------------------------"); Serial.println("Check if we get errors when writing too much or out of bounds"); Serial.println("-------------------------------------------------------------"); Serial.println("Trying to write outside of EEPROM memory..."); EEPROM.writeLong(EEPROMSizeUno+10,1000); Serial.println(); Serial.println("Trying to exceed number of writes..."); for(int i=1;i<=20; i++) { if (!EEPROM.writeLong(address,1000)) { return; } } Serial.println(); } void loop() { } |
EEPROM performance
All of the read/write functions first make sure the EEPROM is ready to be accessed. Since this may cause long delays if a write operation is still pending, time-critical applications should first poll the EEPROM e. g. using the isReady
function before attempting any actual I/O:
bool isReady();
Let’s end with a slightly more extensive example that implements this and combines it with a few other functions. This example demonstrates the write speed and read speeds of the EEPROM memory:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
#include <EEPROMex.h> int address = 0; void setup() { Serial.begin(9600); Serial.println("-----------------------------------------------------"); Serial.println("Check how much time until EEPROM ready to be accessed"); Serial.println("-----------------------------------------------------"); int startMillis; int endMillis; int waitMillis; // Write byte.. startMillis = millis(); EEPROM.writeByte(address,16); endMillis = millis(); // .. and wait for ready waitMillis = 0; while (!EEPROM.isReady()) { delay(1); waitMillis++; } Serial.print("Time to write 1 byte (ms) : "); Serial.println(endMillis-startMillis); Serial.print("Recovery time after writing byte (ms) : "); Serial.println(waitMillis); // Write long .. startMillis = millis(); EEPROM.writeLong(address,106); endMillis = millis(); // .. and wait for ready waitMillis = 0; while (!EEPROM.isReady()) { delay(1); waitMillis++; } Serial.print("Time to write Long (4 bytes) (ms) : "); Serial.println(endMillis-startMillis); Serial.print("Recovery time after writing long (ms) : "); Serial.println(waitMillis); // Read long .. startMillis = millis(); EEPROM.readLong(address); endMillis = millis(); // .. and wait for ready waitMillis = 0; while (!EEPROM.isReady()) { delay(1); waitMillis++; } Serial.print("Time to read Long (4 bytes) (ms) : "); Serial.println(endMillis-startMillis); Serial.print("Recovery time after reading long (ms) : "); Serial.println(waitMillis); // Write times arrays int itemsInArray = 7; byte array7[] = {64, 32, 16, 8 , 4 , 2 , 1 }; byte arraydif7[] = {1 , 2 , 4 , 8 , 16, 32, 64}; byte arrayDif3[] = {1 , 0 , 4 , 0 , 16, 0 , 64}; byte output[sizeof(array7)]; // Time to write 7 byte array startMillis = millis(); EEPROM.writeBlock<byte>(address, array7, itemsInArray); endMillis = millis(); Serial.print("Time to write 7 byte array (ms) : "); Serial.println(endMillis-startMillis); // Time to update 7 byte array with 7 new values startMillis = millis(); EEPROM.updateBlock<byte>(address, arraydif7, itemsInArray); endMillis = millis(); Serial.print("Time to update 7 byte array with 7 new values (ms): "); Serial.println(endMillis-startMillis); // Time to update 7 byte array with 3 new values startMillis = millis(); EEPROM.updateBlock<byte>(address, arrayDif3, itemsInArray); endMillis = millis(); Serial.print("Time to update 7 byte array with 3 new values (ms): "); Serial.println(endMillis-startMillis); // Time to read 7 byte array startMillis = millis(); EEPROM.readBlock<byte>(address, output, itemsInArray); endMillis = millis(); Serial.print("Time to read 7 byte array (ms) : "); Serial.println(endMillis-startMillis); } void loop() { } |
The output of this sketch shows us a few things:
- Writing one byte does not cost time (at least less than 1 ms), but it takes the EEPROM 4 to be ready for next write).
- As a result, writing more than one byte will take more time. I would have expected writing a 4 bytes Long to take 3*4=12 ms, with a 4 ms recovery time.
- Reading data from EEPROM does not cost significant time, and it does not take time for the EEPROM to recover.
- When writing with the updateBlock instead of the writeBlock function the updateBlock is comparable when all bytes need to be changed and faster if less bytes need updating.
So, that’s it for now. Good luck using the library and let me know what you find!
August 6, 2012 at 10:40 AM
Sir, How should i go for MultiDimension Array
like
int TimeTable[Max_Periods][OnHours,OnMins,Duration];
for reading and writing
August 19, 2012 at 10:02 PM
Hi,
The array function does not explicitly allow this, but I’ll try to figure out a more general way to deal with multi-dimensional arrays in a next version
September 21, 2012 at 10:05 AM
Hi,
I really like your EPROM extende library and have tried now for a while to get it to work bu i get the same error all the time.
I use Arduino 1.0 and when i compile the example i get the error:
G:\arduino\arduino-1.0\libraries\EEPROMEx/EEPROMex.h:159: error: conflicting declaration ‘EEPROMClassEx EEPROM’
G:\arduino\arduino-1.0\libraries\EEPROM\EEPROM.h:32: error: ‘EEPROM’ has a previous declaration as ‘EEPROMClass EEPROM’
any pointers?
best regards
chris
January 3, 2013 at 12:20 PM
Hi Chris,
Can you include a sample sketch that creates this issue?
January 19, 2013 at 7:25 PM
I think this is cause by the spelling error, it disappears after changing #include to .
I’m using the example code provided with the library with IDE 1.0.3
After the change I get the error “‘EEPROM’ was not declared in this scope”
so, I included the standard eeprom library (I assume its unnecessary?) regardless.. error is
‘class EEPROMclass’ has no member named ‘writeInt’
I’m a greenhorn.. the only assumption I can make from here is there is a problem in addressing the class, could this also be due to the typo?
January 19, 2013 at 7:29 PM
haha… of course html would hide what I said… correction ” I changed include EEPROMex to EEPROMEx” when I referred to a typo
January 19, 2013 at 7:54 PM
I got it, and realized that this was already mentioned below.
Christian, in your arduino folder /libraries/EEPROMex/
EEPROMex.cpp just needs the typo edited.
Which Roland mentions in a comment a few below this one.
// #include “EEPROMEx.h”
#include “EEPROMex.h”
January 21, 2013 at 12:11 AM
True, I will update that. It has not been an issue for me. Perhaps Windows is not case sensitive?
January 21, 2013 at 1:12 AM
Sorry about that. There now is a fixed version available for download. Please let me know what you find!
October 10, 2012 at 11:19 AM
The “setMaxAllowedWrites(int allowedWrites);” is here an int.
Is it a short or long int?
January 3, 2013 at 12:18 PM
According to the Arduino website:
On the Arduino Uno (and other ATMega based boards) an int stores a 16-bit (2-byte) value. … On the Arduino Due, an int stores a 32-bit (4-byte) value.
I will remove the ambiguity in the next version
December 4, 2012 at 2:50 PM
Great library, really made life easier for me today, i thought i had to write all this functions by myself til i found this, thanks
January 3, 2013 at 12:10 PM
Thanks! you’re welcome 🙂
December 17, 2012 at 6:43 AM
hey there is a typo in EEPROMex.cpp
// #include “EEPROMEx.h”
#include “EEPROMex.h”
January 3, 2013 at 12:16 PM
Ha,
Thanks for catching that! I will update the library.
April 13, 2014 at 5:12 PM
I think this typo is still present in keywords.txt.
Line 42: “EEPROMEx KEYWORD2”
May 9, 2014 at 6:29 PM
Thanks, I will take it up in the next release
January 7, 2013 at 3:58 AM
i am getting an error not sure what to fix
byte MO [21]; declared
in setup vod is
EEPROM.readBlock(0, MO,21);
error is
C:\Users\robert\Documents\Arduino\libraries\EEPROMEx/EEPROMex.h: In member function ‘int EEPROMClassEx::readBlock(int, const T*, int) [with T = byte]’:
CMSBridge_ino2timing_changes.ino:81: instantiated from here
C:\Users\robert\Documents\Arduino\libraries\EEPROMEx/EEPROMex.h:92: warning: comparison between signed and unsigned integer expressions
January 22, 2013 at 5:13 PM
Can you post the full program?
January 19, 2013 at 11:39 PM
I have an array that is too large to fix in ram. Is there a way to address aspect of the array in EEPROM without reading it into or writing it from ram?
EEPROM.writeBlock(address, “int array[122]=3245”, 122);
the above line obviously doesn’t work but I need change that aspect of the array in that way, directly in ee
having it in ram causes issues…Using PROGMEM an transferring it over is great
except for the fact that it is a one off type of thing and the array values need to be changed as the program progresses
January 22, 2013 at 5:13 PM
I have not tried such a thing, but I think you are on the right track: First push all your initial values in Flash using PROGMEM and copy these values during first start-up to EEPROM. You probably want to move these values only once to EEPROM, and afterwards start using the EEPROM values. You can do that in at least two ways: 1. Make a dedicated program that that only sets the initial values and run that once. Next start using your main program. 2. In you main program, use an initializer variable that you write to EEPROM at the beginning of the sequence. If you start the program it will check if this initializer is set, and if not: write Flash to EEPROM.
Let me know what comes out!
February 28, 2013 at 9:11 PM
I am getting the following error’s implementing your example:
——————————————————————————————————–
C:\Users\h.arends\Documents\Arduino\libraries\EEPROMEx/EEPROMEx.h:23:20: warning: EEPROM.h: No such file or directory
EEPROM.ino: In function ‘void setMempoolEx()’:
EEPROM:30: error: expected primary-expression before ‘=’ token
EEPROM:30: error: expected primary-expression before ‘,’ token
EEPROM:30: error: expected `;’ before ‘)’ token
EEPROM.ino: In function ‘boolean loadConfigEx()’:
EEPROM.ino:37: warning: comparison with string literal results in unspecified behaviour
———————————————————————————————————-
As i havent included EEPROM.h becourse it should not be.
Maybe there is a other error?
March 2, 2013 at 12:23 PM
Please discard the earlier message.
But i stil get the following error while compiling:
In file included from C:\Users\h.arends\Documents\Arduino\libraries\EEPROMEx\EEPROMEx.cpp:23:
C:\Users\h.arends\Documents\Arduino\libraries\EEPROMEx\/EEPROMEx.h:23:20: warning: EEPROM.h: No such file or directory
C:\Users\h.arends\Documents\Arduino\libraries\EEPROMEx\EEPROMEx.cpp: In member function ‘bool EEPROMClassEx::writeBit(int, uint8_t, bool)’:
C:\Users\h.arends\Documents\Arduino\libraries\EEPROMEx\EEPROMEx.cpp:148: warning: no return statement in function returning non-void
C:\Users\h.arends\Documents\Arduino\libraries\EEPROMEx\EEPROMEx.cpp: In member function ‘bool EEPROMClassEx::updateBit(int, uint8_t, bool)’:
C:\Users\h.arends\Documents\Arduino\libraries\EEPROMEx\EEPROMEx.cpp:203: warning: control reaches end of non-void function
C:\Users\h.arends\Documents\Arduino\libraries\EEPROMEx\EEPROMEx.cpp: In member function ‘bool EEPROMClassEx::writeBit(int, uint8_t, bool)’:
C:\Users\h.arends\Documents\Arduino\libraries\EEPROMEx\EEPROMEx.cpp:148: warning: control reaches end of non-void function
April 21, 2013 at 9:02 AM
Hi, it seems your main program is not including time.h
March 4, 2013 at 4:22 AM
Another typo/bug in EEPROMex.cpp
Line 197:
byteValOutput &= !(1 << bit); //Set bit to 0
should be:
byteValOutput &= ~(1 << bit); //Set bit to 0
Using logical not clears the entire byte, not just that bit.
Also, is the code in a repository somewhere? I've got a few enhancements I'd like to make when I have some time.
April 21, 2013 at 9:01 AM
Hi, good catch! Thanks. Yes, the code is placed in a github repository: https://github.com/thijse/Arduino-Libraries.
I’m very interested in your changes/additions
March 12, 2013 at 1:31 AM
Hi Thijs, I’ve a question about saving/updating a quite complex Structure, without loosing data by overwrtie:
I have an Array (
arr[1]{time1=1200,time2=1400,duration=30,min=10,max=50}
) and I can edit these in a menu. Now I wanna load the values after reset. So I call updateBlock(4,arr) to save and readBlock(4,arr) to load after reset. But I wanna make it easy to edit for other users and maybe someone saves something at adresse 2 and 21. When the array is to big it overwrites stuff. How can I avoid this without telling the user don’t save before adresse 200 or after 2 to have room to extand my array?
Is it better to save the whole config in a Struct and update this by calling it once?
Hope you have a hint to point me into right direction.
THX Moritz
April 21, 2013 at 8:58 AM
Hi Moriz,
I’m afraid that I do not fully understand you question, but I’ll make a guess:
Storing an array of structs should not be an issue, you can store an array of any type. I suppose, however, you do not want to store the full array if just 1 struct has changed. This is particularly smart, because of the limited writes an EEPROM can handle.
This means that you have to manage the addresses yourself. This is not that difficult. The address would be something like:
Adress = StartAdress + itemNo * sizeof(structType)
March 17, 2013 at 11:29 AM
Hi,
I found your library and it looks great since its doing exactly what i needed. But i have a problem, i tried uploaded one of the example (EEPROMbackup) after download it erliear today and it gives a lot of error. I’m new to arduino and coding and would appreciate your help with the error and the reason for them.
Here are the errors:
EEPROMBackup:25: error: variable or field ‘digitalClockDisplay’ declared void
EEPROMBackup:25: error: ‘time_t’ was not declared in this scope
EEPROMBackup:25: error: ‘time_t’ does not name a type
EEPROMBackup:26: error: ‘time_t’ does not name a type
EEPROMBackup.pde: In function ‘bool CompareFunc(const void*, const void*)’:
EEPROMBackup:39: error: expected initializer before ‘*’ token
EEPROMBackup:40: error: expected initializer before ‘*’ token
EEPROMBackup:43: error: ‘candidate’ was not declared in this scope
EEPROMBackup:43: error: ‘minTime’ was not declared in this scope
EEPROMBackup:43: error: ‘maxTime’ was not declared in this scope
EEPROMBackup:48: error: ‘candidate’ was not declared in this scope
EEPROMBackup:48: error: ‘current’ was not declared in this scope
EEPROMBackup.pde: At global scope:
EEPROMBackup:53: error: expected constructor, destructor, or type conversion before ‘<' token
EEPROMBackup.pde: In function 'void setup()':
EEPROMBackup:70: error: 'timeBackup' was not declared in this scope
EEPROMBackup:70: error: 'minTime' was not declared in this scope
EEPROMBackup:71: error: 'setTime' was not declared in this scope
EEPROMBackup.pde: In function 'void loop()':
EEPROMBackup:77: error: 'timeBackup' was not declared in this scope
EEPROMBackup:77: error: 'now' was not declared in this scope
EEPROMBackup:78: error: 'digitalClockDisplay' was not declared in this scope
EEPROMBackup.pde: At global scope:
EEPROMBackup:82: error: variable or field 'digitalClockDisplay' declared void
EEPROMBackup:82: error: 'time_t' was not declared in this scope
(of course i checked for the typo)
Thankx for your help.
April 1, 2013 at 2:59 PM
Sorry, my mistake, the timebackup should not have been included, it is part of an ongoing project. Please ignore this file
April 18, 2013 at 12:57 PM
You rock dude! Your library worked great for me and saved me hours of work. Thanks!
April 21, 2013 at 8:36 AM
Hey, that’s great to hear. Thanks!
April 28, 2013 at 7:01 PM
Hi Thijs,
I went through the examples and looks it ll make my work much simple.
I have a very requirement of the very first comment, Will this work for multi dimensional array?
Timer[nth timer][on time, off time]
struct Timer_group {
int hr_start[8];
int sc_start[8];
int hr_end[8];
int sc_end[8];
};
Timer_group timer[40];
May 23, 2013 at 8:49 AM
Sorry, I have not added support for multi-dimensional arrays. Your second example will probably work, though. If SizeOf(Timer_Group) gives you back the correct size (4*8*sizeOf(int)) it will work fine.
June 5, 2013 at 8:30 PM
Thanks Thijs.
I went on tried that way, when I use two structures it doesnt seem to work as I expected. Please can you help debug?
#include
int addresskeyvalue = 0, addressnamejob=0, address=0;
struct pair1 {
int key;
int value;
};
pair1 keyValueInput[2], keyValueInputx[2];
struct triplet1 {
int name;
int job;
int comp;
};
triplet1 namejobInput[2], namejobInputx[2];
void setup()
{
int i;
Serial.begin(9600);
EEPROM.setMaxAllowedWrites(100);
for(i=0;i<2;i++)
{
keyValueInput[i].key =i;
keyValueInput[i].value=i+10;
namejobInput[i].name=i+20;
namejobInput[i].job=i+30;
namejobInput[i].comp=i+40;
}
for(i=0;i<2;i++)
{
Serial.print(keyValueInput[i].key);
Serial.print("\t");
Serial.print(keyValueInput[i].value);
Serial.print("\t");
Serial.print(namejobInput[i].name);
Serial.print("\t");
Serial.print(namejobInput[i].job);
Serial.print("\t");
Serial.print(namejobInput[i].comp);
Serial.println("");
}
Serial.println("after");
Serial.println("");
Serial.print(address);
Serial.print("\t");
EEPROM.updateBlock(address, keyValueInput,2);
Serial.print(address);
EEPROM.updateBlock(address, namejobInput,3);
Serial.print("\t");
Serial.print(address);
Serial.println("");
EEPROM.readBlock(address, keyValueInputx,2);
EEPROM.readBlock(address, namejobInputx,3);
for(i=0;i<2;i++)
{
Serial.print(keyValueInputx[i].key);
Serial.print("\t");
Serial.print(keyValueInputx[i].value);
Serial.print("\t");
Serial.print(namejobInputx[i].name);
Serial.print("\t");
Serial.print(namejobInputx[i].job);
Serial.print("\t");
Serial.print(namejobInputx[i].comp);
Serial.println("");
}
}
void loop() { }
June 6, 2013 at 9:08 PM
hi.thanks for library.can we use this library with i2c eeprom? thanks
June 15, 2013 at 2:39 PM
Hi,
I am working on a library that allows writing to different backends. Unfortunately, I do not have a i2C eeprom. How good are your programming skills? Maybe you can debug a first draft?
June 12, 2013 at 6:22 PM
I think I got the hang now, not sure if its intended way. Adding these lines for “address” makes it work as needed
EEPROM.updateBlock(address, keyValueInput,2);
address=sizeof(keyValueInput);
Serial.print(address);
EEPROM.updateBlock(address, namejobInput,3);
Serial.print(“\t”);
Serial.print(address);
Serial.println(“”);
address=0;
EEPROM.readBlock(address, keyValueInputx,2);
address=sizeof(keyValueInput);
EEPROM.readBlock(address, namejobInputx,3);
June 25, 2013 at 1:18 PM
Hi!
Found an error causing exceeding write limit and messages during “readBlock” operations – it because “isWriteOk” check used instead of “isReadOk” in “readBlock” function (template).
Also I’ve got write limit exceeding messages when I’m writing (updating) 8 byte x 8 array by “EEPROM.updateBlock( EEPROMaddr.a_Sensors + ((settingNum-1)*8), pDeviceAddress + ((_tempID-1)*8), 8);” with limit of 100 write cycles… not sure why.
To wish list – count only real write cycles in “update” functions.
April 7, 2014 at 9:45 PM
Ah, thanks! I will fix this!
August 6, 2013 at 8:04 PM
Hi Thuis,
Great work! I like your library but I have one question about storing char * in EEPROM.
I have a struct:
struct Instellingen {
unsigned int controllerID;
long timedLoopInterval;
long maintenanceLoopInterval;
int timeSyncInterval;
long timeZoneOffset;
char *NTPPool;
char *controllerCredentials;
};
The 2 char* fields may hold varying legths of character strings. The lengths for these fields are not known in advance.
I would like to:
int addressInstellingen;
Instellingen instellingen;
addressInstellingen = EEPROM.getAddress(sizeof(Instellingen));
EEPROM.writeBlock(addressInstellingen, instellingen);
and
EEPROM.readBlock(addressInstellingen, instellingen);
and
EEPROM.updateBlock(addressInstellingen, instellingen);
How do I have to deal with the varying lengths of the 2 char* fields in this struct?
With regards,
Jack.
April 7, 2014 at 10:10 AM
Hi,
The getAddress function is not really suitable for dynamic arrays. One of the prerequisites is that after each reboot the same adresses are calculated for the same variables. In case of dynamic variables you need to make your own implementation (and perhaps store length in the EEPROM as a header to the array.
Also, the struct that you describe does not actually contain the array, only a pointer to the array (which is fixed size). Not efficient, but the easiest way to go about this is to define a fixed array that is always large enough.
In fact, many people consider dynamic memory allocation on an embedded processor a Bad Idea, see for example this discussion: http://stackoverflow.com/questions/1725923/how-bad-is-it-to-use-dynamic-datastuctures-on-an-embedded-system
August 27, 2013 at 8:45 AM
There is a small mistake in updateBit: should use bitwise NOT (~) instead of logical NOT (!)
April 7, 2014 at 9:36 AM
Thanks! I have fixed this!
September 5, 2013 at 12:11 AM
Dear Thijs,
I downloaded the latest Code release for EEPROMex from the GitHub Repository. Within the files there is a sketch example of EEPROMVar. However, I cannot get it to compile on Arduino IDE 1.0.5. I allways get the following error message:
In file included from EEPROMVar.pde:10:
C:\Program Files\Arduino\libraries\EEPROMex/EEPROMVar.h: In constructor ‘EEPROMVar::EEPROMVar(T)’:
C:\Program Files\Arduino\libraries\EEPROMex/EEPROMVar.h:34: error: ‘class EEPROMClassEx’ has no member named ‘getAdress’
Do you have any suggestions why that is? I´m clueless.
THX so much,
Jan
April 7, 2014 at 10:27 AM
Dear Jan,
It was a bug but has been fixed now.
Thijs
September 18, 2013 at 2:44 PM
Hi,
Thanks for your work,
I am only saving 1 float to EEPROM. I only am able to access 512 on the nano with the mega 328. Using the standard library I am able to access all 1024 bytes on the same board.
Thanks for any help.
Miles
September 18, 2013 at 2:57 PM
Sorry, I missed the setmempool. All is god now.
Thanks
September 21, 2013 at 11:14 PM
if you want to work with arrays then you can use templates:
template
inline bool blImage5::Wrap(blDataType (&StaticArray)[Size1][Size2])
{
// Do stuff with the
// array elements
for(int i = 0; i < Size1; ++i)
{
for(int j = 0; j < Size2; ++j)
{
}
}
}
October 5, 2013 at 10:51 PM
Hello!
when i wrote with eepromex.h:
EEPROM.writeFloat((600),55);
the Memory 600 is empty
when i wrote with eeprom.h:
EEPROM.write((600),55);
the Memory 600 has the Value 55.
What i do false?
Board ist Arduino Mega 2560
Thank you for help and sorry for the English…
October 6, 2013 at 12:40 AM
Found my fault:
Adding:
EEPROM.setMemPool(0, EEPROMSizeMega);
to the Setup and now works 🙂
Bye
October 11, 2013 at 11:56 AM
I want to store some Boolean value .
First question :
If I store them as Struct and then use writeBlock it will know that is Boolean and stores is as Bit’s in a byte?
[code]
struct StoreSettings{
boolean statusIDs[2];
} storage = {
{false,false}
};
[/code]
Second Question:
If I use writeBit(int address, uint8_t bit, bool value) and I write 7 Boolean values on a byte , what is the EEPROM wear ? it only wears that bit or it’s for the entire byte.
April 6, 2014 at 8:55 PM
1) Yes-ish. That is to say, writeBlock does not know of the internal structure of the struct, but only the bytes it uses in memory. These bytes are then copied to the EEPROM. Even if your struct uses only bitfields, the data is padded to a byte.
2) I looked at the datasheets and the avr library when I wrote the library. There is no way of addressing individual bits, only bytes. It could be that the ATMega does something smart internally, but I do not believe so. There is nothing to indicate this in the datasheets
Pingback: Drawing with a laser | Leaping into the future
December 20, 2013 at 5:38 PM
1) is it neccessary to do
EEPROM.setMemPool(memBase, EEPROMSizeUno);
EEPROM.setMaxAllowedWrites(maxAllowedWrites);
only in the setup() or also in the loop()?
2) I am using the EEPROMex library to store RFIDs in the EEPROM. The sketch is
used for an RFID Access Control. It adds RFIDs to the EEPROM that have access right,
all other RFIDs read by the card reader that are not stored in EEPROM are denied access.
It is also possible to remove RFIDs from EEPROM if their previously granted access is revoked.
I do not use your EEPROM.getAddress, I do my own memory address maintenance because I want
to reuse memory space freed up from deleted RFIDs.
My question is: if I put “setMaxAllowedWrites” into the loop() does the maximum writes refer
to each single loop run? In this case it would protect the EEPROM from being written too many
times in one single loop() but it would allow to write to the EEPROM an infinite number of times
(till EEPROM damaged) by rerunning the loop(); right?
This would allow my sketch to add and delete RFIDs to the EEPROM until the EEPROM is damaged.
Or shout I use these functions only for debugging?
April 6, 2014 at 2:09 PM
1) Only once, in the setup
2) Indeed, the
SetMaxAllowedWrites
is a global value that sets the number of writes anywhere. It is compared to a counter that starts running when your sketch starts running. Setting it multiple times will not reset the counter (which is actually not a bad idea!). It was meant only for the debugging stage of your program.January 3, 2014 at 1:36 AM
Hi,
Is it possible to set max allowed writes to unlimited?
January 27, 2014 at 10:18 PM
Hi,
What you probably want is to disable the debugging option: comment out
_EEPROMex_DEBUG
inEEPROMex.cpp
. Out of interest, what are you using the library for?January 10, 2014 at 11:34 PM
Hi,
thanks for coding EEPROMex and EEPROMvar! They should be included in the standard library of Arduino.
I wanted to use a global variable of type EEPROMvar, but could not figure out a way to call setMemBase to change the base address. That is why I have modified EEPROMvar.h to also define an empty constructor. With this addition, it it possible to declare global variables, call setMemBase, and then instantiate the variable. (Actually the declaration is an instantiation, but because Arduino does not want to use new, a pure declaration of a class object is not possible).
Below is the modified version of EEPROMvar.h and also an example. Please let me know if there is an easier way to get global variables of type EEPROMvar.
Maybe the modification find their way into future releases of the EEPROMvar library.
Modified version of EEPROMvar:
[code]
#include
/*
EEPROMvar.h – EEPROM variable library
Copyright (c) 2012 Thijs Elenbaas. All right reserved.
based on class by AlphaBeta
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _EEPROMVAR_DEBUG // Enables logging of not-instantiated error
template class EEPROMVar
{
public:
EEPROMVar(T init) {
address = EEPROM.getAddress(sizeof(T));
var = init;
}
// Define an empty constructor so that it is possible to declare variables
// but without actually instantiating an object (sort of). Required when global
// variables of type EEPROMvar are desired, but setMemPool should be called
// prior to instantiation. Without this empty constructor, only pointers can be
// used, which is sort of not so nice style.
EEPROMVar() {
address = -1;
var = 0;
}
operator T () {
return var;
}
EEPROMVar &operator=(T val) {
var = val;
return *this;
}
void operator+=(T val) {
var += T(val);
}
void operator-=(T val) {
var -= T(val);
}
void operator++(int) {
var += T(1);
}
void operator–(int) {
var -= T(1);
}
void operator++() {
var += T(1);
}
void operator–() {
var -= T(1);
}
template
void operator /= (V divisor) {
var = var / divisor;
}
template
void operator *= (V multiplicator) {
var = var * multiplicator;
}
void save(){
// check if variable was instantiated (by calling EEPROMvar<T::EEPROMvar(T)
// or simply declared (by calling EEPROMvar::EEPROMvar()
#ifdef _EEPROMVAR_DEBUG
if (address == -1) {
Serial.println(“Attempt to access EEPROMvar variable without calling EEPROMvar::EEPROMvar(T)”);
}
#endif
EEPROM.writeBlock(address, var);
}
void update(){
// check if variable was instantiated (by calling EEPROMvar<T::EEPROMvar(T)
// or simply declared (by calling EEPROMvar::EEPROMvar()
#ifdef _EEPROMVAR_DEBUG
if (address == -1) {
Serial.println(“Attempt to access EEPROMvar variable without calling EEPROMvar::EEPROMvar(T)”);
}
#endif
EEPROM.updateBlock(address, var);
}
int getAddress(){
return address;
}
void restore(){
// check if variable was instantiated (by calling EEPROMvar<T::EEPROMvar(T)
// or simply declared (by calling EEPROMvar::EEPROMvar()
#ifdef _EEPROMVAR_DEBUG
if (address == -1) {
Serial.println(“Attempt to access EEPROMvar variable without calling EEPROMvar::EEPROMvar(T)”);
}
#endif
EEPROM.readBlock(address, var);
}
protected:
T var;
int address;
};
[/code]
An example for the Arduino Uno:
[code]
#include
#include
#define CONFIG_VERSION 1 // Version number of the settings block, must not be 0
// Declare global variables. In my humble opinion Arduino implements handling of classes
// in a non-intuitive way, because the below lines actually call the constructor of the class,
// while I would expect that only spcae for a variable is reserved that will later become the
// object when instantiated. It would be nice if Arduino would force to use the new keyword
// then the declaration below would not call the constructor.
EEPROMVar ConfigVersion;
EEPROMVar Counter;
// when the EEPROMvar.h is not modified, this approach could be used, but then one has to use
// the -> operator instead of . when accessing the methods, e.g. pCounter->getAddress()
//EEPROMVar* pConfigVersion;
//EEPROMVar* pCounter;
void setup() {
Serial.begin(19200); // set Baud rate
Serial.println();
Serial.println(“— testing EEPROMvar”);
// enable an upper limit of writes during developmant
EEPROM.setMaxAllowedWrites(100);
// set address range
EEPROM.setMemPool(100, EEPROMSizeUno);
// load configuration from EEPROM
LoadConfig();
}
void LoadConfig() {
// actual instantiation of the global variables
// also defines the default values when the CONFIG_VERSION is changed
// This (to me) looks also strange, because the new keyword is missing. This non-standard
// way of using the C++ language teaches people the wrong thinking and should be corrected.
ConfigVersion = EEPROMVar(0);
Counter = EEPROMVar(0);
//pConfigVersion = new EEPROMVar(0);
// get config version from EEPROM
ConfigVersion.restore();
Serial.print(“defined ConfigVersion= “);Serial.println(CONFIG_VERSION);
Serial.print(“restored ConfigVersion= “);Serial.print(ConfigVersion);
Serial.print(” @ address “); Serial.println(ConfigVersion.getAddress());
//Serial.print(“restored pConfigVersion= “);Serial.print(*pConfigVersion);
//Serial.print(” @ address “); Serial.println(pConfigVersion->getAddress());
// check if it’s up to date
if (ConfigVersion == CONFIG_VERSION) {
// yes, so restore the values
Counter.restore();
Serial.println(“config loaded”);
} else {
// no, so write them to EEPROM (default values are set above in the instantiation)
Counter.save();
ConfigVersion = CONFIG_VERSION;
ConfigVersion.save();
// Interestingly, this never shows up in Terminal unless I add a delay in Setup(),
// yet the variables are updated in the EEPROM. When uploading to the arduino,
// for some reason the setup() get’s called twice.
Serial.println(“wrinting default config”);
}
Serial.print(“Counter= “); Serial.println(Counter);
Serial.println(“will add 1 to the counter and save changes to EEPROM.”);
Counter++;
Counter.update();
}
void loop() {
}
[/code]
April 7, 2014 at 9:37 PM
Very interesting! I will look into incorporating this when I package a new version of EEPROMEx. Thanks!
February 26, 2014 at 6:30 PM
Werkt zonder problemen en zeer gemakkelijk in gebruik! Een heel dikke merci, net wat ik nodig had!
March 30, 2014 at 5:44 AM
Hi Thijs, great library!
It worked flawlessly for me on an Arduino Uno. However, I tried to initialize EEPROM data on a Sparkfun Pro Micro 5V (ATMega 32U4) and I think that caused it to brick (but I’m not entirely sure what the issue is, to be honest).
Are you aware of any incompatibilities between EEPROMex and the ATMega 32U4?
Thanks!
March 30, 2014 at 7:51 PM
Hi Thijs! Love the library, it worked flawlessly on my Arduino Uno!
However, I bricked by Sparkfun Pro Micro 5V (running ATmega 32U4 processor) and I think, although I am not 100% sure, that the cause was the use of this library.
I’ve managed to reset the bootloader and un-brick the board, but I am wary of trying again. Are you aware of any incompatibility between EEPROMex and ATmega 32U4 chips?
Thanks!
April 4, 2014 at 11:19 PM
Hi Dave,
Really!?! I’m sorry to hear this. I had not heard of something similar before. I searched on the internet, but I could not find cases of bricked ATmega chips, by EEPROM access. The library was specifically designed to prevent the one way I know how to ruin the EEPROM, and that is by writing > 100.000 times per cell. This is not to say that you are wrong.
Do you have a way of pinpointing the issue? That is, separate the EEPROM code from the main program and see if the EEPROM code alone bricks it, or inversely, the other code does not brick it?
Good luck! Thijs
April 6, 2014 at 7:32 PM
Hi Thijs – thanks for your response, and I’m sorry to have wasted your time! After getting up my courage, I ran my sketch to initialize EEPROM addresses, and it worked just fine. So your library is definitely not the culprit!
Likely the simplest explanation is that I goofed up and uploaded code to the Pro Micro using an incorrect device selection, even though typically I was very careful to select the right one as that is a known cause of bricking.
Thanks again, both for your response and the great library!
April 1, 2014 at 8:25 PM
This is a sample of my code, just the eeprom write and read event handler is included.
I am not getting a read or write indication on the LED Displays.
Running the Arduino Uno with a 4D LCD display (uLCD-43-PT.
#include
#include
#include
int mem_write=0;
int mem_read=0;
int address=0;
//I skipped the in-between code.
//In my Event Handler, this follows;
//The long variable that I am trying to store in EEPROM is as an example, freq=7123456
//————————–Memory Write————————————–
if (Event.reportObject.object == GENIE_OBJ_WINBUTTON)
{
if (Event.reportObject.index == 4)
{
mem_write=genieGetEventData(&Event);
if (mem_write==1) //WINBUTTON 4 has been pressed
{
address=0; //The Write Button, Index=4
EEPROM.writeLong(address, freq);
}
}
}
//————————–Memory Read————————————–
if (Event.reportObject.object == GENIE_OBJ_WINBUTTON)
{
if (Event.reportObject.index == 6) //The Read Button, Index=6
{
mem_read=genieGetEventData(&Event);
if (mem_read==1) //WINDBUTTON 6 has been pressed {
address=0;
freq=EEPROM.readLong(address);
freq_low=(freq%10000L); //Display long freq from EEPROM
freq_high=(freq-freq_low)/10000L; //Must break freq into two parts, 2 x 4 digit LED Displays
genieWriteObject(GENIE_OBJ_LED_DIGITS, 0x01, freq_high);
genieWriteObject(GENIE_OBJ_LED_DIGITS, 0x00, freq_low);
}
}
}
April 4, 2014 at 11:07 PM
Hi Lee,
I must admit I do not immediately see the issue. Have you tried storing the frequency in just in memory, to see if the EEPROM calls are the actual issue? If this works, I would push the frequency values to the terminal, to see if they give expected values
Good luck!
April 10, 2014 at 8:00 PM
Just a small note, I don’t know if it is just me, but keywords.txt only works if you have a single tab between keyword and color, and you have multiple tabs on some keywords.
I removed the extra tabs, and now all the keywords show correctly on the Arduino IDE (1.5.5-r2).
May 9, 2014 at 6:32 PM
Indeed I did not know that! I will have a look at all libraries. Thanks.
May 9, 2014 at 7:45 PM
Oh, I forgot to say, thanks for doing this, it has been really useful to me.
Pingback: Mini linetracer | the power of dreams
April 26, 2014 at 6:44 PM
Greetings! This is a beautifully written and designed library. I’m a coder of 30 years, and don’t see this level of work often in the Arduino world. KUDOS!
=Alan R.
May 9, 2014 at 6:28 PM
Hey, that is big praise! Thanks! I think this is partly because the Arduino community attracts people with lots of different background, and only a small part have significant code developer skills. However, the diversity makes for a very vibrant community with lots of cool projects. If my libraries can play a part in that, all the better 🙂
May 17, 2014 at 7:48 AM
Hi
I found your code yesterday because I was looking for a way to write a float value to eeprom table. That worked right off so I thought I was off and running.
Tonight I was writing a fairly large table to eeprom. (A table of x10 commands) Actually was reading EEPROM when I got the message.
Anyhow, I got the following message when the eeprom address went above 512.
“Attempt to write outside of EEPROM memory”
I found the following in line EEPROMex.cpp file .
int EEPROMClassEx::_memSize= 512;
changed 512 to 4096 and error message went away. I have not tested further to see if write/read works in addresses above 512 but the error message did go away so I am assuming it will work.
This library will make it much easier to store some of the things I want to save in EEPROM.
By the way. The ardunio I am using is Mega 2560. Is this a proper fix? Is the library supposed to adjust automatically to the processor being used?
Thanks…
Mike
July 1, 2014 at 11:00 AM
Hi Mike,
Great that you like the library. There is no way (that I could find) to automatically identify your processor, so you have to set it yourself. What it does is allows the library to know the size of your EEPROM, so setting the correct board would help you solve your “Attempt to write outside of EEPROM memory” message.
May 22, 2014 at 7:15 AM
Hi Thijs
Awesome library – very useful for the world!
Do you know yet if anyone has had any success in adapting your library for use with I2C external EEPROM (such as 24LC256 chip ) ?
July 1, 2014 at 11:06 AM
Hey, thanks! I have a half-way finished implementation, but I have many other projects I would like to finish, too, so it may take a while
May 30, 2014 at 11:30 PM
just what i was looking for, thank you very much mate!
July 1, 2014 at 10:47 AM
Thanks!
June 5, 2014 at 8:46 PM
Hallo Thijs
Ik heb een probleempje waar ik niet uit komt tijdens het wegschrijven van een long variable gaat dit willekeurig fout na een paar keer nu heb ik mijn programma helemaal gewist en alleen de eeprom gedeelte behouden maar het probleem blijft . Kan en wil jij even kijken naar mijn programma..
Bedankt
/*
SERIAL uitlezing
eeprom goed :35263
eeprom goed :42463
eeprom goed :49663
eeprom goed :56863
eeprom goed :64063
eeprom fout :71263 hier gaat hij dus in de fout
eeprom fout :78463
eeprom fout :85663
eeprom fout :92863
*/
#include
const int maxAllowedWrites = 20; // eeprom
const int memBase = 140; // eeprom
long uvlamp_sec;
int uvlamp_timer = 0;
int addressInt_uvlamp;
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
delay(100);
EEPROM.setMemPool(memBase, EEPROMSizeUno);
EEPROM.setMaxAllowedWrites(maxAllowedWrites);
//—– adressen toekennen aan de eeprom variable. ——
addressInt_uvlamp = EEPROM.getAddress(sizeof(long));
uvlamp_timer=0;
uvlamp_sec = 0;
if (EEPROM.readInt(addressInt_uvlamp) < 1) { // wegschrijven data naar eeprom
EEPROM.writeInt(addressInt_uvlamp,uvlamp_sec);
}
else { // lezen data van eeprom
uvlamp_sec=EEPROM.readInt(addressInt_uvlamp);
}
}
// the loop routine runs over and over again forever:
void loop() {
timerteller();
delay(1);
}
void timerteller()
{
// uv lamp teller
// Serial.println("UV1");
uvlamp_sec +=1;
uvlamp_timer +=1;
if (uvlamp_timer == 7200){ // om de hoeveel tijd de data word weggeschreven naar de eeprom
uvlamp_timer = 0;
while (!eeprom_is_ready());
cli();
EEPROM.writeInt(addressInt_uvlamp,uvlamp_sec);
sei();
if (EEPROM.readInt(addressInt_uvlamp) == uvlamp_sec) {
Serial.print("eeprom goed :");
}
else
{
Serial.print("eeprom fout :");
}
Serial.println(uvlamp_sec);
}
}
June 8, 2014 at 10:48 AM
Hi Thijs,
thank you for sharing such a great library. I am using it as part of a intelligent lighting system to remember the last settings in case of a power cut or user input cause of changing conditions. Most of the variables are just stating conditions 0, 1, or 2 which are declared as byte anyway. Now I have a few variables they could be anything between 0 and 1023 which is in the rest of the program declared as int. Now it might be a silly question but since it is the first time I am working with EEPROM usage, do I write this variables as int anyway even the value might be something between 0 and 255 or do I have to check the value first and than write it as byte or int accordingly?
July 1, 2014 at 10:43 AM
Hi Dieter,
I would just keep it simple and write to EEPROM in the same format as is used in your program, so as an int. Good luck!
June 12, 2014 at 9:52 PM
I have a problem with part of my program.
maybe someone knows why he stops writing the data to the EEPROM.
/*
SERIAL output
eeprom goed :35263
eeprom goed :42463
eeprom goed :49663
eeprom goed :56863
eeprom goed :64063
eeprom fout :71263 <- this is not good
eeprom fout :78463
eeprom fout :85663
eeprom fout :92863
*/
#include
const int maxAllowedWrites = 20; // eeprom
const int memBase = 140; // eeprom
long uvlamp_sec;
int uvlamp_timer = 0;
int addressInt_uvlamp;
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
delay(100);
EEPROM.setMemPool(memBase, EEPROMSizeUno);
EEPROM.setMaxAllowedWrites(maxAllowedWrites);
//—– adressen toekennen aan de eeprom variable. ——
addressInt_uvlamp = EEPROM.getAddress(sizeof(long));
uvlamp_timer=0;
uvlamp_sec = 0;
if (EEPROM.readInt(addressInt_uvlamp) < 1) { // wegschrijven data naar eeprom
EEPROM.writeInt(addressInt_uvlamp,uvlamp_sec);
}
else { // lezen data van eeprom
uvlamp_sec=EEPROM.readInt(addressInt_uvlamp);
}
}
// the loop routine runs over and over again forever:
void loop() {
timerteller();
delay(1);
}
void timerteller()
{
// uv lamp teller
// Serial.println("UV1");
uvlamp_sec +=1;
uvlamp_timer +=1;
if (uvlamp_timer == 7200){ // om de hoeveel tijd de data word weggeschreven naar de eeprom
uvlamp_timer = 0;
while (!eeprom_is_ready());
cli();
EEPROM.writeInt(addressInt_uvlamp,uvlamp_sec);
sei();
if (EEPROM.readInt(addressInt_uvlamp) == uvlamp_sec) {
Serial.print("eeprom goed :");
}
else
{
Serial.print("eeprom fout :");
}
Serial.println(uvlamp_sec);
}
}
July 1, 2014 at 10:39 AM
Does the application stop, or is it giving the wrong values? Also, what kind of board are you using? Some things I notice:
1. you allocate 4 bytes for a long:
EEPROM.getAddress(sizeof(long));
, but are using an int, which on a Arduino Uno amounts to 2 bytes.2. You do not need
while (!eeprom_is_ready());
. The EEPROM write will block anyway until the EEPROM is ready.Although, I do not believe that this is your problem. If you are using an ARM processor, I think I would understand, so let me know.
July 1, 2014 at 11:35 PM
I have tested it with the uno and the mini pro.
and I got both at the same mistakes after a while.
but if you test the sketch you get the same errors I think.
Thanks for any help
June 18, 2014 at 6:10 AM
Thanks for developing this library! It’s exactly what I’ve been searching for.
I have been having trouble getting the first example “EEPROMex” to work on Arduino 1.0.5. It doesn’t compile and throw’s the follow error:
EEPROMEx.cpp.o: In function
eeprom_write_block':
__eewr_block’c:/program files (x86)/arduino erw 1.0.5/hardware/tools/avr/lib/gcc/../../avr/include/avr/eeprom.h:403: undefined reference to
(windows 7, 64 bit, arduino 1.0.5 enhanced release)
But it works fine on Arduino 1.0 though, so I’m just going to use that.
Thanks Again,
Ben
July 1, 2014 at 10:40 AM
Thanks! I will have a look at that when I have time
June 24, 2014 at 2:37 AM
Hi! I am trying to implement the library but I don’t understand something.
On setup() y declare de following address:
drumSequenceAddress = EEPROM.getAddress(sizeof(byte))*drumTotal;
drumDecayAddress = EEPROM.getAddress(sizeof(byte))*drumTotal;
drumFreqDecayRateAddress = EEPROM.getAddress(sizeof(byte))*drumTotal;
drumInitVolAddress = EEPROM.getAddress(sizeof(byte))*drumTotal;
drumInitFreqAddress = EEPROM.getAddress(sizeof(word))*drumTotal;
drumInitNoiseFreqAddress = EEPROM.getAddress(sizeof(byte))*drumTotal;
drumNoiseDecayRateAddress = EEPROM.getAddress(sizeof(byte))*drumTotal;
lastStepAddress = EEPROM.getAddress(sizeof(byte));
bpmAddress = EEPROM.getAddress(sizeof(word));
But when I do a Serial.println() of each one:
Serial.println(drumSequenceAddress);
Serial.println(drumDecayAddress);
Serial.println(drumFreqDecayRateAddress);
Serial.println(drumInitVolAddress);
Serial.println(drumInitFreqAddress);
Serial.println(drumInitNoiseFreqAddress);
Serial.println(drumNoiseDecayRateAddress);
Serial.println(lastStepAddress);
Serial.println(bpmAddress);
I get the following:
0
40
45
50
55
65
70
15
16
It seems fine until the last two address. Is there something wrong?
Thanks!
July 1, 2014 at 11:08 AM
The problem is that the EEPROM library does not know that it needs to allocate for an array.
Replace
EEPROM.getAddress(sizeof(byte))*drumTotal;
by
EEPROM.getAddress(sizeof(byte*drumTotal));
and same for other types and you’ll be fine
July 5, 2014 at 12:32 AM
Almost 🙂
that gives error, but replacing it by:
EEPROM.getAddress(sizeof(byte)*drumTotal); works perfect!
Thanks!! Great library!