EEMEM

Hi guys,
can somebody point me to a reasource which clearly explains the EEMEM usage?

I'm getting really confused as I intended to move away from the EEPROM clas and it's limitations but I find difficult to find resources and documentation of the EEMEM directive.

What I want to do is store some per device configuration parameters (like RF24 address and so forth) and get rid of the long and error prone code currently written using the EEPROM class.

Thanks

The EEPROM memory inside the ATmega microcontroller is sometimes called EEMEM. It is the same.

You can use the EEPROM class: http://arduino.cc/en/Reference/EEPROM
Or use the avr-gcc functions directly: avr-libc: <avr/eeprom.h>: EEPROM handling
For example the eeprom_read_block and eeprom_write_block.
Perhaps you can use the 'anything' : Arduino Playground - EEPROMWriteAnything

Ok, probably my question wasn't put in the right way. What I'm talking about is the EEMEM attribute defined in avr/eeprom.h and it's practical usage.

I've seen examples using structures on this same forum, but they don't seem to work so I tried to use it with a simple uint16_t, without success.

I'm looking for a way to store parameters, including a couple of uint64_t plus some other uint16_t and int32_t. I want to be able to both control their initial default values and change them when needed. I've succeeded with the EEPROM class and the functions in ave/eeprom.h, but I'm now investigating EEMEM to further simplify the code and reduce SRAM consumption

That is this : avr-libc: <avr/eeprom.h>: EEPROM handling

So you don't want to use the eeprom_read_block, but use the EEMEM to directly read an item of a structure that is defined in EEPROM.

That has been a while ago for me. I can look up the code for you, but its on my other computer. I think was a pointer and the EEMEM keyword.
Or try searching at www.avrfreaks.net

The next example shows how to use EEMEM.
Since the actual position of the data in EEPROM is not known, almost no one uses it.
I think it is better to use the eeprom functions with fixed offsets for the data in EEPROM.

// Use of EEMEM
// Arduino IDE 1.5.8.
// Uno board
//
// A EEMEM structure or EEMEM variable is not located somewhere.
// The compiler uses it only to calculate offsets.
// When more EEMEM variables are used, the order is defined
// by the compiler.
// With a new compiler, that order in EEPROM might change.

// a definition of the data in EEPROM
struct myEEdata_struct {
  int16_t myint;
  uint16_t myword;
  int32_t mylong;
  char myText[10];
};

// Tell the compiler that the data is in EEPROM
// It is not possible to set initial values.
// This struct is only used for offset in EEPROM.
myEEdata_struct EEMEM myEEdata;

// Another EEMEM variable.
uint32_t EEMEM myEEsec;

// Global variable to keep track of total time.
unsigned long totalSec;

void setup() {
  Serial.begin(9600);
  Serial.println(F("\n---------"));
  Serial.println(F("Start"));

  // write it
  // The function wants a pointer to an unsigned integer, so a cast is needed.
  eeprom_write_word( (uint16_t *) &myEEdata.myint, 15);
  
  // read it
  uint16_t i = eeprom_read_word( (uint16_t *) &myEEdata.myint);
  Serial.print(F("myEEdata.myint="));
  Serial.println(i);

  // Reset the time, uncomment it and run it once.
  // eeprom_write_dword(&myEEsec, 0UL);

  // Read value of the last time
  totalSec = eeprom_read_dword(&myEEsec);
}

void loop() {
  // use the variable to keep track of time.
  totalSec++;
  Serial.print(F("time="));
  Serial.println(totalSec);
  
  // Remember the current time by storing it in EEPROM
  eeprom_write_dword(&myEEsec, totalSec);
  
  // do loop once a second
  delay(1000);
}

Peter_n:

// A EEMEM structure or EEMEM variable is not located somewhere.

...which makes it quite memory efficient. We haven't yet figured how much data can be stored in the modestly sized EEPROM of the typical microcontroller, but current research indicates it to be well in excess of the yottabyte region :wink:

