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

nrf_storage_is_busy() never returns false

Hi all,

I'm working on a project which I started from the multiperipheral example. I am using SDK 15.3.0 for this. I am developing the software on the nrf52840 DK using softdevice S140. This is my first C project (I used C++ until now) and I use the armgcc compiler. I want to store the device state to flash memory. Writing data works fine and I can read it back on a NRF_FSTORAGE_EVT_WRITE_RESULT event. However, I would like to make my write function block until writing is actually finished. For this I use a while loop which checks nrf_storage_is_busy() , however the nrf keeps stuck in this while loop until I reset it.

Some code snippets:

Initialization:

NRF_FSTORAGE_DEF(nrf_fstorage_t m_fstr); 

void fstorage_init(void)
{
    ret_code_t err_code;

    m_fstr.evt_handler = fstorage_evt_handler;
    m_fstr.start_addr  = DEVICE_STATE_START_ADDRESS;
    m_fstr.end_addr    = DEVICE_STATE_START_ADDRESS + DEVICE_STATE_SIZE;

    err_code = nrf_fstorage_init(&m_fstr, &nrf_fstorage_sd, NULL);
    APP_ERROR_CHECK(err_code);
}

Write function:

static int write_flash(size_t addr, void *p_data, size_t size)
{
    ret_code_t err_code;

    if (is_section_within_bounds(addr, size))
    {
        err_code = nrf_fstorage_write(&m_fstr, addr, p_data, size, NULL);
        if(err_code == NRF_SUCCESS)
        {
            while(nrf_fstorage_is_busy(&m_fstr))
            {
                sd_app_evt_wait();
            }
            return 1;
        }
    }
    return -1;
}

When I uncomment the while loop it works fine. What I tried so far:

  • Checked if fstorage backend was set to SD in sdk_config (it is).
  • Changed what is executed in the while loop. (to nrf_pwr_mgmt_run(); for example, as nrf_pwr_mgmt is being used)
  • Increasing this (If I understand correctly I should only do this when nrf_fstorage_write() is not returning NRF_SUCCESS all the time, but it is)

Could someone tell me what I am doing wrong?

  • Hi,

    The write_flash() implementation will only work if called from main the context, or from an interrupt context with lower priority than what the Softdevice interrupt has (i.e. no higher than pri. 7 which is also the lowest one available). The reason for this is that the softdevice interrupt is used to notify  the app/fstorage when an asynchrounus flash operation is complete, so if it gets blocked,  the fstorage 'busy' state will never get cleared.

    Have you considered not making the API blocking? Note that fstorage has an internal queue, so you can queue up multiple write commands without  any delays in-between.

     

  • Hi Vidar,

    Thanks for the fast response! The write function is called after a BLE write operation, which I guess is handled by the softdevice. So basically you're saying that I am blocking the softdevice interrupt with this? If I understand you correctly I could make the BLE write event trigger an interupt with pri. < 7 which will write the actual data to flash? I'll go look for some examples Slight smile

    As to why I want to make it blocking: I calculate a checksum of the data before writing, and directly after writing I would like to read the data again and make sure the checksum matches. I could do this by passing the checksum as an argument to the fstorage_write function, so I can do the check on a NRF_FSTORAGE_EVT_WRITE_RESULT. However, I write to flash for different reasons, which require different actions after the write. So I think making it blocking will make it a cleaner implementation for my purpose.

    Update: It seems it isn't a matter of just calling an interrupt from the BLE write event. How is this normally done? When data is written to the device, I think it shouldn't be processed within the BLE_GATTS_EVT_WRITE or should it?

    Update2: Is it usual to use the Scheduler for this?

    Update3: The scheduler seems to be exactly what I need for this.

  • Hi,

    The app scheduler will prevent the interrupt from getting blocked. But I'm afraid it won't solve your problem either, because the softdevice events are added to the scheduler queue and only processed after when returning to the main loop.

    I think usually you can assume that a flash operation will complete succesfully. The fstorage callback will notify the app if there was a problem.

  • Hi Vidar,

    I was thinking about doing it this way: 

    1. BLE_GATTS_EVT_WRITE -> Add data to be processed to scheduler queue.
    2. return from interrupt
    3. In main loop, app_sched_execute() is called. -> data found in queue which should be processed.
    4. data is processed and should be written to flash
    5. as this is now executed in the main context (through the scheduler), nrf_fstorage_is_busy() should work.

    Could you debunk this? Or are you saying that the softdevice uses the very same scheduler?


    Else I think I need to indeed just assume the flash operation will complete succesfully and handle errors when they occur.

  • Hi,

    Yes, I don't foresee any problems with this approach. I actaully did not think of this possibilty. I thought the idea was to use the scheduler for Softevice events so events such as BLE_GATTS_EVT_WRITE didn't have to be processed in the Softdevice IRQ context.

    And as a side note, for frequent storage of data we generally recommend using  Flash Data Storage (FDS) to manage the storage. It helps limit the number of costly erase operations.

Related