[Submission] Flashee-eeprom library: eeprom storage in external flash

Excellent library what I am looking for. Just wonder, I did not see where/how the mapping is done (in library code) for the available flash area to be used as storage. In Spark doc, it mention

0x80000 End of OTA Firmware
NOT USED
0x200000 End of Flash Memory

Thanks

The Devices::userFlash() provides a FlashDevice instance that maps to the user region of flash. With this, it isolates you from the low-level details (e.g. the specific start address.) So the first user address starts at 0 and up to length().

@mdma,

Awesome library! Looking forward to using it. One question thoughā€¦ I need to ā€œseedā€ some data into my ā€œEEPROMā€ at production time for my product (things like logo, fonts, hardware version, etc). Is there a way to take a snapshot of a spark core that has all this data and copy it to a new device? Is it as simple as downloading via dfu-util the entire ā€œNOT USEDā€ flash space:

dfu-util -v -d 1d50:607f -a 1 -s 0x80000:1572864 -U flash_copy.bin

And then uploading it to the new core:

dfu-util -v -d 1d50:607f -a 1 -s 0x80000 -D flash_copy.bin

?

Thanks! :slight_smile: Yes, just like that. As long as these are pages are unused in flashee theyā€™ll not be touched. Although if itā€™s just the read-only data you need, would be best to limit writing to just that (e.g. the first 10 pages, or however much read-only data you have). Then have your program create any additional read-write eeprom areas at startup if needed (e.g. read the last byte of flash - if itā€™s 0xFF then create the read/write area, and set the last byte to 0xFE.)

Or, you could build the ā€œpopulatorā€ app you mentioned - run that once to create the writable areas, then take an image of the entire user area of external flash (as you did above.)

I started the coding and having following problem. If I create the "Devices" will below parameters, the code will crash so bad that I need to use USB to re-flash different code again.
If I don't put parameters, then it is OK.
Is there some limit in number of page to use ?

FlashDevice *record;
struct PROG_HEADER progHeader;

record = Devices::createAddressErase(0, 2*4096); // Crash
record = Devices::createAddressErase( ); // OK

record->read(&progHeader, 0, sizeof(struct PROG_HEADER));

For address erase and wear levelling, the system uses 2 blocks for housekeeping (one so that there is always a free page to copy data to, and another for tracking if the region needs formatting or not.)

To fix, increase the space to at least 3 pages. If you donā€™t plan to use the rest of the flash, then itā€™s best to allocate the maximum size possible so that writes are spread out over the whole region.

Iā€™ll update the doc comments in the code to make this clear.

Thanks for the info.

This is amazing! Thank you so much for your work on this library, so much exactly what I was looking for! Especially all the wear leveling, TDD on ĀµControllers and the abstracted page distribution, ā€¦ <3
Itā€™s a beautiful piece of art. :sunny:

Thanks for your appreciative comments! Itā€™s my hope that it in some way encourages library writers to go that extra mile and develop using quality-first techniques.

I have been successfully data logging using wear levelling mode for 3 weeks and all seems well. Just had a problem tonight with the cloud compiler giving the following error message:-

monitor-rev5.7.cpp:4:43: fatal error: flashee-eeprom/flashee-eeprom.h: No such file or directory
#include ā€œflashee-eeprom/flashee-eeprom.hā€
^
compilation terminated.
make: *** [monitor-rev5.7.o] Error 1

Seems to be a bug coming up a bit today, the trick is to remove the tabs in the ide and re add them.

@Dave there are a few posts about this now, just thought it would be best to bring it to your attention

Another link with same issue i think

1 Like

Hi @Hootie81,

I just got off a plane, so Iā€™m catching up. Thanks for the heads up, Iā€™m investigating now. :slight_smile:

Specific build times, and the url you were on would help me investigate if you have em.

Thanks!
David

Hey All,

I think the library issue youā€™re seeing might be a database / saving error in the build IDE. It would help a lot if you either sent me the url of a project where you had this issue, or the name of your project. You can also email it to me if you feel better about that (david@spark.io).

Thanks,
David

1 Like

Hi @mdma,

I know its been a while and this is not top priority for you at the moment, but Iā€™ve been having some issues with the library for the past two months. I keep seeing SOS errors with one blink for code that I compile locally.

Initially I thought this was mainly my fault because I extensively use the flash. But after applying many fixes to my code the issue persists. I use createAddressErase as the mode. So for the time being, could you tell me the safest and most reliable mode to use. Thanks :smile:

Strange that youā€™d get a SOS - I would have expected only that you get corrupt data. If you can find a way to reproduce the SOS, Iā€™ll compile the code locally and debug it.

Iā€™m using the Spark as part of a keypad door access project and want to store the access code locally in the Spark. Iā€™m a very out of date (20 years ago) C programmer so Iā€™m slowly getting to grips with all this. Would the library you discuss here work for this kind of thing? I just need a very simple write function into which Iā€™d pass the access code string and then a read function to retrieve it when required. Thanks!

You should probably start with the built-in EEPROM emulator docā€™ed here:

http://docs.spark.io/firmware/#other-functions-eeprom

If you outgrow that and need more storage, then you can look at Flashee.

Thanks for this. I wonder if you might be able to give me a few tips how I might use these functions to store and retrieve something declared in my code as
char* secretCode = "1234"
Do I need to split it up into bytes and store each one in consecutive memory locations? Sorry if Iā€™m being stupid and Iā€™m grateful for your help.

Hi @jmcaddy

You need to write the bytes one at a time with a cast:

void saveSecret(char* secret, int baseAddr) {
  for(int i=0,i<strlen(secret),i++) {
    EEPROM.write( baseAddr+i, (uint8_t)secret[i]);
  }
}

If your secrets are not all the same length, change the loop to i<=strlen(secret) to also write the zero byte at the end of the string so you will know how long it is when you read it back out.

I included a baseAddr so you can have multiple strings if you want.

I didnā€™t test that the final address is less than 100, the limit for EEPROM so be careful.

1 Like

Thank you very much itā€™s very kind of you to help.