ESP32: библиотека энергонезависимого хранилища данных Печать
Добавил(а) microsin   

Библиотека для энергонезависимого хранилища данных (Non-volatile storage, NVS) была разработана для хранения пар ключ-значение в памяти flash. В этой статье показаны некоторые концепции NVS (перевод документации [1]).

[Варианты хранилища нижнего уровня]

В настоящее время NVS использует часть основной памяти flash через вызовы esp_partition API. Библиотека использует все разделы (partitions) с типом data и субтипом nvs. Приложение может выбрать использование раздела с меткой nvs вызовом API-функции nvs_open(), или выбрать любой другой раздел путем указания его имени с использованием API-функции nvs_open_from_partition().

Будущие версии этой библиотеки смогут использовать другие системы хранения данных в различных типах микросхем (SPI или I2C), RTC, FRAM, и т. д.

Замечание: если раздел NVS урезается (например, когда меняется конфигурация таблицы разделов), то его содержимое должно быть очищено. Система сборки проекта в среде разработки ESP-IDF [2] предоставляет цель idf.py erase-flash для стирания всего содержимого чипа flash.

NVS лучше всего работает для очень маленьких значений, но не с большими массивами данных наподобие типов string и blob. Если нужно работать с большими порциями данных, то рассмотрите вариант хранилища на основе файловой системы FAT, реализованной поверх библиотеки выравнивания износа секторов FLASH (wear levelling library).

[Ключи и значения]

Как уже упоминалось, NVS работает с данными по принципу пар ключ-значение. Ключи это строки ASCII, т. е. имена значений. Максимальная длина ключа в настоящий момент составляет 15 символов. Значения могут быть одним из следующих типов (дополнительные типы, такие как float и double, могут быть добавлены позже):

• Целочисленные типы: uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t.
• Строки, заканчивающиеся нулем (zero-terminated string, или ASCIIZ).
• Двоичные данные переменной длины (blob).

В настоящее время значения ограничены 4000 байтами, включая null-терминатор. Blob-значения ограничены 508000 байтами, или 97.6% от размера раздела - 4000 байт, в зависимости от того, что меньше.

Ключи должны быть уникальными. Назначение нового значения существующему ключу работает следующим образом:

• Если новое значение такого же типа, что и старое, то новое значение обновляется.
• Если у нового значения другой тип данных, не совпадающий со старым типом, то будет возвращена ошибка.

Проверка типа данных выполняется при чтении значения. Будет возвращена ошибка, если тип данных операции чтения не соответствует типу данных значения.

Пространства имен. Чтобы уменьшить потенциальные конфликты в именах ключей между различными компонентами, NVS назначает каждую пару ключ-значение одному из пространств имен (namespace). Имена пространств следуют тем же правилам, что и имена ключей, например их максимальная длина составляет 15 символов. Имя для namespace указывается в вызове nvs_open() или nvs_open_from_partition(). Этот вызов вернет непрозрачный дескриптор, который используется в последующих вызовах функций nvs_get_*, nvs_set_* и nvs_commit(). Таким методом дескриптор связывается с namespace, и имена ключей не конфликтуют с такими же именами в других namespace. Обратите внимание, что пространства имен с одинаковым именем в разных разделах NVS считаются разными namespace.

Итераторы NVS. Итераторы позволяют пролистать пары ключ-значение, сохраненные в NVS, основываясь на имени раздела, namespace, и типе данных.

Для этого доступны следующие функции:

nvs_entry_find() вернет непрозрачный дескриптор, который используется в последующих вызовах функций nvs_entry_next() и nvs_entry_info().
nvs_entry_next() вернет итератор для следующей пары ключ-значение.
nvs_entry_info() вернет информацию для каждой пары ключ-значение.

Если не найдена никакая другая пара ключ-значение по заданному критерию, то nvs_entry_find() и nvs_entry_next() вернут NULL. В таком случае итератор освобождать не нужно. Если итератор больше не нужен, его можно освободить вызовом функции nvs_release_iterator().

