Save RAM in FLASH

Hi,

I am using a neural network librari which has its knowledge in RAM.

With this behaviour when I have a PowerOff all of my knowledge is lost, so I want to store the RAM in FLASH.

Here is the documentation and the procedure to save the knowledge in the FLASH : NanoEdge AI Library (AD) — NanoEdge AI Studio documentation

I have to create a RAM section using the linker script, then three functions: one to save RAM in FLASH, one to put FLASH in RAM and another one to dump the FLASH.

I have a working custom board with EFM32LG330F256G-QFN64, to debug and program I have an EFM32 Zero Gecko Starter Kit and I use mbed-os.

I’ve never worked with Silicon Labs MCU before.

I searched for application Note but could not find anything.

To compile my project I use in a terminal this command :

mbed compile -t GCC_ARM -m EFM32GG_STK3700 --profile mbed-os/tools/profiles/release.json -DREGION_EU868

I found where is the linker script in mbed:

https://os.mbed.com/questions/77416/How-to-add-a-Section-with-GCC-ARM-mbed-5/

Any idea how I can proceed to save the RAM in the FLASH ?

Thank you for your help.

Hello Jean_Guy,

This thread might help.

Thank you for your help.

The size of th RAM I want to save is 6496 + 52 bytes.
Is it possible to use your exemple to do so ?

Because I have a crypted library (see the link) placed at a particular address in the RAM. I have to read it, then save it in the flash.

They say that I have to modify the linker script to do so. How can I read the RAM at this particular address ?

The size of th RAM I want to save is 6496 + 52 bytes.
Is it possible to use your example to do so ?

  • Check the size of the last sector in flash memory on you target. For example by running the following program on the target:
#include "mbed.h"

FlashIAP flash;

int main() {
    printf("Starting...\r\n");

    flash.init();

    const uint32_t  flash_start = flash.get_flash_start();
    const uint32_t  flash_size = flash.get_flash_size();
    const uint32_t  flash_end = flash_start + flash_size;
    const uint32_t  page_size = flash.get_page_size();                  // in bytes
    uint32_t        sector_size = flash.get_sector_size(flash_end - 1); // in bytes
    uint32_t        addr = flash_end - sector_size;                     // address of first byte in the last sector

    printf("flash_start = 0x%.8x\r\n", flash_start);
    printf("flash_size = 0x%.8x\r\n", flash_size);
    printf("flash_end = 0x%.8x\r\n", flash_end);
    printf("page_size = 0x%.8x\r\n", page_size);
    printf("sector_size = 0x%.8x\r\n", sector_size);
    printf("addr = 0x%.8x\r\n", addr);
    printf("----------------------\r\n");

    flash.deinit();
}
  • If the sector_size < (6496 + 52) the related RAM can fit into the last sector.

  • If not check the size of the last but one sector (could be different than the size of the last sector) by replacing:

uint32_t        sector_size = flash.get_sector_size(flash_end - 1);

with

uint32_t        sector_size = flash.get_sector_size(flash_end - flash.get_sector_size(flash_end - 1) - 1); 

etc., until you know how many sectors are needed to store the related RAM.

  • In the neural network program create a pointer pointing to the begin of the RAM you’d like to save in flash and define the address in flash to store the RAM. For example:
...
uint32_t *myRAM = &myKnowledge_data;
uint32_t addr = flash_end - number_of_sectors_needed_for_RAM * sector_size;
...
  • Save myRAM in flash:
...
flash.erase(addr, number_of_sectors_needed_for_RAM * sector_size); // erase the related flash
flash.program(myRAM, addr, number_of_pages_needed_for_RAM * page_size); // save myRAM in flash
...
  • Load myRAM from flash:
...
flash.read((const void*)myRAM, addr, number_of_pages_needed_for_RAM * page_size);
...
  • Make sure the size of the neural network program < (flash_size - number_of_sectors_needed_for_RAM * sector_size). Otherwise the RAM cannot be stored in the flash memory.

  • Be aware of increased FLASH memory wear out and quite slow write speed!

1 Like

Waw, thank you for your answer. I’ll test it and let you know !

Thank you again.

So,
I tried to determine the number of sectors I need. The sectors have a size of 8 bytes, so I need at least 819 sectors [ (6496+52)/8 ] (I tried with several sectors, and I had always the same size).

