How to replace AVR-like EEPROM functionality for SAMD21

Hi,

Searching for this topic on google comes up with a number of threads, however none of them was conclusive or I was unable to understand what the final recommendation was!

Current situation :
I have a number of working sketches that use the onboard eeprom on 32U4 or 1284p MPUs to store settings for my sketches. Having decided to move to an ARM MPU I now need to "port" these sketches to work on an arduino zero clone type of board but I need to find a replacement for the functionality of the onboad EEPROM that does not exist on ARM MPUs.
As for hardware, I seem to have two options:

  1. My custom PCB also has a place for an external I2C connected EEPROM
  2. EEPROM emulation of the MPU's flash memory

Does the fact that the contains of this "EEPROM" must be maintained even when the program is re-flashed crosses out option 2 above?

If now option 1 is implemented, whats the easiest way to use my existing sketches and somehow "re-direct" access to external I2C eeprom when the sketch is loaded to an arduino zero board but also maintain compatibility with the AVR boards?

Thanks!

You can have a look at FlashStorage (Maintainer: Arduino)

You could use SPIFFS and have a look at Arduino_MKRMEM

Please take note of the comment (on GitHub):

Attention : Before you can use SPIFFS you need to erase and format the flash memory chip using SPIFFSFormat.ino

ESP32 offers directly some embedded options mimicking EEPROM (in Flash too)

External I2C EEPROM is an option, it's an additional piece on your I2C bus and cost to your BOM. The plus side is that you can exchange the External I2C EEPROM chip if it wears out (if you write very often) whereas you'll have to change the full SAMD board if your flash memory wears out.

1 Like

Thanks for your input!
It looks like with FlashStorage memory contains are lost when a new sketch is uploaded.
Also the SPIFFS option requires to erase all page memory data in order to change a single bit from zero to 1.
This makes both above options unsuitable for my application.

So i suppose i am left with an external I2C EEPROM option.

I wonder how I could easily redirect access to the external EEEPOM whenever the sketch is compiled for an ARM based arduino...

Write a custom class that is encompassing both capabilities behind a unified API with conditional compilation...

I already use conditional compilation using #ifdef statements.
However I am not sure what you mean by "custom class" and "Unified API".

Care to offer a snippet example ?

if you look at the EEPROM library, it offers the following API

EEPROM Methods

you could design a Class mimicking that API that would just basically be the EEPROM class on AVR through conditional compilation and implement an I2C EEPROM access layer on other architectures.

You mean design another library similar to eeprom.h which will instead send data to the external eeprom?

almost

design another library similar to eeprom.h which will pose as EEPROM on AVR and mimic the internal EEPROM (using external EEPROM) on other platform. This way you write only one code and depending on your architecture the compilers figures out what needs to be done.

Could you use this Sparkfun library?

https://github.com/sparkfun/SparkFun_External_EEPROM_Arduino_Library

At the top of your sketch, put:

#ifdef __AVR__
#include <EEPROM.h>
#else
#include <Wire.h>
#include "SparkFun_External_EEPROM.h"
ExternalEEPROM EEPROM;
#endif

Then in setup() put

#ifndef __AVR__
  Wire.begin();

  if (!EEPROM.begin())
  {
    Serial.println("No i2c EEPROM detected. Freezing.");
    while (true);
  }
#endif

Yes there are libraries out there that you could use (this one does not offer update() or exactly the same API but that's the idea) and you can abstract the thing into your own class if you don't want to have the #ifdef stuff in your sketch

As long as it offers eeprom.read and eeprom.write so that i wont have to change the existing code... but absence of update is an issue too

update() is just a read() followed by a comparison and a write() if the values are different, so easy to implement with read() and write() if you have your own class

and quite fun to look at how it's done through the abstraction layer with the EERef struct

EERef &update( uint8_t in ) { return  in != *this ? *this = in : *this; }

I think all .update() does is check if the value is different before writing it. So you could change your code to use

if (EEPROM.read(address) != value) EEPROM.write(address, value);

Unlike the internal eeprom, the external eeproms have page boundaries which need to be taken into consideration. Porting the code to an external device depends on the size of what is stored.

From the Sparkfun library description on the link above:

Yes, I know what the library claims, but if you actually look at the source code, it just truncates the write.

There was a bug posted against the library in GitHub about the page boundaries as well.
https://github.com/sparkfun/SparkFun_External_EEPROM_Arduino_Library/issues/3

1 Like

I store mostly single byte variables, sometimes Ints in specific contiguous mem addresses from 0 to 1000 dec.

You should be able to manage the page boundaries just fine with these short writes.

Good spot @cattledog . Shame on Sparkfun for not fixing that in a way that any odd-sized data works ok with page boundaries, or at least clarifying the claim I quoted above. Sounds like @Watcher will not have any problems saving his (or her) byte and int data.

Thank you all for your input.

I added this compile option

#ifdef __AVR__
 #include <EEPROM.h>
 
#else
  #include "SparkFun_External_EEPROM.h"
  #define EEPROM_ADDRESS 0b1010001
  #define EEPROMSIZE  32768
 
 ExternalEEPROM EEPROM;
#endif

also created a custom function:


void EEPROMupdate(int addr,byte value){

if (EEPROM.read(addr)==value) return;
else
 EEPROM.write(addr,value);
 
}

which replaced all previous EEPROM updates while all other EEPROM read calls remain the same as before.

And it seems to work...