Безопасность, взлом и надежность. NVS не совместима напрямую с системой шифрования flash (ESP32 flash encryption system). Однако данные все еще можно хранить в зашифрованном виде, если шифрование NVS используется вместе с ESP32 flash encryption (подробнее см. далее "Шифрование NVS").

Если шифрование NVS не используется, то любой взломщик, который получил физический доступ к микросхеме flash, может изменить, удалить или добавить пары ключ-значение. С разрешенным шифрованием NVS невозможно изменить или добавить пару ключ-значение, чтобы они потом были распознаны как достоверные, не зная соответствующих ключей шифрования NVS. Однако от операции стирания не существует защиты.

Библиотека сделает попытку восстановления из ситуаций, когда память flash находится в несогласованном состоянии. В частности, необходимо иметь возможность выключить питание устройства, и потом его снова включить. Это не должно привести к потере данных, за исключением новой пары ключ-значение, если она была записана в момент выключения питания. Библиотека должна быть способна инициализировать любые случайные данные, которые присутствуют в памяти flash.

[Шифрование NVS]

Данные, сохраненные в разделах (NVS partitions), могут быть зашифрованы с использованием AES-XTS способом, описанным в стандарте шифрования диска IEEE P1619. Для шифрования каждая запись рассматривается как один сектор и относительный адрес записи (w.r.t. partition-start), и в алгоритм шифрования подается как номер сектора. NVS Encryption можно разрешить опцией CONFIG_NVS_ENCRYPTION. Ключи, требуемые для шифрования, сохраняются в другом разделе, который защищен Flash Encryption. Таким образом, включение Flash Encryption является обязательным условием для работы NVS encryption.

По умолчанию NVS Encryption разрешается, когда разрешено Flash Encryption. Это осуществляется потому, что драйвер Wi-Fi сохраняет учетные данные (наподобие SSID и пароля) в разделе по умолчанию (default NVS partition). Важно зашифровать их по умолчанию, если на уровне платформы шифрование уже включено.

Для использования шифрования NVS таблица разделов должна содержать раздел ключа (NVS key partition). Для шифрования предоставляются две таблицы разделов, содержащие раздел ключа NVS (опция menuconfig -> Partition Table). Они могут быть выбраны через меню конфигурации проекта (командой idf.py menuconfig). Как конфигурировать и использовать функцию шифрования NVS, см. пример проекта security/flash_encryption (находится среди примеров каталога установки ESP-IDF [2]).

Раздел ключа NVS. Приложению, которому требуется поддержка шифрования NVS, должно быть скомпилировано с разделом ключа (key-partition) типа data и субтипом key. Этот раздел должен быть помечен как зашифрованный, и его размер должен быть минимальным для раздела (4KB), подробности см. в [3]. Две дополнительные таблицы разделов, которые содержат NVS key partition, предоставляются опцией menuconfig -> Partition Table. Они могут непосредственно использоваться для NVS Encryption, и их структура следующая:

+-----------+--------------+-------------+----+
|              XTS encryption key (32)        |
+---------------------------------------------+
|              XTS tweak key (32)             |
+---------------------------------------------+
|                  CRC32 (4)                  |
+---------------------------------------------+

Ключи шифрования (XTS encryption keys) в NVS key partition можно сгенерировать одним из двух способов.

1. Генерация ключей на чипе ESP.

Когда шифрование разрешено, API-функция nvs_flash_init() может использоваться для инициализации зашифрованного раздела NVS по умолчанию. Эта API-функция генерирует внутри себя ключи шифрования XTS на чипе ESP. API-функция находит первый раздел ключей NVS, за. Then the API functionем она автоматически генерирует и сохраняет ключи NVS в этом разделе с помощью API-функции nvs_flash_generate_keys(), предоставленной в nvs_flash/include/nvs_flash.h. Новые ключи генерируются и сохраняются только когда соответствующий раздел ключей пуст. Тот же самый раздел ключей может затем использоваться для чтения конфигураций безопасности, чтобы инициализировать пользовательский зашифрованный раздел NVS, с помощью nvs_flash_secure_init_partition().

