EEPROM by emulation??

In the product description one can read

It also has 32 KB of SRAM and up to 16 KB of EEPROM by emulation.

This information is also found on several site on the net if you google for "arduino zero eeprom", but noone seems to have any clue how the emulation is done?!

I have an existing codebase, which makes massive use of EEPROM.h and it would be very nice if there would be an identical API for accessing the (eeprom emulated) flash.

Any hints or comments?

If there is no identical eeprom API for accessing flash: Any suggestions how to overcome complete re-write of existing functionality in my codebase wrt EEPROM access?!

I need this too ...
see here --> how to get an EEPROM like functionality ? - Arduino Zero - Arduino Forum

xx

I ended up using a Microchip 24LC256 I2C EEPROM in an 8 pin DIP package. It's inexpensive, widely available, with 256kbits (32k x 8 ) of memory, operates from 2.5V to 5.5V, up to 400kHz I2C and an endurance of over 1 million erase/write cycles.

The Hobbytronics (hobbytronics.co.uk) website has comprehensive instructions and example code that covers not only byte read and writes, just like the EEPROM library, but also page writes as well.

The only disadvantage is that byte or page writes take 5ms to complete, which might be an issue for some applications.

A page-write on the 24LCxxx will take about 3.5 ms. On an AVR, a single byte-write to the EEPROM takes about the same time.

You typically reserve a page or two of Flash on an ARM to "emulate" EEPROM. I have not checked the data sheet. I suspect that a page-write will take a similar time.

A 24xxxx or an AVR will handle the load the page buffer, erase page, program the modified page buffer transparently.

You do the ARM "emulation" via software. In practice, all the strategies work. It is always best to write multiple bytes to a page.

David.

but when you upload a new firmware to the zero the whole Flash will be erased first (with bossac)... :frowning:

You have the same "feature" with internal EEPROM on an AVR.

I am sure that you can preserve a block of Flash from erasure in software.
Much like the EESAVE fuse on an AVR.

Untested. I have not looked at Bossac.

I would agree that an external 24xxxx is a simple and easy solution.

David.

1 Like

I've written two small C++ libraries for the 24LC256 called "ExtEEPROM" and "EEPROMAnything2".

"ExtEEPROM" is based on the example code from Hobbytronics and allows you to read and write bytes to and from the external EEPROM, just like the EEPROM library. Works with the 24LC256's I2C address set to 0x50, (all the chip address inputs A0, A1 and A2 pulled low or left unconnected).

"EEPROMAnything2" is a modification of the EEPROMAnything library that allows you to read and write any data structure or array to and from the external EEPROM.

I've attached the libraries in the zip file below. Just place them in your Arduino/libraries directory.

Here's some example test code for EEPROMAnything2:

#include <Wire.h>
#include <ExtEEPROM.h>
#include <EEPROMAnything2.h>

struct TestStruct   // Create a test structure
{
  int32_t x;
  float y;
  uint8_t z;
} testStruct = { 5, 1.23483748, 0x08 };

void setup() 
{
  Serial.begin(115200);                   // Initialise the Serial port
  Wire.begin();                           // Initialise the I2C library
  Serial.println("Begin Test...");        

  EEPROM_writeAnything(0, testStruct);    // Write the test structure to EEPROM
  
  int32_t valueX;
  float valueY;
  uint8_t valueZ;
  
  EEPROM_readAnything((uint32_t)&testStruct.y - (uint32_t)&testStruct, valueY);   // Read the EEPROM values individually
  EEPROM_readAnything((uint32_t)&testStruct.z - (uint32_t)&testStruct, valueZ);
  EEPROM_readAnything((uint32_t)&testStruct.x - (uint32_t)&testStruct, valueX);
  Serial.println(valueX);                                                         // Display the values
  Serial.println(valueY, 6);
  Serial.println(valueZ);
  EEPROM_writeAnything((uint32_t)&testStruct.y - (uint32_t)&testStruct, (float)3.35343);  // Change the float value
  EEPROM_readAnything((uint32_t)&testStruct.y - (uint32_t)&testStruct, valueY);   // Read the EEPROM values individually
  EEPROM_readAnything((uint32_t)&testStruct.z - (uint32_t)&testStruct, valueZ);
  EEPROM_readAnything((uint32_t)&testStruct.x - (uint32_t)&testStruct, valueX);
  Serial.println(valueX);                                                         // Display the values again
  Serial.println(valueY, 6);
  Serial.println(valueZ); 
  EEPROM_readAnything(0, testStruct);     // Read from EEPROM back to the test structure
  Serial.println(testStruct.x);           // Display the test structure
  Serial.println(testStruct.y, 6);
  Serial.println(testStruct.z); 
  Serial.println("End Test...");
}

void loop() {}

EEPROM.zip (1.23 KB)

tuxedo:
but noone seems to have any clue how the emulation is done?!

Well, I have a pretty good idea about this, so I wouldn't say noone does!

During the Arduino Zero beta test period, I wrote a couple lengthy messages on a private forum Arduino used to coordinate beta testers, regarding my thoughts on implementing the EEPROM library on top of SAMD's flash. Sadly, nobody seems to have attempted to implement it. Those messages never became public. I no longer have access to them.

