+--------+ +--------+ +--------+ +--------+
| Page 1 | | Page 2 | | Page 3 | | Page 4 |
| Full +---> | Full +---> | Active | | Empty | <- 状态
| #11 | | #12 | | #14 | | | <- 序列号
+---+----+ +----+---+ +----+---+ +---+----+
| | | |
| | | |
| | | |
+---v------+ +-----v----+ +------v---+ +------v---+
| Sector 3 | | Sector 0 | | Sector 2 | | Sector 1 | <- 物理扇区
+----------+ +----------+ +----------+ +----------+
页面结构
当前,我们假设 flash 扇区大小为 4096 字节,并且 ESP32 flash 加密硬件在 32 字节块上运行。未来有可能引入一些编译时可配置项(可通过 menuconfig 进行配置),以适配具有不同扇区大小的 flash 芯片。但目前尚不清楚 SPI flash 驱动和 SPI flash cache 之类的系统组件是否支持其他扇区大小。
页面由头部、条目状态位图和条目三部分组成。为了实现与 ESP32 flash 加密功能兼容,条目大小设置为 32 字节。如果键值为整数型,条目则保存一个键值对;如果键值为字符串或 BLOB 类型,则条目仅保存一个键值对的部分内容(更多信息详见条目结构描述)。
页面结构如下图所示,括号内数字表示该部分的大小(以字节为单位)。
+-----------+--------------+-------------+-------------------------+
| State (4) | Seq. no. (4) | version (1) | Unused (19) | CRC32 (4) | 页头部 (32)
+-----------+--------------+-------------+-------------------------+
| Entry state bitmap (32) |
+------------------------------------------------------------------+
| Entry 0 (32) |
+------------------------------------------------------------------+
| Entry 1 (32) |
+------------------------------------------------------------------+
+------------------------------------------------------------------+
| Entry 125 (32) |
+------------------------------------------------------------------+
头部和条目状态位图写入 flash 时不加密。如果启用了 ESP32 flash 加密功能,则条目写入 flash 时将会加密。
通过将 0 写入某些位可以定义页面状态值,表示状态改变。因此,如果需要变更页面状态,并不一定要擦除页面,除非要将其变更为 擦除 状态。
头部中的 version
字段反映了所用的 NVS 格式版本。为实现向后兼容,版本升级从 0xff 开始依次递减(例如,version-1 为 0xff,version-2 为 0xfe,以此类推)。
头部中 CRC32 值是由不包含状态值的条目计算所得(4 到 28 字节)。当前未使用的条目用 0xff
字节填充。
条目结构和条目状态位图的详细信息见下文描述。
条目和条目状态位图
每个条目可处于以下三种状态之一,每个状态在条目状态位图中用两位表示。位图中的最后四位 (256 - 2 * 126) 未使用。
空 (2'b11)条目还未写入任何内容,处于未初始化状态(全部字节为 0xff
)。
写入(2'b10)一个键值对(或跨多个条目的键值对的部分内容)已写入条目中。
擦除(2'b00)条目中的键值对已丢弃,条目内容不再解析。
条目结构
如果键值类型为基础类型,即 1 - 8 个字节长度的整数型,条目将保存一个键值对;如果键值类型为字符串或 BLOB 类型,条目将保存整个键值对的部分内容。另外,如果键值为字符串类型且跨多个条目,则键值所跨的所有条目均保存在同一页面。BLOB 则可以切分为多个块,实现跨多个页面。BLOB 索引是一个附加的固定长度元数据条目,用于追踪 BLOB 块。目前条目仍支持早期 BLOB 格式(可读取可修改),但这些 BLOB 一经修改,即以新格式储存至条目。
+--------+----------+----------+----------------+-----------+---------------+----------+
| NS (1) | Type (1) | Span (1) | ChunkIndex (1) | CRC32 (4) | Key (16) | Data (8) |
+--------+----------+----------+----------------+-----------+---------------+----------+
Primitive +--------------------------------+
+--------> | Data (8) |
| Types +--------------------------------+
+-> Fixed length --
| | +---------+--------------+---------------+-------+
| +--------> | Size(4) | ChunkCount(1)| ChunkStart(1) | Rsv(2)|
Data format ---+ BLOB Index +---------+--------------+---------------+-------+
| +----------+---------+-----------+
+-> Variable length --> | Size (2) | Rsv (2) | CRC32 (4) |
(Strings, BLOB Data) +----------+---------+-----------+
条目结构中各个字段含义如下:
命名空间 (NS, NameSpace)该条目的命名空间索引,详细信息参见命名空间实现章节。
类型 (Type)一个字节表示的值的数据类型,nvs_flash/include/nvs_handle.hpp 下的 ItemType
枚举了可能的类型。
跨度 (Span)该键值对所用的条目数量。如果键值为整数型,条目数量即为 1。如果键值为字符串或 BLOB,则条目数量取决于值的长度。
块索引 (ChunkIndex)用于存储 BLOB 类型数据块的索引。如果键值为其他数据类型,则此处索引应写入 0xff
。
CRC32对条目下所有字节进行校验后,所得的校验和(CRC32 字段不计算在内)。
键 (Key)即以零结尾的 ASCII 字符串,字符串最长为 15 字节,不包含最后一个字节的零终止符。
数据 (Data)如果键值类型为整数型,则数据字段仅包含键值。如果键值小于八个字节,使用 0xff
填充未使用的部分(右侧)。
如果键值类型为 BLOB 索引条目,则该字段的八个字节将保存以下数据块信息:
块大小整个 BLOB 数据的大小(以字节为单位)。该字段仅用于 BLOB 索引类型条目。
命名空间
如上所述,每个键值对属于一个命名空间。命名空间标识符(字符串)也作为键值对的键,存储在索引为 0 的命名空间中。与这些键对应的值就是这些命名空间的索引。
+-------------------------------------------+
| NS=0 Type=uint8_t Key="wifi" Value=1 | Entry describing namespace "wifi"
+-------------------------------------------+
| NS=1 Type=uint32_t Key="channel" Value=6 | Key "channel" in namespace "wifi"
+-------------------------------------------+
| NS=0 Type=uint8_t Key="pwm" Value=2 | Entry describing namespace "pwm"
+-------------------------------------------+
| NS=2 Type=uint16_t Key="channel" Value=20 | Key "channel" in namespace "pwm"
+-------------------------------------------+
条目哈希列表
为了减少对 flash 执行的读操作次数,Page 类对象均设有一个列表,包含一对数据:条目索引和条目哈希值。该列表可大大提高检索速度,而无需迭代所有条目并逐个从 flash 中读取。Page::findItem
首先从哈希列表中检索条目哈希值,如果条目存在,则在页面内给出条目索引。由于哈希冲突,在哈希列表中检索条目哈希值可能会得到不同的条目,对 flash 中条目再次迭代可解决这一冲突。
哈希列表中每个节点均包含一个 24 位哈希值和 8 位条目索引。哈希值根据条目命名空间、键名和块索引由 CRC32 计算所得,计算结果保留 24 位。为减少将 32 位条目存储在链表中的开销,链表采用了数组的双向链表。每个数组占用 128 个字节,包含 29 个条目、两个链表指针和一个 32 位计数字段。因此,每页额外需要的 RAM 最少为 128 字节,最多为 640 字节。
API 参考
Header File
components/nvs_flash/include/nvs_flash.h
This header file can be included with:
#include "nvs_flash.h"
This header file is a part of the API provided by the nvs_flash
component. To declare that your component depends on nvs_flash
, add the following to your CMakeLists.txt:
REQUIRES nvs_flash
PRIV_REQUIRES nvs_flash
esp_err_t nvs_flash_init(void)
Initialize the default NVS partition.
This API initialises the default NVS partition. The default NVS partition is the one that is labeled "nvs" in the partition table.
When "NVS_ENCRYPTION" is enabled in the menuconfig, this API enables the NVS encryption for the default NVS partition as follows
Read security configurations from the first NVS key partition listed in the partition table. (NVS key partition is any "data" type partition which has the subtype value set to "nvs_keys")
If the NVS key partiton obtained in the previous step is empty, generate and store new keys in that NVS key partiton.
Internally call "nvs_flash_secure_init()" with the security configurations obtained/generated in the previous steps.
Post initialization NVS read/write APIs remain the same irrespective of NVS encryption.
ESP_OK if storage was successfully initialized.
ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages (which may happen if NVS partition was truncated)
ESP_ERR_NOT_FOUND if no partition with label "nvs" is found in the partition table
ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures
one of the error codes from the underlying flash storage driver
error codes from nvs_flash_read_security_cfg API (when "NVS_ENCRYPTION" is enabled).
error codes from nvs_flash_generate_keys API (when "NVS_ENCRYPTION" is enabled).
error codes from nvs_flash_secure_init_partition API (when "NVS_ENCRYPTION" is enabled) .
esp_err_t nvs_flash_init_partition(const char *partition_label)
Initialize NVS flash storage for the specified partition.
partition_label -- [in] Label of the partition. Must be no longer than 16 characters.
ESP_OK if storage was successfully initialized.
ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages (which may happen if NVS partition was truncated)
ESP_ERR_NOT_FOUND if specified partition is not found in the partition table
ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures
one of the error codes from the underlying flash storage driver
esp_err_t nvs_flash_init_partition_ptr(const esp_partition_t *partition)
Initialize NVS flash storage for the partition specified by partition pointer.
partition -- [in] pointer to a partition obtained by the ESP partition API.
ESP_OK if storage was successfully initialized
ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages (which may happen if NVS partition was truncated)
ESP_ERR_INVALID_ARG in case partition is NULL
ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures
one of the error codes from the underlying flash storage driver
esp_err_t nvs_flash_deinit(void)
Deinitialize NVS storage for the default NVS partition.
Default NVS partition is the partition with "nvs" label in the partition table.
ESP_OK on success (storage was deinitialized)
ESP_ERR_NVS_NOT_INITIALIZED if the storage was not initialized prior to this call
esp_err_t nvs_flash_deinit_partition(const char *partition_label)
Deinitialize NVS storage for the given NVS partition.
partition_label -- [in] Label of the partition
ESP_OK on success
ESP_ERR_NVS_NOT_INITIALIZED if the storage for given partition was not initialized prior to this call
esp_err_t nvs_flash_erase(void)
Erase the default NVS partition.
Erases all contents of the default NVS partition (one with label "nvs").
If the partition is initialized, this function first de-initializes it. Afterwards, the partition has to be initialized again to be used.
ESP_OK on success
ESP_ERR_NOT_FOUND if there is no NVS partition labeled "nvs" in the partition table
different error in case de-initialization fails (shouldn't happen)
esp_err_t nvs_flash_erase_partition(const char *part_name)
Erase specified NVS partition.
Erase all content of a specified NVS partition
If the partition is initialized, this function first de-initializes it. Afterwards, the partition has to be initialized again to be used.
part_name -- [in] Name (label) of the partition which should be erased
ESP_OK on success
ESP_ERR_NOT_FOUND if there is no NVS partition with the specified name in the partition table
different error in case de-initialization fails (shouldn't happen)
esp_err_t nvs_flash_erase_partition_ptr(const esp_partition_t *partition)
Erase custom partition.
Erase all content of specified custom partition.
If the partition is initialized, this function first de-initializes it. Afterwards, the partition has to be initialized again to be used.
partition -- [in] pointer to a partition obtained by the ESP partition API.
ESP_OK on success
ESP_ERR_NOT_FOUND if there is no partition with the specified parameters in the partition table
ESP_ERR_INVALID_ARG in case partition is NULL
one of the error codes from the underlying flash storage driver
esp_err_t nvs_flash_secure_init(nvs_sec_cfg_t *cfg)
Initialize the default NVS partition.
This API initialises the default NVS partition. The default NVS partition is the one that is labeled "nvs" in the partition table.
cfg -- [in] Security configuration (keys) to be used for NVS encryption/decryption. If cfg is NULL, no encryption is used.
ESP_OK if storage has been initialized successfully.
ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages (which may happen if NVS partition was truncated)
ESP_ERR_NOT_FOUND if no partition with label "nvs" is found in the partition table
ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures
one of the error codes from the underlying flash storage driver
esp_err_t nvs_flash_secure_init_partition(const char *partition_label, nvs_sec_cfg_t *cfg)
Initialize NVS flash storage for the specified partition.
partition_label -- [in] Label of the partition. Note that internally, a reference to passed value is kept and it should be accessible for future operations
cfg -- [in] Security configuration (keys) to be used for NVS encryption/decryption. If cfg is null, no encryption/decryption is used.
ESP_OK if storage has been initialized successfully.
ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages (which may happen if NVS partition was truncated)
ESP_ERR_NOT_FOUND if specified partition is not found in the partition table
ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures
one of the error codes from the underlying flash storage driver
esp_err_t nvs_flash_generate_keys(const esp_partition_t *partition, nvs_sec_cfg_t *cfg)
Generate and store NVS keys in the provided esp partition.
partition -- [in] Pointer to partition structure obtained using esp_partition_find_first or esp_partition_get. Must be non-NULL.
cfg -- [out] Pointer to nvs security configuration structure. Pointer must be non-NULL. Generated keys will be populated in this structure.
ESP_OK, if cfg was read successfully;
ESP_ERR_INVALID_ARG, if partition or cfg is NULL;
or error codes from esp_partition_write/erase APIs.
esp_err_t nvs_flash_read_security_cfg(const esp_partition_t *partition, nvs_sec_cfg_t *cfg)
Read NVS security configuration from a partition.
Provided partition is assumed to be marked 'encrypted'.
partition -- [in] Pointer to partition structure obtained using esp_partition_find_first or esp_partition_get. Must be non-NULL.
cfg -- [out] Pointer to nvs security configuration structure. Pointer must be non-NULL.
ESP_OK, if cfg was read successfully;
ESP_ERR_INVALID_ARG, if partition or cfg is NULL
ESP_ERR_NVS_KEYS_NOT_INITIALIZED, if the partition is not yet written with keys.
ESP_ERR_NVS_CORRUPT_KEY_PART, if the partition containing keys is found to be corrupt
or error codes from esp_partition_read API.
esp_err_t nvs_flash_register_security_scheme(nvs_sec_scheme_t *scheme_cfg)
Registers the given security scheme for NVS encryption The scheme registered with sec_scheme_id by this API be used as the default security scheme for the "nvs" partition. Users will have to call this API explicitly in their application.
scheme_cfg -- [in] Pointer to the security scheme configuration structure that the user (or the nvs_key_provider) wants to register.
ESP_OK, if security scheme registration succeeds;
ESP_ERR_INVALID_ARG, if scheme_cfg is NULL;
ESP_FAIL, if security scheme registration fails
nvs_sec_scheme_t *nvs_flash_get_default_security_scheme(void)
Fetch the configuration structure for the default active security scheme for NVS encryption.
Pointer to the default active security scheme configuration (NULL if no scheme is registered yet i.e. active)
esp_err_t nvs_flash_generate_keys_v2(nvs_sec_scheme_t *scheme_cfg, nvs_sec_cfg_t *cfg)
Generate (and store) the NVS keys using the specified key-protection scheme.
scheme_cfg -- [in] Security scheme specific configuration
cfg -- [out] Security configuration (encryption keys)
ESP_OK, if cfg was populated successfully with generated encryption keys;
ESP_ERR_INVALID_ARG, if scheme_cfg or cfg is NULL;
ESP_FAIL, if the key generation process fails
esp_err_t nvs_flash_read_security_cfg_v2(nvs_sec_scheme_t *scheme_cfg, nvs_sec_cfg_t *cfg)
Read NVS security configuration set by the specified security scheme.
scheme_cfg -- [in] Security scheme specific configuration
cfg -- [out] Security configuration (encryption keys)
ESP_OK, if cfg was read successfully;
ESP_ERR_INVALID_ARG, if scheme_cfg or cfg is NULL;
ESP_FAIL, if the key reading process fails
typedef esp_err_t (*nvs_flash_generate_keys_t)(const void *scheme_data, nvs_sec_cfg_t *cfg)
Callback function prototype for generating the NVS encryption keys.
typedef esp_err_t (*nvs_flash_read_cfg_t)(const void *scheme_data, nvs_sec_cfg_t *cfg)
Callback function prototype for reading the NVS encryption keys.
This header file is a part of the API provided by the nvs_flash
component. To declare that your component depends on nvs_flash
, add the following to your CMakeLists.txt:
REQUIRES nvs_flash
PRIV_REQUIRES nvs_flash
esp_err_t nvs_set_i8(nvs_handle_t handle, const char *key, int8_t value)
set int8_t value for given key
Set value for the key, given its name. Note that the actual storage will not be updated until nvs_commit
is called. Regardless whether key-value pair is created or updated, function always requires at least one nvs available entry. See nvs_get_stats
. After create type of operation, the number of available entries is decreased by one. After update type of operation, the number of available entries remains the same.
handle -- [in] Handle obtained from nvs_open function. Handles that were opened read only cannot be used.
key -- [in] Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
value -- [in] The value to set.
ESP_OK if value was set successfully
ESP_FAIL if there is an internal error; most likely due to corrupted NVS partition (only if NVS assertion checks are disabled)
ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only
ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the underlying storage to save the value
ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn't fail again.
esp_err_t nvs_set_u8(nvs_handle_t handle, const char *key, uint8_t value)
set uint8_t value for given key
This function is the same as nvs_set_i8
except for the data type.
esp_err_t nvs_set_i16(nvs_handle_t handle, const char *key, int16_t value)
set int16_t value for given key
This function is the same as nvs_set_i8
except for the data type.
esp_err_t nvs_set_u16(nvs_handle_t handle, const char *key, uint16_t value)
set uint16_t value for given key
This function is the same as nvs_set_i8
except for the data type.
esp_err_t nvs_set_i32(nvs_handle_t handle, const char *key, int32_t value)
set int32_t value for given key
This function is the same as nvs_set_i8
except for the data type.
esp_err_t nvs_set_u32(nvs_handle_t handle, const char *key, uint32_t value)
set uint32_t value for given key
This function is the same as nvs_set_i8
except for the data type.
esp_err_t nvs_set_i64(nvs_handle_t handle, const char *key, int64_t value)
set int64_t value for given key
This function is the same as nvs_set_i8
except for the data type.
esp_err_t nvs_set_u64(nvs_handle_t handle, const char *key, uint64_t value)
set uint64_t value for given key
This function is the same as nvs_set_i8
except for the data type.
esp_err_t nvs_set_str(nvs_handle_t handle, const char *key, const char *value)
set string for given key
Sets string value for the key. Function requires whole space for new data to be available as contiguous entries in same nvs page. Operation consumes 1 overhead entry and 1 entry per each 32 characters of new string including zero character to be set. In case of value update for existing key, entries occupied by the previous value and overhead entry are returned to the pool of available entries. Note that storage of long string values can fail due to fragmentation of nvs pages even if available_entries
returned by nvs_get_stats
suggests enough overall space available. Note that the underlying storage will not be updated until nvs_commit
is called.
handle -- [in] Handle obtained from nvs_open function. Handles that were opened read only cannot be used.
key -- [in] Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
value -- [in] The value to set. For strings, the maximum length (including null character) is 4000 bytes, if there is one complete page free for writing. This decreases, however, if the free space is fragmented.
ESP_OK if value was set successfully
ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only
ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the underlying storage to save the value
ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn't fail again.
ESP_ERR_NVS_VALUE_TOO_LONG if the string value is too long
esp_err_t nvs_get_i8(nvs_handle_t handle, const char *key, int8_t *out_value)
get int8_t value for given key
These functions retrieve value for the key, given its name. If key
does not exist, or the requested variable type doesn't match the type which was used when setting a value, an error is returned.
In case of any error, out_value is not modified.
out_value
has to be a pointer to an already allocated variable of the given type.
// Example of using nvs_get_i32:
int32_t max_buffer_size = 4096; // default value
esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size);
assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND);
// if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still
// have its default value.
handle -- [in] Handle obtained from nvs_open function.
key -- [in] Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
out_value -- Pointer to the output value. May be NULL for nvs_get_str and nvs_get_blob, in this case required length will be returned in length argument.
ESP_OK if the value was retrieved successfully
ESP_FAIL if there is an internal error; most likely due to corrupted NVS partition (only if NVS assertion checks are disabled)
ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data
esp_err_t nvs_get_u8(nvs_handle_t handle, const char *key, uint8_t *out_value)
get uint8_t value for given key
This function is the same as nvs_get_i8
except for the data type.
esp_err_t nvs_get_i16(nvs_handle_t handle, const char *key, int16_t *out_value)
get int16_t value for given key
This function is the same as nvs_get_i8
except for the data type.
esp_err_t nvs_get_u16(nvs_handle_t handle, const char *key, uint16_t *out_value)
get uint16_t value for given key
This function is the same as nvs_get_i8
except for the data type.
esp_err_t nvs_get_i32(nvs_handle_t handle, const char *key, int32_t *out_value)
get int32_t value for given key
This function is the same as nvs_get_i8
except for the data type.
esp_err_t nvs_get_u32(nvs_handle_t handle, const char *key, uint32_t *out_value)
get uint32_t value for given key
This function is the same as nvs_get_i8
except for the data type.
esp_err_t nvs_get_i64(nvs_handle_t handle, const char *key, int64_t *out_value)
get int64_t value for given key
This function is the same as nvs_get_i8
except for the data type.
esp_err_t nvs_get_u64(nvs_handle_t handle, const char *key, uint64_t *out_value)
get uint64_t value for given key
This function is the same as nvs_get_i8
except for the data type.
esp_err_t nvs_get_str(nvs_handle_t handle, const char *key, char *out_value, size_t *length)
get string value for given key
These functions retrieve the data of an entry, given its key. If key does not exist, or the requested variable type doesn't match the type which was used when setting a value, an error is returned.
In case of any error, out_value is not modified.
All functions expect out_value to be a pointer to an already allocated variable of the given type.
nvs_get_str and nvs_get_blob functions support WinAPI-style length queries. To get the size necessary to store the value, call nvs_get_str or nvs_get_blob with zero out_value and non-zero pointer to length. Variable pointed to by length argument will be set to the required length. For nvs_get_str, this length includes the zero terminator. When calling nvs_get_str and nvs_get_blob with non-zero out_value, length has to be non-zero and has to point to the length available in out_value. It is suggested that nvs_get/set_str is used for zero-terminated C strings, and nvs_get/set_blob used for arbitrary data structures.
// Example (without error checking) of using nvs_get_str to get a string into dynamic array:
size_t required_size;
nvs_get_str(my_handle, "server_name", NULL, &required_size);
char* server_name = malloc(required_size);
nvs_get_str(my_handle, "server_name", server_name, &required_size);
// Example (without error checking) of using nvs_get_blob to get a binary data
into a static array:
uint8_t mac_addr[6];
size_t size = sizeof(mac_addr);
nvs_get_blob(my_handle, "dst_mac_addr", mac_addr, &size);
handle -- [in] Handle obtained from nvs_open function.
key -- [in] Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
out_value -- [out] Pointer to the output value. May be NULL for nvs_get_str and nvs_get_blob, in this case required length will be returned in length argument.
length -- [inout] A non-zero pointer to the variable holding the length of out_value. In case out_value a zero, will be set to the length required to hold the value. In case out_value is not zero, will be set to the actual length of the value written. For nvs_get_str this includes zero terminator.
ESP_OK if the value was retrieved successfully
ESP_FAIL if there is an internal error; most likely due to corrupted NVS partition (only if NVS assertion checks are disabled)
ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
ESP_ERR_NVS_INVALID_LENGTH if length
is not sufficient to store data
esp_err_t nvs_get_blob(nvs_handle_t handle, const char *key, void *out_value, size_t *length)
get blob value for given key
This function behaves the same as nvs_get_str
, except for the data type.
esp_err_t nvs_open(const char *namespace_name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle)
Open non-volatile storage with a given namespace from the default NVS partition.
Multiple internal ESP-IDF and third party application modules can store their key-value pairs in the NVS module. In order to reduce possible conflicts on key names, each module can use its own namespace. The default NVS partition is the one that is labelled "nvs" in the partition table.
namespace_name -- [in] Namespace name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
open_mode -- [in] NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will open a handle for reading only. All write requests will be rejected for this handle.
out_handle -- [out] If successful (return code is zero), handle will be returned in this argument.
ESP_OK if storage handle was opened successfully
ESP_FAIL if there is an internal error; most likely due to corrupted NVS partition (only if NVS assertion checks are disabled)
ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized
ESP_ERR_NVS_PART_NOT_FOUND if the partition with label "nvs" is not found
ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and mode is NVS_READONLY
ESP_ERR_NVS_INVALID_NAME if namespace name doesn't satisfy constraints
ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures
ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is no space for a new entry or there are too many different namespaces (maximum allowed different namespaces: 254)
ESP_ERR_NOT_ALLOWED if the NVS partition is read-only and mode is NVS_READWRITE
ESP_ERR_INVALID_ARG if out_handle is equal to NULL
other error codes from the underlying storage driver
esp_err_t nvs_open_from_partition(const char *part_name, const char *namespace_name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle)
Open non-volatile storage with a given namespace from specified partition.
The behaviour is same as nvs_open() API. However this API can operate on a specified NVS partition instead of default NVS partition. Note that the specified partition must be registered with NVS using nvs_flash_init_partition() API.
part_name -- [in] Label (name) of the partition of interest for object read/write/erase
namespace_name -- [in] Namespace name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
open_mode -- [in] NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will open a handle for reading only. All write requests will be rejected for this handle.
out_handle -- [out] If successful (return code is zero), handle will be returned in this argument.
ESP_OK if storage handle was opened successfully
ESP_FAIL if there is an internal error; most likely due to corrupted NVS partition (only if NVS assertion checks are disabled)
ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized
ESP_ERR_NVS_PART_NOT_FOUND if the partition with specified name is not found
ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and mode is NVS_READONLY
ESP_ERR_NVS_INVALID_NAME if namespace name doesn't satisfy constraints
ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures
ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is no space for a new entry or there are too many different namespaces (maximum allowed different namespaces: 254)
ESP_ERR_NOT_ALLOWED if the NVS partition is read-only and mode is NVS_READWRITE
ESP_ERR_INVALID_ARG if out_handle is equal to NULL
other error codes from the underlying storage driver
esp_err_t nvs_set_blob(nvs_handle_t handle, const char *key, const void *value, size_t length)
set variable length binary value for given key
Sets variable length binary value for the key. Function uses 2 overhead and 1 entry per each 32 bytes of new data from the pool of available entries. See nvs_get_stats
. In case of value update for existing key, space occupied by the existing value and 2 overhead entries are returned to the pool of available entries. Note that the underlying storage will not be updated until nvs_commit
is called.
handle -- [in] Handle obtained from nvs_open function. Handles that were opened read only cannot be used.
key -- [in] Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
value -- [in] The value to set.
length -- [in] length of binary value to set, in bytes; Maximum length is 508000 bytes or (97.6% of the partition size - 4000) bytes whichever is lower.
ESP_OK if value was set successfully
ESP_FAIL if there is an internal error; most likely due to corrupted NVS partition (only if NVS assertion checks are disabled)
ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only
ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the underlying storage to save the value
ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn't fail again.
ESP_ERR_NVS_VALUE_TOO_LONG if the value is too long
esp_err_t nvs_find_key(nvs_handle_t handle, const char *key, nvs_type_t *out_type)
Lookup key-value pair with given key name.
Note that function may indicate both existence of the key as well as the data type of NVS entry if it is found.
handle -- [in] Storage handle obtained with nvs_open.
key -- [in] Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
out_type -- [out] Pointer to the output variable populated with data type of NVS entry in case key was found. May be NULL, respective data type is then not provided.
ESP_OK if NVS entry for key provided was found
ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
ESP_FAIL if there is an internal error; most likely due to corrupted NVS partition (only if NVS assertion checks are disabled)
other error codes from the underlying storage driver
esp_err_t nvs_erase_key(nvs_handle_t handle, const char *key)
Erase key-value pair with given key name.
Note that actual storage may not be updated until nvs_commit function is called.
handle -- [in] Storage handle obtained with nvs_open. Handles that were opened read only cannot be used.
key -- [in] Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
ESP_OK if erase operation was successful
ESP_FAIL if there is an internal error; most likely due to corrupted NVS partition (only if NVS assertion checks are disabled)
ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
ESP_ERR_NVS_READ_ONLY if handle was opened as read only
ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
other error codes from the underlying storage driver
esp_err_t nvs_erase_all(nvs_handle_t handle)
Erase all key-value pairs in a namespace.
Note that actual storage may not be updated until nvs_commit function is called.
handle -- [in] Storage handle obtained with nvs_open. Handles that were opened read only cannot be used.
ESP_OK if erase operation was successful
ESP_FAIL if there is an internal error; most likely due to corrupted NVS partition (only if NVS assertion checks are disabled)
ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
ESP_ERR_NVS_READ_ONLY if handle was opened as read only
other error codes from the underlying storage driver
esp_err_t nvs_commit(nvs_handle_t handle)
Write any pending changes to non-volatile storage.
After setting any values, nvs_commit() must be called to ensure changes are written to non-volatile storage. Individual implementations may write to storage at other times, but this is not guaranteed.
handle -- [in] Storage handle obtained with nvs_open. Handles that were opened read only cannot be used.
ESP_OK if the changes have been written successfully
ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
other error codes from the underlying storage driver
void nvs_close(nvs_handle_t handle)
Close the storage handle and free any allocated resources.
This function should be called for each handle opened with nvs_open once the handle is not in use any more. Closing the handle may not automatically write the changes to nonvolatile storage. This has to be done explicitly using nvs_commit function. Once this function is called on a handle, the handle should no longer be used.
handle -- [in] Storage handle to close
esp_err_t nvs_get_stats(const char *part_name, nvs_stats_t *nvs_stats)
Fill structure nvs_stats_t. It provides info about memory used by NVS.
This function calculates the number of used entries, free entries, available entries, total entries and number of namespaces in partition.
// Example of nvs_get_stats() to get overview of actual statistics of data entries :
nvs_stats_t nvs_stats;
nvs_get_stats(NULL, &nvs_stats);
printf("Count: UsedEntries = (%lu), FreeEntries = (%lu), AvailableEntries = (%lu), AllEntries = (%lu)\n",
nvs_stats.used_entries, nvs_stats.free_entries, nvs_stats.available_entries, nvs_stats.total_entries);
part_name -- [in] Partition name NVS in the partition table. If pass a NULL than will use NVS_DEFAULT_PART_NAME ("nvs").
nvs_stats -- [out] Returns filled structure nvs_states_t. It provides info about used memory the partition.
ESP_OK if the changes have been written successfully. Return param nvs_stats will be filled.
ESP_ERR_NVS_PART_NOT_FOUND if the partition with label "name" is not found. Return param nvs_stats will be filled 0.
ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized. Return param nvs_stats will be filled 0.
ESP_ERR_INVALID_ARG if nvs_stats is equal to NULL.
ESP_ERR_INVALID_STATE if there is page with the status of INVALID. Return param nvs_stats will be filled not with correct values because not all pages will be counted. Counting will be interrupted at the first INVALID page.
esp_err_t nvs_get_used_entry_count(nvs_handle_t handle, size_t *used_entries)
Calculate all entries in a namespace.
An entry represents the smallest storage unit in NVS. Strings and blobs may occupy more than one entry. Note that to find out the total number of entries occupied by the namespace, add one to the returned value used_entries (if err is equal to ESP_OK). Because the name space entry takes one entry.
// Example of nvs_get_used_entry_count() to get amount of all key-value pairs in one namespace:
nvs_handle_t handle;
nvs_open("namespace1", NVS_READWRITE, &handle);
size_t used_entries;
size_t total_entries_namespace;
if(nvs_get_used_entry_count(handle, &used_entries) == ESP_OK){
// the total number of entries occupied by the namespace
total_entries_namespace = used_entries + 1;
handle -- [in] Handle obtained from nvs_open function.
used_entries -- [out] Returns amount of used entries from a namespace.
ESP_OK if the changes have been written successfully. Return param used_entries will be filled valid value.
ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized. Return param used_entries will be filled 0.
ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL. Return param used_entries will be filled 0.
ESP_ERR_INVALID_ARG if used_entries is equal to NULL.
Other error codes from the underlying storage driver. Return param used_entries will be filled 0.
esp_err_t nvs_entry_find(const char *part_name, const char *namespace_name, nvs_type_t type, nvs_iterator_t *output_iterator)
Create an iterator to enumerate NVS entries based on one or more parameters.
// Example of listing all the key-value pairs of any type under specified partition and namespace
nvs_iterator_t it = NULL;
esp_err_t res = nvs_entry_find(<nvs_partition_name>, <namespace>, NVS_TYPE_ANY, &it);
while(res == ESP_OK) {
nvs_entry_info_t info;
nvs_entry_info(it, &info); // Can omit error check if parameters are guaranteed to be non-NULL
printf("key '%s', type '%d' \n", info.key, info.type);
res = nvs_entry_next(&it);
nvs_release_iterator(it);
part_name -- [in] Partition name
namespace_name -- [in] Set this value if looking for entries with a specific namespace. Pass NULL otherwise.
type -- [in] One of nvs_type_t values.
output_iterator -- [out] Set to a valid iterator to enumerate all the entries found. Set to NULL if no entry for specified criteria was found. If any other error except ESP_ERR_INVALID_ARG occurs, output_iterator
is NULL, too. If ESP_ERR_INVALID_ARG occurs, output_iterator
is not changed. If a valid iterator is obtained through this function, it has to be released using nvs_release_iterator
when not used any more, unless ESP_ERR_INVALID_ARG is returned.
ESP_OK if no internal error or programming error occurred.
ESP_ERR_NVS_NOT_FOUND if no element of specified criteria has been found.
ESP_ERR_NO_MEM if memory has been exhausted during allocation of internal structures.
ESP_ERR_INVALID_ARG if any of the parameters is NULL. Note: don't release output_iterator
in case ESP_ERR_INVALID_ARG has been returned
esp_err_t nvs_entry_find_in_handle(nvs_handle_t handle, nvs_type_t type, nvs_iterator_t *output_iterator)
Create an iterator to enumerate NVS entries based on a handle and type.
// Example of listing all the key-value pairs of any type under specified handle (which defines a partition and namespace)
nvs_iterator_t it = NULL;
esp_err_t res = nvs_entry_find_in_handle(<nvs_handle>, NVS_TYPE_ANY, &it);
while(res == ESP_OK) {
nvs_entry_info_t info;
nvs_entry_info(it, &info); // Can omit error check if parameters are guaranteed to be non-NULL
printf("key '%s', type '%d' \n", info.key, info.type);
res = nvs_entry_next(&it);
nvs_release_iterator(it);
handle -- [in] Handle obtained from nvs_open function.
type -- [in] One of nvs_type_t values.
output_iterator -- [out] Set to a valid iterator to enumerate all the entries found. Set to NULL if no entry for specified criteria was found. If any other error except ESP_ERR_INVALID_ARG occurs, output_iterator
is NULL, too. If ESP_ERR_INVALID_ARG occurs, output_iterator
is not changed. If a valid iterator is obtained through this function, it has to be released using nvs_release_iterator
when not used any more, unless ESP_ERR_INVALID_ARG is returned.
ESP_OK if no internal error or programming error occurred.
ESP_ERR_NVS_NOT_FOUND if no element of specified criteria has been found.
ESP_ERR_NO_MEM if memory has been exhausted during allocation of internal structures.
ESP_ERR_NVS_INVALID_HANDLE if unknown handle was specified.
ESP_ERR_INVALID_ARG if output_iterator parameter is NULL. Note: don't release output_iterator
in case ESP_ERR_INVALID_ARG has been returned
esp_err_t nvs_entry_next(nvs_iterator_t *iterator)
Advances the iterator to next item matching the iterator criteria.
Note that any copies of the iterator will be invalid after this call.
iterator -- [inout] Iterator obtained from nvs_entry_find or nvs_entry_find_in_handle function. Must be non-NULL. If any error except ESP_ERR_INVALID_ARG occurs, iterator
is set to NULL. If ESP_ERR_INVALID_ARG occurs, iterator
is not changed.
ESP_OK if no internal error or programming error occurred.
ESP_ERR_NVS_NOT_FOUND if no next element matching the iterator criteria.
ESP_ERR_INVALID_ARG if iterator
is NULL.
Possibly other errors in the future for internal programming or flash errors.
esp_err_t nvs_entry_info(const nvs_iterator_t iterator, nvs_entry_info_t *out_info)
Fills nvs_entry_info_t structure with information about entry pointed to by the iterator.
iterator -- [in] Iterator obtained from nvs_entry_find or nvs_entry_find_in_handle function. Must be non-NULL.
out_info -- [out] Structure to which entry information is copied.
ESP_OK if all parameters are valid; current iterator data has been written to out_info
ESP_ERR_INVALID_ARG if one of the parameters is NULL.