API-функции nvs_flash_secure_init() и nvs_flash_secure_init_partition() не генерируют ключи внутри себя. Когда эти API-функции используются для инициализации зашифрованных разделов NVS, ключи могут быть сгенерированы после запуска системы (startup) с использованием API-функции nvs_flash_generate_keys(), предоставленной в nvs_flash.h. Эта API-функция затем запишет эти ключи на key-partition в зашифрованном виде.

2. Использование предварительно сгенерированного раздела ключей.

Этот способ потребуется, когда ключи в NVS key partition не генерируются приложением. NVS key partition, содержащий ключи хранить сгенерированный раздел ключей во flash с помощью следующих двух команд.

i) Сборка и прошивка таблицы разделов:

idf.py partition-table partition-table-flash

ii) Сохранение ключей в NVS key partition (на flash) с помощью скрипта parttool.py (см. секцию Partition Tool в [3] для получения дополнительной информации).

parttool.py --port /dev/ttyUSB0 --partition-table-offset "nvs_key partition offset" write_partition
 --partition-name="name of nvs_key partition" --input "nvs_key partition"

Поскольку раздел ключа помечен как зашифрованный, и разрешено Flash Encryption is enabled, загрузчик (bootloader) зашифрует этот раздел, используя flash encryption key при первой загрузке приложения (boot).

Приложение может использовать разные ключи для разных разделов NVS, и иметь для этого соответственно несколько разделов ключей (key-partitions). Однако в зоне ответственности приложения находится предоставление корректных key-partition/ключей для шифрования/дешифровки.

[Шифрованные чтение/запись]

Те же функции NVS API nvs_get_ * или nvs_set_ * могут также использоваться для чтения и записи в зашифрованный раздел NVS.

Шифрование раздела NVS по умолчанию: чтобы разрешить шифрование default NVS partition, не требуется предпринимать дополнительные шаги. Когда разрешена опция CONFIG_NVS_ENCRYPTION, API-функция nvs_flash_init() внутри себя выполнит некоторые дополнительные шаги, используя первый найденный раздел ключей (NVS key partition), чтобы разрешить шифрование для default NVS partition (подробнее см. документацию по API [1]). Альтернативно также может использоваться API-функция nvs_flash_secure_init() для разрешения шифрования default NVS partition.

Шифрование пользовательского раздела NVS: чтобы разрешить шифрование custom NVS partition, используется API-функция nvs_flash_secure_init_partition() вместо nvs_flash_init_partition().

Когда используются API-функции nvs_flash_secure_init() и nvs_flash_secure_init_partition(), от приложения ожидаются следующие шаги, чтобы выполнить операции чтения/записи NVS с разрешенным шифрованием:

1. Найдите раздел ключа (key partition) и раздел данных (data partition) NVS, используя API-функции esp_partition_find*.

2. Заполните структуру nvs_sec_cfg_t, используя API-функции nvs_flash_read_security_cfg() или nvs_flash_generate_keys().

3. Инициализируйте NVS flash partition, используя API-функции nvs_flash_secure_init() или nvs_flash_secure_init_partition().

4. Откройте namespace, используя API-функции nvs_open() или nvs_open_from_partition().

5. Выполните операции чтения/записи NVS, используя nvs_get_* или nvs_set_*.

6. Отмените инициализацию раздела NVS, используя nvs_flash_deinit().

[Утилита NVS Partition Generator]

Эта утилита помогает генерировать двоичные файлы раздела NVS, которые можно отдельно прошить в выделенный раздел partition binary с помощью скрипта программирования. Пары ключ-значение для прошивки в раздел могут быть предоставлены посредством файла CSV. Для подробностей см. NVS Partition Generator Utility [4].

[Пример приложения]

Примеры кода можно найти в каталоге storage, среди прочих примеров ESP-IDF [2].

storage/nvs_rw_value

Этот пример демонстрирует, как прочитать одно целое значение из NVS, и как его записывать в NVS.

Значение, проверяемое в этом примере, хранит количество перезагрузок модуля ESP32. Функция значения в качестве счетчика возможна только благодаря его хранению в NVS.

