blob: 81a7c4325a7c39efaf22081f17fbc1274fc025ed [file] [log] [blame]
.. _nvs:
Non-volatile storage (NVS) for Zephyr
#####################################
Elements, represented as id-data pairs, are stored in flash using a
FIFO-managed circular buffer. The flash area is divided into sectors. Elements
are appended to a sector until storage space in the sector is exhausted. Then a
new sector in the flash area is prepared for use (erased). Before erasing the
sector it is checked that identifier - data pairs exist in the sectors in use,
if not the id-data pair is copied.
The id is a 16-bit unsigned number, where two values are reserved:
- ``0xFFFF`` is used to determine free locations in flash
- ``0xFFFE`` is used to close a sector
NVS ensures that for each id there is at least one id-data pair stored in flash
at all time.
NVS allows storage of binary blobs, strings, integers, longs, and any
combination of these. As each element is stored with a header (containing the
id and length) and a footer (containing the crc16) it is less suited to store
only integers.
NVS has a configuration option to enable extra flash protection
(``CONFIG_NVS_FLASH_PROTECTION=y``), when selected NVS does a extra check
before writing data to flash. If the id-data pair is unchanged no write to
flash is performed. The down-side of this protection is that NVS needs to read
the storage system to check if the id-data pair is unchanged. If you are
already performing such a check you can disable the extra flash protection
(``CONFIG_NVS_FLASH_PROTECTION=n``).
To protect the storage system against frequent sector erases the size of
id-data pairs is limited to ``CONFIG_NVS_MAX_ELEM_SIZE``. This limit is by default set to 1/4 of the sector
size.
For NVS the file system is declared as:
.. code-block:: c
static struct nvs_fs fs = {
.sector_size = NVS_SECTOR_SIZE,
.sector_count = NVS_SECTOR_COUNT,
.offset = NVS_STORAGE_OFFSET,
.max_len = NVS_MAX_ELEM_SIZE,
};
where
- ``NVS_SECTOR_SIZE`` is the sector size, it has to be a multiple of
the flash erase page size and a power of 2.
- ``NVS_SECTOR_COUNT`` is the number of sectors, it is at least 2, one
sector is always kept empty to allow copying of existing data.
- ``NVS_STORAGE_OFFSET`` is the offset of the storage area in flash.
- ``NVS_MAX_ELEM_SIZE`` is the maximum item size.
Flash wear
**********
When writing data to flash a study of the flash wear is important. Flash has a
limited life which is determined by the number of times flash can be erased.
Flash is erased one page at a time and the pagesize is determined by the
hardware. As an example a nRF51822 device has a pagesize of 1024 bytes and each
page can be erased about 20,000 times.
Calculating expected device lifetime
====================================
Suppose we use a 4 bytes state variable that is changed every minute and
needs to be restored after reboot. NVS has been defined with a sector_size
equal to the pagesize (1024 bytes) and 2 sectors have been defined. Each
sector in NVS has a sector header of 8 bytes.
Each write of the state variable requires 4 bytes for the variable, but also 4
bytes for the data header and 4 bytes for the data slot, so in total 12 bytes.
When storing the data the first sector will be full after (1024-8)/12 = 84
minutes. After another 84 minutes, the second sector is full. When this
happens, because we're using only two sectors, the first sector will be used
for storage and will be erased after 168 minutes of system time. With the
expected device life of 20,000 writes, with two sectors writing every 168
minutes, the device should last about 168*20,000 minutes, or about 6.5 years.
More generally then, with
- ``NS`` as the number of storage requests per minute,
- ``DS`` as the data size in bytes,
- ``SECTOR_SIZE`` in bytes, and
- ``PAGE_ERASES`` as the number of times the page can be erased,
the expected device life (in minutes) can be calculated as::
SECTOR_COUNT * (SECTOR_SIZE-8) * PAGE_ERASES / (NS * (DS+8)) minutes
From this formula it is also clear what to do in case the expected life is too
short: increase ``SECTOR_COUNT`` or ``SECTOR_SIZE``.
Sample
******
A sample of how NVS can be used is supplied in ``samples/subsys/nvs``.
API
**************
The NVS subsystem APIs are provided by ``nvs.h``:
.. doxygengroup:: nvs
:project: Zephyr