Seriously, while there may be instances where one needs to know the address of data in EEPROM, often it is no more necessary than it is to know the address of a variable in SRAM. Here is a simple example using <avr/eeprom.h>.

Thanks everybody: I'll come back after an appropriate reading of the posted links. :grin:

Ok, so EEMEM does not define a variable, it is used by the compiler to infer an EEPROM address and it's type is used to understand the number of bytes it has to reserve to store one of those.

Whatever I put beside EEMEM is not going to occupy memory itself, but to access its value I'll need to declare another variable of the same type without the EEMEM directive: when I read from EEPROM I can use &eememVarName as EEPROM address and the data size is left to me: I should use a eeprom_read_byte for int8_t and uint8_t, eeprom_read_word for int16_t and uint16_t, eeprom_read_dword for int32_t and uint32_t, two calls to eeprom_read_dword and some bit shifting for int64_t and uint64_t, and so forth.

Now, while I see a big advantage in not being limited to read/write one byte at time (which is not strictly related to EEMEM directive usage), I also see the advantage of not being forced to define EEPROM locations upfront: this should somewhat simplify using EEPROM storage in libraries as you automatically avoid conflicts (all the address are computed at compile time): I like it!

Now I need a way to provide defaults so I can flash EEPROM value alongside the firmware. My favorite development environment id Arduino Eclipse, which in turns uses the Arduino toolchain.

How can I prepare an EEPROM file containing the values I want to put into EEPROM using the compiler generated addresses?

in case you are not familiar with Arduino Eclipse, this is the output I get when building a firmware containing an EEMEM directive:

make all 
Building file: ../herba.cpp
Starting C++ compile
"R:/Tools/ArduinoIDE/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=155-r2 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR    -I"R:\Tools\ArduinoIDE\hardware\arduino\avr\cores\arduino" -I"R:\Tools\ArduinoIDE\hardware\arduino\avr\variants\eightanaloginputs" -I"R:\Projects\viridi-nexu\common" -I"R:\Arduino\libraries\RF24" -I"R:\Arduino\libraries\LowPower" -I"R:\Tools\ArduinoIDE\libraries\SPI" -I"R:\Tools\ArduinoIDE\libraries\EEPROM" -I"R:\Arduino\libraries\VoltageReference" -I"R:\Arduino\libraries\OneWire" -I"R:\Arduino\libraries\MicroDebug" -MMD -MP -MF"herba.cpp.d" -MT"herba.cpp.d" -D__IN_ECLIPSE__=1 -x c++ "../herba.cpp"  -o  "herba.cpp.o"
Finished building: ../herba.cpp
 
Starting combiner
"R:/Tools/ArduinoIDE/hardware/tools/avr/bin/avr-gcc" -Os -Wl,--gc-sections -mmcu=atmega328p -o "R:/Projects/viridi-nexu/herba/Release/herba.elf"    ./herba.cpp.o  ./common/RF24Address.cpp.o  ./Libraries/VoltageReference/VoltageReference.cpp.o  ./Libraries/SPI/SPI.cpp.o  ./Libraries/RF24/RF24.cpp.o  ./Libraries/OneWire/OneWire.cpp.o  ./Libraries/LowPower/LowPower.cpp.o  ./Libraries/EEPROM/EEPROM.cpp.o  ./Libraries/Battery/Battery.cpp.o   R:/Projects/viridi-nexu/herba/Release/arduino.ar   "R:/Projects/viridi-nexu/herba/Release/arduino.ar" "-LR:/Projects/viridi-nexu/herba/Release" -lm
Finished building: herba.elf
 
Create eeprom image
"R:/Tools/ArduinoIDE/hardware/tools/avr/bin/avr-objcopy" -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 "R:/Projects/viridi-nexu/herba/Release/herba.elf" "R:/Projects/viridi-nexu/herba/Release/herba.eep"
Finished building: herba.eep
 
Create Flash image (ihex format)
"R:/Tools/ArduinoIDE/hardware/tools/avr/bin/avr-objcopy" -O ihex -R .eeprom "R:/Projects/viridi-nexu/herba/Release/herba.elf" "R:/Projects/viridi-nexu/herba/Release/herba.hex"
Finished building: herba.hex
 