Пример также показывает, что проверить, была ли успешной операция чтения / записи, и было ли инициализировано значение в NVS. Процедура диагностики предоставляется в виде обычного текста, чтобы помочь разобраться в ходе выполнения программы, и легче исправлять возникающие проблемы.

storage/nvs_rw_blob

Пример демонстрирует, как читать одиночное целое значение и объект blob (binary large object), и как их записывать в NVS, чтобы сохранять значения между перезапусками модуля ESP32.

value - отслеживает количество программных (soft) и аппаратных (hard) перезагрузок модуля ESP32.

blob - содержит информацию о реальном времени выполнения. Таблица считывается из NVS в динамически выделенную область RAM. Новая run time информация добавляется в таблицу при каждом запущенном вручную программном рестарте, и затем эта информация записывается в NVS. Этот процесс запускается притягиванием к лог. 0 ножки GPIO0.

Этот пример также показывает, как реализовать процедуру диагностики, чтобы проверить, была ли успешной операция чтения / записи.

storage/nvs_rw_value_cxx

Этот пример делает то же самое, что и storage/nvs_rw_value, отличие только в том, что используется дескриптор класса C++ NVS.

[Внутренняя организация NVS]

Журнал пар ключ-значение. NVS сохраняет пары key-value последовательно, добавляя новые пары в конец заполненной области. Когда обновляется значение любого указанного ключа, в конец журнала добавляется новая пара key-value, и старая пара key-value помечается как стертая (erased).

Страницы (pages) и записи (entries). Библиотека NVS в своей работе использует 2 основных объекта: страницы и записи. Страница это логическая структура, которая хранит порцию общего журнала. Логическая страница соответствует одному физическому сектору памяти flash. С используемыми страницами связан порядковый номер. Этот номер позволяет упорядочить страницы. Чем больше порядковый номер, тем позже была создана страница. Каждая страница может быть в одном из следующих состояний:

Empty/uninitialized
Носитель данных flash для этой страницы пустой (все байты в значении 0xff). Эта страница не используется в настоящий момент для хранения каких-либо данных, и у неё нет порядкового номера.

Active
Хранилище flash инициализировано, заголовок страницы записан во flash, странице присвоен правильный порядковый номер. На странице есть несколько пустых записей, куда можно записать данные. В любой момент времени в этом состоянии может быть не более одной страницы.

Full
Хранилище flash находится в согласованном состоянии, хранилище заполнено парами key-value. Запись новых пар key-value на эту страницу невозможно. Некоторые пары key-value все еще можно пометить как erased.

Erasing
Не стертые пары key-value перемещаются на другую страницу, так что текущая страница может быть стерта. Это переходное состояние, т. е. страница никогда не остается в этом состоянии, когда происходит выход из любой API-функции. В случае внезапного отключения питания процесс перемещения и стирания будет завершен при следующем включении питания.

Corrupted
Заголовок страницы содержит недопустимые данные, и дальнейший парсинг данных страницы был отменен. Любые элементы данных, которые ранее были записаны на эту страницу, больше не будут доступны. Соответствующий сектор flash не стирается немедленно, и сохраняется вместе с секторами в uninitialized-состоянии для последующего использования. Это может быть полезно для отладки.

Сопоставление секторов flash-памяти с логическими страницами не имеет определенного порядка. Библиотека будет проверять порядковые номера страниц, найденных в каждом секторе памяти flash, и упорядочивать страницы в списке на основе этих номеров.

+--------+     +--------+     +--------+     +--------+
| 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
+----------+  +----------+  +----------+  +----------+

Структура страницы. На данный момент мы предполагаем, что размер сектора памяти flash составляет 4096 байт, и что оборудование ESP32 шифрования flash-памяти работает на 32-байтовых блоках. Можно ввести некоторые настройки, конфигурируемые во время компиляции (например, через menuconfig) для установки микросхем flash с различными размерами секторов (хотя неясно, могут ли другие компоненты в системе, например драйвер flash-памяти SPI и кэш flash-памяти SPI, поддерживать эти другие размеры).

