Why do I need macro NRF_FSTORAGE_DEF?

Software Development Aspects:

  • nRF52805
  • Nordic SDK V 17.1.0
  • Softdevice 113 V 7.2.0
  • Segger Studio 6.40



I want to store some small user configuration (< 50 Bytes) to flash. So I used fstorage.h, which works perfectly. However sometimes it stops working, sometimes `app_error_fault_handler()` gets called during `nrf_fstorage_write()`, sometimes `nrf_fstorage_read()` returns `NRF_ERROR_INVALID_ADDR`.

So I took a closer look to used global variable `fstorage`.


NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage) =
{
    /* Set a handler for fstorage events. */
    .evt_handler = fstorage_evt_handler,

    /* These below are the boundaries of the flash space assigned to this instance of fstorage.
     * You must set these manually, even at runtime, before nrf_fstorage_init() is called.
     * The function nrf5_flash_end_addr_get() can be used to retrieve the last address on the
     * last page of flash available to write data. */
    .start_addr = 0x3e000,
    .end_addr   = 0x3ffff,
};



Everytime an error occurs, global variable `fstorage` isn't initialized correctly. After some tests I saw `fstorage` variable is persistent meaning values survice a chip reset. A closer look shows:


nrf_fstorage_t fstorage __attribute__ ((section(".fs_data"))) __attribute__((used))  = ...



This means variable `fstorage` resists in section .fs_data, which confuses me a lot.

A further test. I set `fstorage.start_addr` to a value, stopped execution on next statement via debugger and removed power source. After waiting a few seconds I started chip again and looked at `fstorage.start_addr` which remains unchanged.

Does this mean reading values via fstorage.h means writing persistent data three times (see `nrf_fstorage_init()`, `nrf_fstorage_uninit()`)?

When will variable `fstorage` be initialized? I guess only if section .fs_data is empty. In this case I may explain above initialization error.

Why do I need Macro NRF_FSTORAGE_DEF?


PS:
I removed NRF_FSTORAGE_DEF for test purposes and it worked.

Parents
  • Hello,

    The NRF_FSTORAGE_DEF() is use to define fstorage instances as a Section variable. This allows modules to register their own fstorage instances independently.

    But I'm not sure why the variable it is not getting initialized in your case. It is supposed to happen on startup here:

    Does your project include the file above (https://github.com/NordicSemiconductor/nrfx/blob/v1.8.6/mdk/ses_startup_nrf_common.s#L174)? Or are you using a different set of startup files?

    Best regards,

    Vidar

    Edit: I noticed after posting that you use SES version v6.40. There were multiple changes introduced in >v6.20 which are not compatible with our SDK and it may be related to the problem you are seeing. The general recommendation is to use same version as specified in the SDK release notes:

    The following toolchains/devices have been used for testing and verification:
     
     - ARM: MDK-ARM version 5.25   
     - GCC: GCC ARM Embedded 9.2020-q2.major
     - IAR: IAR Workbench 7.80.4
     - SES: SES 5.42a

  • Thanks for your fast answer.

    I am using the same `ses_startup_nrf52805.s` file. However I saw there is just another #define so I set INITIALIZE_USER_SECTIONS and initialization error is gone.

    However I am asking me if global variable `fstorage` still resides in flash memory. Just look in default flash_placement.xml.

    <!DOCTYPE Linker_Placement_File>
    <Root name="Flash Section Placement">
      <MemorySegment name="FLASH1" start="$(FLASH_PH_START)" size="$(FLASH_PH_SIZE)">
        // ...
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".fs_data"  inputsections="*(.fs_data*)" runin=".fs_data_run"/>
        // ...
      </MemorySegment>
      <MemorySegment name="RAM1" start="$(RAM_PH_START)" size="$(RAM_PH_SIZE)">
        // ...
        <ProgramSection alignment="4" keep="Yes" load="No" name=".fs_data_run" address_symbol="__start_fs_data" end_symbol="__stop_fs_data" />
        // ...
      </MemorySegment>
    </Root>

    So calling nrf_fstorage_init() probably results in flash write, which i didn't want.

    ret_code_t nrf_fstorage_init(nrf_fstorage_t     * p_fs,        // Points to global variable fstorage residing in .fs_data
                                 nrf_fstorage_api_t * p_api,
                                 void               * p_param){
        //...
        p_fs->p_api = p_api;    // Will this call be mapped to a flash write?
        //...
    }


    For me I don't need section variables. Sections variables looks like Inter Prozess Communication, which I don't need. Stored data is for firmware only.


  • Good to hear that it worked now. All of our SDK examples includes the INITIALIZE_USER_SECTIONS flag by default, so I just assumed it was included in your project too.

    The "p_fs->p_api = p_api;" line assigns function pointers to the flash APIs (NVMC or Softdevice) that are to be used with the fstorage instance.

Reply Children
No Data
Related