Storage Library
The Storage library provides abstractions for reading, writing, and erasing non-volatile memory (NVM).
Overview
The library supports multiple storage instances, each bound to a specific memory region, and reports operation results through user-defined event handlers. Depending on the backend and runtime state, operations may be synchronous or asynchronous.
Configuration
The library is enabled and configured entirely using the Kconfig system.
Set the CONFIG_BM_STORAGE Kconfig option to enable the library.
Select a storage backend by enabling one of the following Kconfig options:
CONFIG_BM_STORAGE_BACKEND_RRAM– RRAM backend. The events reported are synchronous.CONFIG_BM_STORAGE_BACKEND_SD– SoftDevice backend. The events reported are asynchronous.
The selected backend’s API instance is made available through the include/bm/storage/bm_storage_backends.h header, which is included transitively by include/bm/storage/bm_storage.h.
SoftDevice backend options:
CONFIG_BM_STORAGE_BACKEND_SD_QUEUE_SIZE– Queue size for pending operations.CONFIG_BM_STORAGE_BACKEND_SD_MAX_RETRIES– Maximum retries if the SoftDevice is busy.CONFIG_BM_STORAGE_BACKEND_SD_MAX_WRITE_SIZE- Maximum number of bytes to write in a single call tosd_flash_write().CONFIG_BM_STORAGE_BACKEND_SD_ERASE_BLOCKS– Batch erase operations up to_MAX_WRITE_SIZEbytes at once.
Initialization
Each storage instance is represented by a bm_storage structure.
To initialize a storage instance, use the bm_storage_init() function, providing a configuration struct bm_storage_config with the following information:
bm_storage_config.evt_handler– Event callback.bm_storage_config.api– Backend API implementation (for example,&bm_storage_sd_apior&bm_storage_rram_api).bm_storage_config.addrandbm_storage_config.size– Partition starting address and size.
The following example shows how to initialize a storage instance with a backend API:
#include <bm/storage/bm_storage.h>
struct bm_storage storage;
struct bm_storage_config config = {
.evt_handler = my_handler,
.api = &bm_storage_sd_api,
.addr = PARTITION_ADDR,
.size = PARTITION_SIZE,
};
bm_storage_init(&storage, &config);
All read, write, and erase operations use offsets relative to the partition start (0-based).
You can uninitialize a storage instance with the bm_storage_uninit() function.
Usage
The following is a list of operations you can perform with this library.
Read
Use the bm_storage_read() function to copy data from NVM into RAM.
Write
Use the bm_storage_write() function to write data to NVM.
The completion of the operation is reported by the BM_STORAGE_EVT_WRITE_RESULT event.
Note
The program unit is the minimum programmable block in NVM. Write operations must start at an address aligned by the program unit and use a length that is a multiple of this value.
If bm_storage_config.is_wear_aligned is set during initialization, the wear unit (bm_storage_info.wear_unit) is used for alignment instead.
If bm_storage_config.is_write_padded is set during initialization, write operations are automatically padded to the chosen alignment unit (either the program or wear unit).
Erase
Use the bm_storage_erase() function to erase a region in NVM.
The completion of the operation is reported by the BM_STORAGE_EVT_ERASE_RESULT event.
Note
The erase unit is the minimum erasable block in NVM.
Erase operations must start at an address aligned by the erase unit and use a length that is a multiple of this value.
The erase unit is reported by bm_storage_info.erase_unit.
When the erase operation is not supported by the hardware, the backend will emulate it by writing the memory’s erased value to the NVM area. If the erase operation is emulated, the alignment requirements are the same as those for the write operation.
Busy state
Use the bm_storage_is_busy() function to check whether a backend is executing an operation.
Events
The following events may be reported to the user callback:
BM_STORAGE_EVT_WRITE_RESULT– Write operation completed.BM_STORAGE_EVT_ERASE_RESULT– Erase operation completed.
Each event includes the result code, information about the address range of the associated operation, and whether the operation is synchronous or asynchronous.
Event deferral
Backends that do not have an internal operation queue (for example, the RRAM backend) deliver events synchronously from the same call context as the caller. If the application queues another storage operation from within its event handler, unbounded recursion can occur.
Backends with an internal operation queue (for example, the SoftDevice backend) are not affected, because re-entrant calls are enqueued and processed iteratively.
To prevent recursion in backends without a queue, enable the CONFIG_BM_SCHEDULER Kconfig option.
When the scheduler is available, synchronous events are automatically deferred and delivered from the main thread context on the next call to bm_scheduler_process().
Deferred events have their bm_storage_evt.is_async field set to true.
Sample
The usage of this library is demonstrated in the Bare Metal Storage sample.
Dependencies
CONFIG_BM_STORAGE_BACKEND_RRAM:This backend requires the following Kconfig options to be disabled:
-
This backend requires the following Kconfig options to be enabled:
Optional dependencies:
CONFIG_BM_SCHEDULER– Enables deferral of synchronous events to the main thread context. See Event deferral.
API documentation
include/bm/storage/bm_storage.hinclude/bm/storage/bm_storage_backends.hlib/bm_storage/