Unfortunately, the neural network program I use is a crypted one. But I know that the library attributes a specific memory section called .neai for the knowledge variables (model hyperparameters). To use it, I need to create a memory section in the linker script according to my microcontroller architecture.

I have added :

.neai 0x0000000020007fff :
{
KEEP((.neai)) / keep my variable even if not referenced */
} >RAM

in my linker script.

Now, I’ll try to save using your exemples.

Which linker script file are you trying to modify (please provide path within the mbed-os directory)?

I eddited my previous reply, because I was writing the new memory section outside of the bracket of the SECTIONS part. I had to change the start address of the section too (I put the start adress of the data space of the SRAM from the datasheet).
Now I can compile my code properly.

Now, I am going to try to save/read/flush.

Thank you for your help, I let you know.

Once you have defined a neai RAM section in the linker script you can access it in your program by defining an array variable for example as follows:

uint32_t myRAM[size_of_the_neai_ram / size_of(uint32_t)] __attribute__((section("neai"))); 

rather than

uint32_t *myRAM = &myKnowledge_data;
1 Like

I have a problem with my linker script, when I add my new section :

.neai 0x0000000020000000 :
{
KEEP( *(.neai)) /* keep my variable even if not referenced */
} >RAM

My bin file is 524Mb… But without it it is 194ko. Why ?

The linker script I changed is in the folder :
mbedos\targets\TARGET_Silicon_Labs\TARGET_EFM32\TARGET_EFM32GG\device\TARGET_1024K\TOOLCHAIN_GCC_ARM

The pastbin of my linker script I modified with the neai section at the end : /* Linker script for Silicon Labs EFM32GG devices *//* - Pastebin.com

I found the same problem here : Solved: Using a custom memory section causes bin file is t... - NXP Community

Do I have to do the same thing as the answer ?

Based on a comment to the selected answer here : linker - Huge Binary size while ld Linking - Stack Overflow

Adding NOLOAD ensures that the section is not part of the binary file. Is this the correct thing to do ?

Well, after adding the NOLOAD it seems to work. I can erase, and program the flash.

But my program is stuck when I want to read the flash. I had to change the (const void *) to (void *) due to compilation error.

Is it because of mismatching size ?

Thank you for your help so far !

But my program is stuck when I want to read the flash. I had to change the (const void *) to (void *) due to compilation error.
Is it because of mismatching size ?

No, it’s because by a mistake (I’m sorry for that :frowning: ) I used the FlashIAP::program signature instead of the FlashIAP::read function, which is defined as:

int FlashIAP::read(void *buffer, uint32_t addr, uint32_t size)

So the cast should be to (void*) rather than to (const void*).
It seems that the compiler is never mistaken :slight_smile:

Hy,

I already tried to change the cast from (const void*) to (void*) and I have the same problem. Sorry I should have written :

I had to change the (const void *) to (void *) due to compilation error. But my program is stuck when I want to read the flash.

I don’t know it’s blocking, here is my line :
flash.read((void *)myRAM, addr, number_of_sectors_needed_for_nai_RAM * page_size);

Why are we deviding by sizeof(uint32_t) ?

uint32_t myRAM[(size_of_the_neai_ram / sizeof(uint32_t))] __attribute__((section("neai")));

  • Try to pass the number_of_pages_needed_for_neai_RAM * page_size to the read function rather than the number_of_sectors_needed_for_neai_RAM * page_size.

  • Why are we dividing by sizeof(uint32_t) ?

In the brackets we suppose to specify the number of elements of the array. However, the size_of_the_neai_ram is given as number of bytes (6496+52 bytes). To get the number of array elements we have to divide it by the number of bytes occupied by one element. Because the array type is uint32_t the size_of(uint32_t) should return the number of bytes occupied by one element.

If you don’t like it that way you can change the type of the array to uint8_t. In that case we don’t have to divide because one element occupies one byte:

uint8_t myRAM[size_of_the_neai_ram] __attribute__((section("neai")));

When I was debuging (before reading your answer) I found that the writing calculated address was 0xffdcd000 but the end address is 0x00100000

It’s because when I calculated the number of sectors needed for my RAM I ended with 819 sectors (don’t know why I thought sector size was 8 bytes, meh) ! But one sector is 4096 bytes, sooooo 819 times sector size was the error. I only need 2 (rounded) sectors of 4096 bytes to store the 6496+52 bytes.

I checked with a tool the memory map and I properly write to the good place in the memory.

Thank you very much for your help ! I learnt a lot today.