Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

fstorage_read and coordination with the Softdevice

nrf52832

SDK 14.2

NVMC and SD backend both

Hi,

I had a question about the nrf_fstorage_read function. In a previous answer, it was mentioned that fstorage_read function is blocking. I would like to know a few
more details about this:

Q1. It was mentioned: "Read operations are implemented using memcpy function, and will block until read is completed." What is meant by block here? If I call fstorage_read, will it really block the CPU
and no other instructions can be performed until the data is read?(even in the SoftDevice backend)

Q2. With the Softdevice backend, if I call fstorage_write, it will break the large write into smaller writes that will be coordinated between NVM and the Radio. Now if I call
fstorage_read when this coordination is going on, I could read NVM and then get interrupted to write to NVM and then come back again into the read. The data read could not be different from
the data in NVM?

Q3. fstorage_read by itself just calls memcpy and doesn't really do any coordination. It is not even queued. So can this be a problem? The smaller writes can occur during fstorage_read and we
could read data that is not actually the real data?

Thanks.

Parents
  • Hi,

    One thing one must understand is that the NVMC backend is synchronous and the SD is asynchronous. So if you use the NVMC backend, all your calls to read and write functions will be executed sequentially one after another. In other words, given this code:

    fstorage_write();
    fstorage_write();

    the call to fstorage_write() at line 1 will complete the entire write operation before your application can move on to the second line of code. 

    The SD backend on the other hand is asynchronous, meaning that given the code above, the call to fstorage_write() at line 1 completes immediately and leaves it up to the Softdevice to handle the write operation. When the operation completes you will get a NRF_FSTORAGE_WRITE_RESULT event returned from the Softdevice. If you call fstorage_write() twice one after another as in the code above, the first write operation will not be able to complete and you might run into trouble. What you need to do is to make sure that all fstorage operations are completed before you proceed with the next one. 

    fstorage_write();
    // Wait for the NRF_FSTORAGE_WRITE_RESULT 
    fstorage_write();

     

    The explanation above assumes that you are not starting any fstorage operations from interrupt contexts. If you an interrupt should happen to start an fstorage operation while another one is already in progress you will run into trouble again. As you say, it could e.g. lead to sections of data being overwritten while you are reading. To avoid this you should use a scheduler or flags in your interrupts to make sure to process all fstorage operations from your main context. 

    EDIT 22.03.2018: fstorage_write() instead of fstorage_read() for better example. 

Reply Children
  • Hi

    fstorage_read() was a bad example. The function is indeed always synchronous, is not being handled by the Softdevice, and does not produce any events. I should have used fstorage_write() as an example instead. I'm not sure why the NRF_FSTORAGE_EVT_READ_RESULT event is included in the SDK and documentation at all. I'll take it up with the SDK team. 

    Anyway, my point above regarding interrupt priorities and contexts still stands. Always make sure that your interrupts never start fstorage operations directly. You should rather make them schedule the operations to be executed in the main context after the interrupt is completed. 

  • Thanks Martin. I'll do that. But I had another question regarding your example about:

    fstorage_write()
    fstorage_write()

    You said the first write would not be able to complete if I call fstorage_write() like this one after another. But don't these fstorage_write() calls just get added into a queue and the SD/Fstorage takes care of them when it can?

    For example, if I call fstorage_write() it will go into the queue and then I call fstorage_write() again that will go into the queue as well. Fstorage/SD will complete these requests when it can. Waiting for the callback will only tell me when its complete.

    I thought if they are getting queued I don't need to wait till one gets complete
    and only then issue a second fstorage_write() request. I could call fstorage_write() one after another and as long as the queue is not full, these operations will get added into the queue
    and will be serviced when fstorage/sd decides. So why would waiting for one to complete before another fstorage_write() is called be an issue?

    Thank you for your help Martin!

  • It appears that my understanding of fstorage was poor, and my explanation above was only partially correct. My apologies. 

    You are right, of course. The fstorage write and erase operations are put in queue and executed sequentially. After each completed operation you will get an event in return. So contrary to what I said before, calling fstorage_write() twice right after one another is not a problem. Write and erase operations are still asynchronous though. And that can be a challenge when you also use the synchronous read operation. Going back to your initial questions:

    Q1) The read operation implements memcpy. The word blocking might be a bit misleading, but the point is that the read operation is synchronous. I.e. the entire read operation completes before the CPU moves on to the next task. Unless an interrupt occurs. As is the case with all other code, a read operation will be interrupted by higher priority interrupts. 

    Q2) Yes. Your read operations can get interrupted by write operations, and you risk reading garbage values. To avoid that it is your responsibility to make sure that there are no pending write operations before you start a read operation. You can check this using nrf_fstorage_is_busy() or control it yourself via the events you get in return.

Related