Site logo

Developer Blog

Pavel Koltyshev

Энергонезависимое хранилище NVS в ESP32

Содержание

В ESP32 можно хранить пары ключ-значение в специальном разделе SPI Flash памяти. Вы можете сами определить размер этого раздела памяти с помощью разметки разделов. NVS лучше всего подходит для хранения небольших значений, для хранения больших значений лучше использовать файловую систему FAT.

Библиотека для работы с энергонезависимым хранилищем или NVS (Non-volatile storage) использует все разделы флешки с типом data и подтипом nvs.

Раздел с названием nvs можно открыть функцией nvs_open(), или указав названием раздела открыть функцией nvs_open_from_partition().

Ключи/значения

Максимальная длина ключа - 15 символов.

Значение ключа может быть одним из типов:

Ключи должны быть уникальными.

Пространства имен

Чтобы избежать проблем с одинаковыми ключами используются пространства имен (namespaces). Пространство имен это специальная строковая метка (не больше 15 символов) которая задается в функциях открытия nvs_open() и nvs_open_from_partition(). Пространства имен с одинаковыми именами находящиеся в разных разделах флеш памяти являются различными и никак не связаны.

NVS Итераторы

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

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

Ниже представлен пример программы которая запоминает количество перезагрузок ESP32 в целочисленную переменную в NVS.

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"

#define NVS_RESTART_COUNTER "restart_counter"

static const char *TAG = "NVS";
static const gpio_num_t LED_PIN = GPIO_NUM_2;

void app_main(void)
{
    // Setup LED
    gpio_pad_select_gpio(LED_PIN);
    gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
    gpio_set_level(LED_PIN, 1);

    // Initialize NVS
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);

    // Open NVS
    nvs_handle_t my_handle;
    ESP_ERROR_CHECK(nvs_open("storage", NVS_READWRITE, &my_handle));

    // Read value
    int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS
    err = nvs_get_i32(my_handle, NVS_RESTART_COUNTER, &restart_counter);
    if (err != ESP_ERR_NVS_NOT_FOUND)
    {
        ESP_ERROR_CHECK(err);
    }
    ESP_LOGI(TAG, "Restart counter: %d", restart_counter);

    // Write value
    restart_counter++;
    ESP_ERROR_CHECK(nvs_set_i32(my_handle, NVS_RESTART_COUNTER, restart_counter));
    ESP_ERROR_CHECK(nvs_commit(my_handle));

    // NVS Close
    nvs_close(my_handle);

    // Restart module
    for (int i = 10; i >= 0; i--)
    {
        ESP_LOGI(TAG, "Restarting in %d seconds...", i);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    ESP_LOGI(TAG, "Restarting now.");
    gpio_set_level(LED_PIN, 0);
    esp_restart();
}