How can I provision a persistent array of int in flash memory and access it as an array of int from mbed C++?

Here is an example. If I declare an array like this:

static const int32_t data = {comma separated values};

The array does not show up in the memory map in either flash or ram.

It appears to be allocated in flash because if I make the array too big, I get an error:

.text’ will not fit in region `FLASH.

Rather than compile the array, I would like to provision the array in the flash and access it from the code in the same way as if it were compiled in.

How could I accomplish this?

Constant’s value cannot be changed so it’s rational to store it in the FLASH memory rather than in the SRAM. The modifier const tells the compiler that a name represents a constant and it shall be stored in the FLASH memory (in contrary to for example Arduino). As far as I know we cannot change that behaviour of the ARM compiler. Then we can access constants in the code without any additional provisions. We don’t have to specify that they should be read from FLASH (in contrary to for example Arduino).

If your question was how to create a variable (especially an array) in the FLASH memory and access it from the code then one way is to utilize Mbed’s Flash IAP API. But be aware of increased FLASH memory wear out and quite slow write speed (in comparison to using SRAM)!

An example is below:

#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");

    // Create an array in SRAM (later on to be stored in the first page of last sector in FLASH)
    uint32_t        data_len = page_size/sizeof(uint32_t);      // calculate available space
    uint32_t*       data = new uint32_t[data_len] {1, 2, 3};    // create an array in SRAM and initialize the first three elements

    data[11] = 572; // set element 11 to 572

    // Print the first 15 elements
    for (int i = 0; i < 15; i++) {
        printf("data[%d] = %d\r\n", i, data[i]);
    }

    // Store the array 'data' in FLASH
    flash.erase(addr, sector_size);         // erase needs sector_size (not page size)
    flash.program(data, addr, page_size);   // write needs page_size


    printf("----------------------\r\n");

    // Clear the first 15 elements in SRAM (to see whether they are going to be updated with values stored in FLASH)
    for (int i = 0; i < 15; i++) {
        data[i] = 0;
        printf("data[%d] = %d\r\n", i, data[i]);
    }

    printf("----------------------\r\n");

    // Update the SRAM array with values stored in FLASH
    flash.read(data, addr, page_size);      // read needs page_size

    // Print the first 15 elements
    for (int i = 0; i < 15; i++) {
        printf("data[%d] = %d\r\n", i, data[i]);
    }

    delete[] data;
    flash.deinit();

    printf("----------------------\r\n");
    printf("Done.\r\n");
}

Thank you for your timely reply with examples.

This is helpful, but not quite what I am looking for.

I have a large data structure on the order of 132K uint_32t, or 512K bytes.

If I declare this array const, the compiler allocates it in flash, which is what I want.

If I am not mistaken, the code that accesses this array in flash is identical to the code that accesses the same array in sram if it were not compiled with the const modifier. The arm must have some way to map the memory accesses to flash.

If I write the data to flash and use the flash API to read it into sram, then I have to pay the price of the storage twice – once in flash, and again in sram – if it will even fit in sram.

What I am looking for is a way to provision the data in flash with one app and then access the data from another app as if it were a compiled const array.

Is this possible?

The example you gave me is very useful for a different purpose – for storing a small amount of persistent configuration data. I have one question about this: how do I know it will not be overwritten by compiler const data?

Thank you for your help. I really appreciate it.

Jim

I think the first part (provision the data in flash with one app) is feasible. But I don’t know how to access the data from another app as if it were a compiled const array. The problem is when a const is declared it also must be initialized with data. And that would overwrite the existing data in FLASH.

Get the flash_start and addr as indicated in the example above and make sure that flash_start + Total flash memory used by the program (as reported by the compiler) < addr.

Hello hudakz,

I am currently trying to make a simple project for saving an array in Flash memory and I found your code great for starting with.

I tried using your code in this post but I am getting an Error: Identifier “FlashIAP” is undefined in “main.cpp”, Line: 4, Col: 2

Although FlashIAP belongs to mbed API official library the programm does not even compile. I am posting here in order to check maybe you have come accross with the same problem.

I am using mbed online compiler and Nucleo F334R8 as a target.

Best regards.

Hello Giannis,

I’m sorry, I don’t have good news for your. The FlashIAP is available only in Mbed OS 5. But unfortunately the NUCLEO-F334R8 board does not seem to be supported by Mbed OS 5. I’ve got the following error when trying to compile:

Could not compile for NUCLEO_F334R8: Target does not support mbed OS 5

Best regards, Zoltan

Are you sure?
I can not test it because I do not have this board but both tools (Online compiler and Mbed Studio) can successfully compile program for this board, with bare metal profile.

And the FlashIAP can be probably added via Mbed_app.json file.

Save data on Nucleo F334R8 when powered by battery

BR, Jan

Yes, that was reported by mbed-cli after issuing: mbed compile -m NUCLEO_F334R8.
After adding bare-metal I have got the following message:

[Error] main.cpp@4,1: 'FlashIAP' does not name a type

Yes, but how I wrote, it is need to add

{
    "requires": ["bare-metal"],
        "target_overrides": {
        "*": {
            "target.device_has_add": ["FLASH"]
        }
    }
}

BR, Jan

Thanks for the support.

I maybe try the bare metal profile way that Johnny K suggested.

However, it is quite strange not to be able to use Flash memory in this way for boards supporting MbedOS2.