Страница состоит из 3 частей: заголовок (header), биты состояния записи (entry state bitmap), и сами записи (entries). Для поддержки совместимости шифрования ESP32 flash, размер записи равен 32 байтам. Для целочисленных типов одна запись хранит одну пару ключ-значение (key-value). Для строк (string) и двоичных данных (blob) запись хранит часть пары key-value (подробнее об этом в описании структуры записи).

На следующей диаграмме показана структура страницы. Числа в круглых скобках показывают размер в байтах для каждой части.

+-----------+---------------+-------------+-------------------------+
| State (4) | Порядк. № (4) | version (1) | Unused (19) | CRC32 (4) |   Header (32)
+-----------+---------------+-------------+-------------------------+
|                 Entry state bitmap (32)                           |
+-------------------------------------------------------------------+
|                        Entry 0 (32)                               |
+-------------------------------------------------------------------+
|                        Entry 1 (32)                               |
+-------------------------------------------------------------------+
/                                                                   /
/                                                                   /
+-------------------------------------------------------------------+
|                        Entry 125 (32)                             |
+-------------------------------------------------------------------+

Заголовок страницы (header) и entry state bitmap всегда записываются во flash не зашифрованными. Записи (Entry n) шифруются, если используются шифрование flash ESP32.

Значения для поля state определены таким образом, что изменение состояния фиксируется записью 0 в некоторые биты. Поэтому нет необходимости стирать страницу, чтобы изменить её состояние, если это не является изменением для перехода в состояние erased.

Поле version в заголовке отражает используемую версию формата NVS. Для обеспечения обратной совместимости при каждом обновлении поле версии декрементируется, начиная с 0xff (например, 0xff для version-1, 0xfe для version-2, и так далее).

Значение контрольной суммы CRC32 в заголовке вычисляется от части страницы, которая не включает поле state и поле самой контрольной суммы (байты от 4 до 28). Не используемая часть сейчас заполняется байтами 0xff.

Следующие секции описывают структуру поля состояния записи (entry state bitmap) и саму запись (entry).

[Entry и entry state bitmap]

Каждая запись (entry) может быть в одном из следующих состояний, которые представлены двумя битами в entry state bitmap. Последние 4 бита bitmap (256 - 2 * 126) не используются.

Empty (11)
Пока в эту запись ничего не записаноt. Это соответствует не инициализированному состоянию (все байты в значении 0xff).

Written (10)
Пара key-value (или часть от пары key-value, которая распространяется на несколько записей) была записана в эту запись.

Erased (00)
Пара key-value в этой записи отброшена (считается стертой). Содержимое этой записи больше не будет анализироваться.

Структура записи. Для значений примитивных типов (в настоящий момент это целые числа размером от 1 до 8 байт), запись хранит одну пару key-value. Для строк и типов blob запись хранит часть от всей пары key-value. Для строк, когда пара key-value распространяется на несколько записей, все эти записи хранятся на одной и той же странице. Данным blob разрешается распространятся между несколькими страницами, путем разделения их на отдельные куски. Для отслеживания этих кусков сохраняется дополнительная запись метаданных фиксированного размера, которая называется "blob index". Ранние форматы blob все еще поддерживаются (могут быть прочитаны и изменены). Однако после того, как blob был изменен, он будет сохранен уже в новом формате.

+--------+----------+----------+----------------+-----------+---------------+----------+
| NS (1) | Type (1) | Span (1) | ChunkIndex (1) | CRC32 (4) |    Key (16)   | Data (8) |
+--------+----------+----------+----------------+-----------+---------------+----------+

                                       Примитивные  +--------------------------------+
                                        +-------->  |     Data (8)                   |
                                        | типы      +--------------------------------+
                   +-> Фикс. длина ----
                   |                    |           +---------+--------------+---------------+-------+
                   |                    +-------->  | Size(4) | ChunkCount(1)| ChunkStart(1) | Rsv(2)|
  Формат данных ---+                    Blob Index  +---------+--------------+---------------+-------+
                   |
                   |                             +----------+---------+-----------+
                   +-> Переменная длина    -->   | Size (2) | Rsv (2) | CRC32 (4) |
                        (string, Blob Data)      +----------+---------+-----------+