If you doubt I might know this stuff, I am the creator of Teensy and I implemented EEPROM emulation on Teensy-LC, which uses a 48 MHz Cortex-M0+ processor pretty similar to Arduino Zero. On Teensy-LC, sketches that use the EEPROM library work properly, as long as they access only the first 128 EEPROM bytes. That's not nearly as much EEPROM memory as most AVR-based Arduino boards have, but nearly all libraries and examples sketches which store configuration in the EEPROM use less than 100 bytes (or have a #define or variable to edit for the total size to use). Writing to the emulated EEPROM stalls program execution and even reading has very different timing than AVR, but nearly all existing sketches that need EEPROM storage aren't very sensitive to write or even read timing. Despite these limitations, Teensy-LC's compatibility with most sketches storing data with the EEPROM library is very good. Arduino Zero could be do, if anyone is willing to do the programming work....

Obviously the first step involves choosing a region of flash memory to be reserved for emulating the EEPROM. Unfortunately, the tools used for Zero erase the entire flash memory. Changing the bootloader to preserve that memory might be possible. The EDBG chip might be harder! You can still emulate EEPROM without this, but the Arduino users expect EEPROM contents to be preserved during every upload. FWIW, on Teensy-LC the top 2K of flash was set aside from the beginning as space for EEPROM emulation, so the bootloader never erases it. The linker script also prevents compiled code from using that space. If you get the rest working, maybe the Arduino devs will consider changing the published tools?

Assuming you have space reserved, you need to come up with a data storage scheme that works with the properties of your flash memory. Flash is erased in large blocks and written in small words. Erase turns all the bits within a block to 1s. Writing can turn those 1s into 0s. Some chips allow re-writing words, others don't. Even if they do, the only way to get 0 bits back to 1s is with an erase of the entire block.

Freescale's FTFA flash controller has 512 byte block erase size. Write words are 32 bits, but can be used multiple times to turn any 1s into 0s.

Many things about SAMD aren't perfectly clear to me. For example, section 21.6.3 seems to say the erase block size is 256 (4 pages, which are 64 bytes), but other places seem to suggest pages may be erasable. 21.6.5.3 pretty clearly says the write word size is either 16 or 32 bits. 8 bit writes aren't possible. It's not clear if you can turn more 1s into 0s within the same already-written word. Some chips allow this, others don't. Atmel's documentation isn't clear to me on this point. In fact, some parts seem to suggest 64 bytes have to be written at once.

When I looked into this during the Zero beta test, I found an extra restriction in Atmel's software documentation about a limited number of writes being allowed within each page before erasing. It doesn't seem to be mentioned in their datasheet at all, though I must admit I've not read every part. I just looked and couldn't find this info again.... so perhaps I'm remembering incorrectly. Anyone actually trying to implement this might look for it.

Working within the block erase size and word write size and any other erase/write hardware guidelines, you need to come up with a data storage scheme which spreads the write activity (hopefully) evenly across the memory. Flash memory has much lower write endurance, so this "wear leveling" is needed to allow EEPROM-like endurance.

For Teensy-LC, I used a simple scheme where every EEPROM write stores 2 bytes within the flash blocks, one for address and the other for data. Because I only implemented 128 emulated EEPROM bytes, addresses 128 to 255 mean the 2 bytes are unused. Reading requires a linear search to find the last location with the desired address. I used a very simple scheme where the entire 2K is erased when you need to write past the last location. Because only 128 bytes can be stored, simple code just reads the whole thing to collect up all the data into a 128 byte buffer in RAM, then the entire 2K is erase, and all non-255 bytes from the buffer are written to the beginning of the freshly erased memory. It's a very simple scheme, but it works. A good number of people have used sketches that depend on the EEPROM library for storing small amounts of data, with happy results.

Atmel appears to have designed something similar. It's documented in application note AT03265. However, Atmel's scheme appears to be designed around storage of 60 byte blocks, rather than individual bytes. It also uses a RAM-based cache, which is an opportunity for data loss and very unlike when most users of the EEPROM library would expect. Atmel recommends implementing the brownout early warning interrupt to flush the cache.

A simple but inefficient approach might be to build the EEPROM library on top of Atmel's code, by placing just a single byte in the 60-byte logical page. This would allow immediate flushing, which is closest to what people expect from AVR. Or you could pack pairs of address+data into the 60 byte pages, which might give good wear leveling even with unusual write patterns, but at a cost of searching to read (similar to what I did on Teensy-LC, which has worked well in practice). Or each 60 byte page could implement 60 bytes of emulated EEPROM, which is probably the most memory efficient way, and still might have decent wear leveling if you limit the emulated address size. Maybe?

Or you could not use any of Atmel's code and try working directly with the hardware registers documented in section 21.8. Since none of the 256K chips have the RWW feature, you'd probably have to place a small amount of code in RAM to do the actual dirty work, which you'd call with interrupts disabled. That's what I did for Freescale's chip on Teensy-LC.

Of course, if you only care about getting your own project to work, rather than developing a good emulation of the EEPROM library, perhaps Atmel's software with 60 byte blocks could meet your needs? Or just adding an external EEPROM chip might be the path of least resistance?

Any update so far on this interesting topic ?

I'm trying to port a source code from AVR to SAMD21 that use extensively EEPROM
I would like to avoid an external I2C eeprom chip and I'm wondering if no one has developed a proper EEPROM emulation library compatible with EEPROM.h for AVR

thank you
Davide

extEEPROM library (Original library by J. Christensen) is available on library manager (IDE >1.6.5) --> GitHub - PaoloP74/extEEPROM: Arduino library to support external I2C EEPROMs.

Thank you

I have already seen that specific library but according to my understanding it’s used to manage external EEPROM via I2C
Just wondering if there is any library to emulate EEPROM inside SAMD21 flash that uses same EEPROM primitives as standard Arduino Library to port the orginal code

Davide

Is there any change regarding the subject? is there a proper library to write to WWR in the SAMD21 ?

I heard this library works: