This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Fstorage vs. SoftDevice activity: application halts when writing to flash if waiting to write or data not correctly written if not waiting

Dear Madam/Sir,

I'm working with SDK14.2, softdevice5.0.0-2alpha, s140, and nRF52840 through the DevKit.

I'm recurring to the fstorage API to read/write/erase flash while using the SoftDevice and respective BLE activity.

When erasing and subsequently writing to the flash (see flash_write_setup() below), in order to get the data correctly written I wait for the commands to get accomplished before continuing running the application, as follows:

static void fstorage_erase(uint32_t addr, uint32_t pages_cnt)
{
    ret_code_t rc = nrf_fstorage_erase(
		&fstorage,      /* The fstorage instance to use. */
		addr,           /* The initial address of the flash pages to erase. */
		pages_cnt,      /* The number of pages to erase. */
		NULL);          /* Optional parameter, backend-dependent. */

    if (rc != NRF_SUCCESS)
    {
        NRF_LOG_INFO("nrf_fstorage_erase() returned: %s",
                        nrf_strerror_get(rc));
    }
    APP_ERROR_CHECK(rc);
}

static void fstorage_write(uint32_t addr, void const * p_data)
{
    /* The following code snippet make sure that the length of the data we are writing to flash
     * is a multiple of the program unit of the flash peripheral (4 bytes).
     *
     * In case of non-string piece of data, use the sizeof operator instead of strlen.
     */
    //uint32_t len = round_up_u32(strlen(p_data)); //THIS CRASHES WHEN DEBUG MODE, WHY?
    uint32_t len = sizeof(p_data);

    ret_code_t rc = nrf_fstorage_write(
		&fstorage,      /* The fstorage instance to use. */
		addr,           /* Address in flash where to write the data. */
		p_data,         /* Data to be written. */
		len,            /* Length of the data (in bytes). */
                NULL);          /* User-defined parameter passed to the event handler (may be NULL). */
    
    if (rc != NRF_SUCCESS)
    {
        NRF_LOG_INFO("nrf_fstorage_write() returned: %s",
                        nrf_strerror_get(rc));
    }
    APP_ERROR_CHECK(rc);
}
void wait_for_flash_ready(nrf_fstorage_t const * p_fstorage)
{
    /* While fstorage is busy, sleep and wait for an event. */
    while (nrf_fstorage_is_busy(p_fstorage))
    {
        //power_manage()
        ret_code_t err_code = sd_app_evt_wait();
        APP_ERROR_CHECK(err_code);
    }
}

void flash_write_setup(DEVICE dev)
{
static uint32_t pages_to_erase = 4;
fstorage_erase(m_start_addr_write, pages_to_erase); //m_start_addr_write =0x69000 (my app is not using bootloader)
wait_for_flash_ready(&fstorage);
fstorage_write(m_start_addr_write, &dev); //DEVICE is a struct with three uint8_t fields
wait_for_flash_ready(&fstorage);
}


Yet, if the app is advertising (1.285s interval) or in a connection (275ms interval with slave_latency 3) the app halts and never finishes erasing/writing the data and the app stops working.
If not calling wait_for_flash_ready() after erasing/writing the flash, the app runs smoothly, the data is suposely written after around 2secs and when reading it afterwards the data is wrongly written.

What am I doing wrong and how can I successfully erase/write data in the flash while operating with the SoftDevice and BLE activity?

Thank you,
Best regards,
João
Parents Reply Children
  • Hi Pawel,

    Thank you for your answer.

    I'm writing in the flash some default app configurations right after enabling the softdevice and advertising and subsequently enabling the fstorage API. I write again after establishing a connection under which I'm erasing the default configurations and writing new ones in the same flash address.

    How can I check on which priority are the flash operations running?

    If I not block the app until the flash erase/write operations are running the app doesn't halt and keeps running smoothly but the data is not correctly written.

    I've forced len = 4 to be sure, but with len = sizeof(p_data) it always work when I block the app while the flash erase/write is taking place.

    Thank you again for your help,

    João

  • Hi Joao,

    If I understand correctly your first store is done from the main context after you have performed initialization (enable SD and started advertising). Does store pass without hang here?

    The second time you perform store after connection. Do you perform this store from SD event informing about connection?

    If you do perform the store operation from SD event then code will hang. FLASH stores are performed from SD context. This operation will never be started until you finish SD event call. You cannot then wait in the event for FLASH operation to complete.

    Thanks,
    Pawel

  • Hi Pawel,

    You're right, both write flash calls are performed from the main context, the first after enabling the softdevice and start advertising and the second immediately after connecting to the peripheral (from the BLE_GAP_EVT_CONNECTED event).

    I understand that I can't hang from the main context and SD events, yet if don't hang the data is not correctly written using the fstorage. 

    I just replaced the fstorage API with the FDS one and it works perfectly without hanging, so why is fstorage not writing the data correctly if I don't hang?

    Thank you again for your help,

    Best regards,

    João

  • Hi Joao,

    the second immediately after connecting to the peripheral (from the BLE_GAP_EVT_CONNECTED event).

    This second store is not done from main context but from SD event called from SD assigned interrupt.

    To make sure that SD can meet strict timing requirements it is not possible to perform blocking flash store. Instead fstorage performs store through SoftDevice. When you call store from BLE_GAP_EVT_CONNECTED store is not yet performed but only scheduled. It will be performed via SD later on.

    Your data is incorrect as store happens asynchronously - it may happen that you read data before it is actually written to FLASH.

    What you can do is to register a callback function when you create fstorage instance to be be notified when store completes. You could change you application logic to behave correctly now.

    FDS was written to work correctly considering SD and fstorage interaction limitations.

    I hope it helps.

    BTW, going back to

    len = sizeof(p_data)

    I mentioned this above and I am sorry if I repeat something you already know.

    The sizeof(p_data) in your case will not give you size of the buffer but sizeof void* which is 4. When you store let's say a buffer of 16 bytes, you cannot use sizeof with pointer to this buffer as it will not give you length you may expect (i.e. in this case you may expect 16 but it will give you 4). You also cannot use strlen as it will only work with nul-terminated strings.

    Regards,
    Pawel

Related