Отдельные поля в структуре записи имеют следующее назначение:

NS
Индекс namespace для этой записи.

Type
Один байт, показывающий тип данных value. Возможные значения см. в перечислении заголовочного файла nvs_flash/include/nvs_handle.hpp for possible values.

Span
Количество записей, которые использует эта пара key-value. Для целых типов это поле равно 1. Для строк и blob количество зависит от длины value.

ChunkIndex
Используется для хранения индекса куска данных blob. Для других типов это поле должно быть равно 0xff.

CRC32
Контрольная сумма, вычисленная от всех байт этой записи, кроме байт самого поля CRC32.

Key
Строка, заканчивающаяся нулем (ASCII), где находится имя key. Максимальная длина строки имени составляет 15 байт, не считая завершающего нуля.

Data
Для целых типов это поле содержит само value. Если value короче 8, то оно добавляется справа не используемыми байтами, равными 0xff.

Для записи "blob index" эти 8 байт хранят следующую информацию о кусках данных:

• Size
(только для blob index) размер в байтах всех данных blob.

• ChunkCount
(только для blob index) Общее количество кусков данных blob, на которые blob был поделен для хранения.

• ChunkStart
(только для blob index) ChunkIndex первого куска данных этого blob. Последующие куски получают инкрементное распределение индекса (с шагом 1).

Для кусков строк и кусков данных blob эти 8 байт хранят дополнительные описательные данные для value:

• Size
(только для строк и blob) размер реальных данных в байтах. Для строк это значение включает завершающий 0.

• CRC32
(только для строк и blob) контрольная сумма, вычисленная от всех байт данных.

Value с переменной длиной (строки и blob) сохраняются в последующих записях, по 32 байта на запись. Поле Span последней записи показывает, сколько записей используется.

[Пространства имен (namespace)]

Как упоминалось выше, каждая пара key-value принадлежит одному из пространств имен (namespace). Идентификаторы пространства имен (строки) сохраняются как ключи пар key-value в namespace с индексом 0. Значения, соответствующие этим ключам, будут индексами для этих namespace.

+-------------------------------------------+
| NS=0 Type=uint8_t Key="wifi" Value=1      |   Запись, описывающая namespace "wifi"
+-------------------------------------------+
| NS=1 Type=uint32_t Key="channel" Value=6  |   Ключ "channel" в namespace "wifi"
+-------------------------------------------+
| NS=0 Type=uint8_t Key="pwm" Value=2       |   Запись, описывающая namespace "pwm"
+-------------------------------------------+
| NS=2 Type=uint16_t Key="channel" Value=20 |   Ключ "channel" в namespace "pwm"
+-------------------------------------------+

Hash-список элементов. Для уменьшения количества чтений из памяти flash, каждый элемент класса Page поддерживает список пар: индекс элемента (item index); хэш элемента (item hash). Этот список значительно ускоряет поиск. Вместо того, чтобы выполнять итерацию по всем записям, считывая записи из flash по одной, функция Page::findItem сначала осуществляет поиск хэша элемента в hash-списке. Это дает индекс элемента на странице, если такой элемент существует. Из-за хеш-коллизии есть вероятность, что будет найден не тот элемент. Эта ситуация разрешается путем отката на итерацию по элементам из flash-памяти.

Каждый узел в hash-списке содержит 24-битный хэш и 8-битный индекс элемента. Хэш вычисляется от namespace элемента, имени ключа и ChunkIndex. Для вычисления используется CRC32, результат обрезается до 24 бит. Для снижения чрезмерных расходов на сохранение 32-битных записей в связанном списке, этот список реализован как двойной список (double-linked list) массивов. Каждый массив содержит 29 записей, общий размер которых составляет 128 байт, вместе со связанным списком указателей и 32-битным полем счетчика. Минимальный объем дополнительного использования RAM на страницу составляет 128 байт, максимальный 640 байт.