Building target: herba
Printing size:
"R:/Tools/ArduinoIDE/hardware/tools/avr/bin/avr-size" -A "R:/Projects/viridi-nexu/herba/Release/herba.elf"
R:/Projects/viridi-nexu/herba/Release/herba.elf  :
section             size      addr
.data                636   8388864
.text              13546         0
.bss                 242   8389500
.eeprom                4   8454144
.debug_aranges      2744         0
.debug_pubnames     6326         0
.debug_info        51917         0
.debug_abbrev       9927         0
.debug_line        27045         0
.debug_frame        4816         0
.debug_str         13228         0
.debug_loc         28079         0
.debug_ranges       2816         0
Total             161326


Finished building target: herba

The herba.eep file content is somewhat simple:

:02000000CCCC66
:00000001FF

With the following use of EEMEM in the source code

EEMEM uint16_t something = 0xCCCC;

Which seems somewhat correct to me: I'm defining the default value in my code and the compiler is taking it into the .eep file, but when I read that same value using uint16_t another = eeprom_read_word(&something).... I get 0xFFFF :cold_sweat:

How can I push the .eep file onto the EEPROM?

UPDATE

I self answered my own question after a quick search: I can use avrdude to flash the eeprom contents just using

R:/Tools/ArduinoIDE/hardware/tools/avr/bin/avrdude -CR:/Tools/ArduinoIDE/hardware/tools/avr/etc/avrdude.conf -patmega328p -carduino -P COM3 -b57600 -D -Ueeprom:w:R:\Projects\viridi-nexu\herba/Release/herba.eep:i

Now I need to write some code to generate the .eep files: if you guys already have some reference it would be a time saver!

You can not use the EEMEM variables directly, you still have to use those eeprom_read... functions. It is as you wrote.

I used a binary file, eeprom.dat.
I think I created it with a small 'c' program in linux that had the same struct. I compiled it with the bytes packed after each other with "#pragma pack(1)". But that is a long time ago.

The Arduino IDE does not allow writing initialized values to EEPROM, even though avrdude does support it. Perhaps in the future...

Thanks for confirming I'm understanding it

Peter_n:
The Arduino IDE does not allow writing initialized values to EEPROM, even though avrdude does support it. Perhaps in the future...

As I said, I'm not using the ArduinoIDE but Arduino Eclipse which apparently nicely supports defaults, at least when specified as simple variables.

How can I provide default values if I use a custom structure?

struct Config {
uint16_t var1; // can't add a value here
uint16_t var2; // can't add a value here
}

EEMEM Config config;

Try to fill them as a normal struct. I'm curious if Eclipse generates an eeprom file out of that.

EEMEM config_struct config = { 10, 12 };

FWIW, I struggled with this greatly (my project.eep files being full of 0's). Did some research, and found out that attribute ONLY works with POD types. So, check if you have any constructors, destructors, base-classes, etc. they will all mess you up. Anything you flag with this attribute HAS to be very simply declared/defined and initialized.

In either case, if you're looking for a generalized solution to automat, compile-time EEPROM allocation check out this library I built. It solves a critical corner-case: What happens if your MCU looses power right in the middle of saving to EEPROM? It also allows you to transparently wrap up your EEPROM data with a magic value and a version number, so at load-time you know if your bits are valid or not. Check it out: GitHub - Yewess/Eep: Templated class for initializing/containing EEPROM data in user-defined structure

rlogiacco:
How can I push the .eep file onto the EEPROM?

UPDATE

I self answered my own question after a quick search: I can use avrdude to flash the eeprom contents just using

R:/Tools/ArduinoIDE/hardware/tools/avr/bin/avrdude ...

Now I need to write some code to generate the .eep files: if you guys already have some reference it would be a time saver!

It exist bug#1318 that default IDE will not upload eep file even it exist.

You can check THIS method, how to patch IDE