NVS
Overview
Non-Volatile Storage (NVS) is a module that uses flash memory to store key-value pairs. This document will introduce some basic concepts of NVS.
Basic Principle
The NVS library uses part of the main flash memory by calling the wm_nvs API
API, specifically using the partition named “nvs” in the flash partition table to store data.
Note
NVS is best suited for storing smaller data. For larger data storage, consider using a file system.
Key-Value Pairs
NVS operates on key-value pairs, where the key is an ASCII
string with a maximum length of 15 characters. The stored values can be of the following types:
Integers:
uint8_t
,int8_t
,uint16_t
,int16_t
,uint32_t
,int32_t
,uint64_t
andint64_t
;Strings: Null-terminated strings
Binary data: Variable length binary data (BLOB)
Floating point:
double
type floating point numbers
Warning
When storing string data, the trailing \0
character is also stored, so the actual stored length is the length obtained by the strlen
function plus 1.
When retrieving a string, the buffer length should be one more than the actual number of characters, otherwise an invalid parameter error will be returned.
Note
Each flash sector is currently 4096 bytes. NVS storage cannot span sectors. By default, each sector has 20 bytes of header to mark the sector’s usage status, and each data item has a 24-byte header. Therefore, whether storing strings or binary data, their size cannot exceed 4052 bytes.
Note
Although NVS provides read and write for integers and floating points, it’s also possible to convert integers and floating points to strings for storage in the project.
Keys must be unique. Writing a new value to an existing key will replace the old value and its data type.
When reading a value, a data type check is performed. If the expected data type for the read operation does not match the data type of the corresponding key, an error is returned.
Grouping
NVS does not support grouping. If users need to group key-values, it’s suggested to add a group prefix to a set of keys, such as wifi.ssid. The iterator traversal interface supports prefix traversal, and specifying a prefix will retrieve all key-value pairs with that prefix.
NVS Iterator
Iterators allow traversing data in NVS. You can specify a key-value to retrieve or specify a prefix to retrieve a set of key-values. If not specified, all key-values will be traversed.
Use the following functions for related operations:
wm_nvs_entry_find
: Creates an opaque iterator handle and points the iterator to the first record, for subsequent calls towm_nvs_entry_next
,wm_nvs_entry_info
, andwm_nvs_entry_data
.wm_nvs_entry_next
: Points the iterator to the next key-value pair.wm_nvs_entry_info
: Returns information about the current key-value pair.wm_nvs_entry_data
: Returns the data of the current key-value pair.wm_nvs_release_iterator
: Releases the iterator handle.
In summary, all iterators obtained through wm_nvs_entry_find()
(including NULL iterators) must be released using wm_nvs_release_iterator()
.
Functional Implementation
To accommodate diverse user needs, we can implement multiple functions:
NVS Initialization:
wm_nvs_init
String Write and Read:
wm_nvs_set_str
,wm_nvs_get_str
Binary Data Write and Read:
wm_nvs_set_blob
,wm_nvs_get_blob
8-bit, 16-bit, 32-bit, 64-bit Integer Write and Read:
wm_nvs_set_i8
,wm_nvs_get_i8
wm_nvs_set_i16
,wm_nvs_get_i16
wm_nvs_set_i32
,wm_nvs_get_i32
wm_nvs_set_i64
,wm_nvs_get_i64
wm_nvs_set_u8
,wm_nvs_get_u8
wm_nvs_set_u16
,wm_nvs_get_u16
wm_nvs_set_u32
,wm_nvs_get_u32
wm_nvs_set_u64
,wm_nvs_get_u64
Floating Point Read and Write:
wm_nvs_set_float
,wm_nvs_get_float
Traverse NVS Data Items and Print:
wm_nvs_print
Get Data Item Type and Size:
wm_nvs_get_info
NVS Data Item Deletion:
wm_nvs_del
NVS Reset:
wm_nvs_reset
NVS Iteration Interface:
wm_nvs_entry_find
: Create iterator, point iterator to the first recordwm_nvs_entry_next
: Move to the next recordwm_nvs_entry_info
: Get key, type, and data length of record based on iteratorwm_nvs_entry_data
: Get data of record based on iteratorwm_nvs_release_iterator
: Release iteratorSupports Wear Leveling
Supports Power Failure Protection
Supports Hash Quick Read and Write
Note
After executing wm_nvs_reset
, the NVS partition will be formatted, and all stored data will be cleared. Use with caution.
Configuration Method
To adjust the NVS size in the project, adjust the partition named nvs
in the partition table. Both the starting address and size can be adjusted. Specific configuration is as follows:
# name, offset, size, flag
nvs, 0x1F0000, 0x8000, 0x0
For detailed configuration, refer to the partition table section.
Note
When the data is full, it needs to recycle deleted data. To prevent data loss due to power failure during the recycling process, a dedicated sector is needed for recycling. Therefore, the actual available space will be 4K less. The size should be configured to at least 2 sectors, i.e., at least 0x2000.
Module Configuration
- Hash Table Configuration
The hash table is created to speed up reading and writing. During initialization, the NVS storage partition is scanned, and an address offset table is established in memory. During read and write, the key is converted to an index by hash calculation, and the offset address of the key-value is directly obtained from the table, enabling fast value retrieval. The initial number of hash table entries is 53, which dynamically expands as the number of stored data entries increases. When the number of stored data entries exceeds 75%, the hash table length is dynamically expanded, adding about 50 entries each time. Each entry occupies 3 bytes. Disabling the hash table can save memory space roughly equal to the number of stored entries * 4, but at the cost of traversing each sector during read and write.
CONFIG_NVS_HASH_ENABLED can configure whether to use the hash table. By default, it is enabled. The hash table greatly improves read and write speed, so it is not recommended to disable it.
- Key Length Configuration
The key length is configured using CONFIG_NVS_ITEM_NAME_MAX_SIZE, with a default configuration of 16. Since the trailing 0 needs to be stored, the actual maximum supported string length is 15 characters. If a longer key name is needed in the project, this configuration can be increased.
Note
After modifying this key length configuration, historical stored data will be lost.
Application Examples
For details, refer to the project under /examples/storage/nvs/.