[NVS API]

Заголовочные файлы:

components/nvs_flash/include/nvs_flash.h
components/nvs_flash/include/nvs.h

В таблице ниже приведено общее описание API-функций NVS, полное описание см. в документации [1].

Функция Описание
nvs_flash_init Инициализация раздела NVS по умолчанию.
nvs_flash_init_partition Инициализация хранилища flash NVS для указанного раздела.
nvs_flash_init_partition_ptr Инициализация хранилища flash NVS для раздела, указанного указателем.
nvs_flash_deinit Отмена инициализации хранилища NVS для раздела NVS по умолчанию.
nvs_flash_deinit_partition Отмена инициализации хранилища NVS для указанного раздела NVS.
nvs_flash_erase Стирает раздел NVS по умолчанию.
nvs_flash_erase_partition Стирает указанный раздел NVS.
nvs_flash_erase_partition_ptr Стирает пользовательский раздел.
nvs_flash_secure_init Инициализирует раздел NVS по умолчанию.
nvs_flash_secure_init_partition Инициализирует хранилище NVS flash для указанного раздела.
nvs_flash_generate_keys Генерация и сохранение ключей NVS в предоставленном разделе.
nvs_flash_read_security_cfg Чтение конфигурации безопасности NVS из раздела.
nvs_set_i8 Установит значение int8_t для указанного ключа.
nvs_set_u8 Установит значение uint8_t для указанного ключа.
nvs_set_i16 Установит значение int16_t для указанного ключа.
nvs_set_u16 Установит значение uint16_t для указанного ключа.
nvs_set_i32 Установит значение int32_t для указанного ключа.
nvs_set_u32 Установит значение uint32_t для указанного ключа.
nvs_set_i64 Установит значение int64_t для указанного ключа.
nvs_set_u64 Установит значение uint64_t для указанного ключа.
nvs_set_str Установит строку для указанного ключа.
nvs_get_i8 Получит значение int8_t для указанного ключа.
nvs_get_u8 Получит значение uint8_t для указанного ключа.
nvs_get_i16 Получит значение int16_t для указанного ключа.
nvs_get_u16 Получит значение uint16_t для указанного ключа.
nvs_get_i32 Получит значение int32_t для указанного ключа.
nvs_get_u32 Получит значение uint32_t для указанного ключа.
nvs_get_i64 Получит значение int64_t для указанного ключа.
nvs_get_u64 Получит значение uint64_t для указанного ключа.
nvs_get_str Получит значение строки для указанного ключа.
nvs_set_blob Установит значение данных переменной длины для указанного ключа.
nvs_get_blob Получит значение данных переменной длины для указанного ключа.
nvs_open Откроет энергонезависимое хранилище с указанным namespace из раздела NVS по умолчанию.
nvs_open_from_partition Откроет энергонезависимое хранилище с указанным namespace из указанного раздела NVS.
nvs_erase_key Сотрет пару key-value с указанным именем ключа.
nvs_erase_all Сотрет все пары key-value в указанном namespace.
nvs_commit Запишет любые ожидающие сохранения изменения в энергонезависимое хранилище.
nvs_close Закроет дескриптор хранилища и освободит любые выделенные ресурсы.
nvs_get_stats Заполнит структуру nvs_stats_t, которая предоставит информацию об используемой разделом памяти.
nvs_get_used_entry_count Подсчитает все записи в namespace.
nvs_entry_find Создает итератор, чтобы просмотреть записи NVS, основываясь на одном или нескольких параметров.
nvs_entry_next Возвратит следующий элемент, который подходит под критерий итератора, или NULL, если таких элементов нет.
nvs_entry_info Заполнит структуру nvs_entry_info_t информацией о записи, на которую указывает итератор.
nvs_release_iterator Освободит итератор.

[Ссылки]

1. ESP32 Non-volatile storage library site:docs.espressif.com.
2. Установка среды разработки ESP-IDF для ESP32.
3. ESP32: таблицы разделов.
4. ESP32: утилита генерации раздела NVS.