zakkieのアイコン画像
zakkie 2021年01月17日作成
セットアップや使用方法 セットアップや使用方法 閲覧数 2331
zakkie 2021年01月17日作成 セットアップや使用方法 セットアップや使用方法 閲覧数 2331

ESP-IDF の NVS を使ってみる

ESP32 で工作していると、ちょっとしたフラグや設定値を保存したいことがあるかと思います。
こういった用途のために NVS という仕組みが用意されていますが、いまいち情報が少ないのでまとめてみました。
なお ESP-IDF v4.1 ベースで書いています。

パーティション、名前空間、キー

NVS は key-value 式のデータストアです。

NVS 領域はパーティションによって分割することができます。でも分割すると色々と面倒な上、素の状態でもふつーに使う分には困らないので、そのまま使うことにします。
デフォルトのパーティションは nvs です。

パーティション内は名前空間で区切ることが出来ます。
キーは同一名前空間内で一意である必要があります。

つまりパーティション ∋ 名前空間 ∋ キー のような階層構造になります。

NVS の空き領域を確認する

NVS 領域はWiFiやBluetoothも使うので、気付いたら満杯だったみたいなことがあります。
使う前に nvs_get_stats() で一度状態を確認しておくと安心ですね。

サンプルコード

err = nvs_get_stats("nvs", &stats);
if (err != ESP_OK) {
    printf("failed to nvs_get_stats(): %s\n", esp_err_to_name(err));
    goto fail;
}
printf("NVS Entries: total=%d  used=%d  free=%d\n",
    stats.total_entries, stats.used_entries, stats.free_entries);

出力

NVS Entries: total=756  used=158  free=598

NVS に保存されているデータをダンプする

nvs_entry_find("nvs", NULL, NVS_TYPE_ANY) で全ての要素を抽出できます。
抽出結果を nvs_entry_next() でまわして取得します。

サンプルプロジェクト全体をgithubに置いたので、良かったらどうぞ。

namespace=misc key=log type=blob(0x42) value(hexdump)=ffffffff
namespace=nvs.net80211 key=sta.phym type=uint8(0x1) value=3
namespace=nvs.net80211 key=sta.phybw type=uint8(0x1) value=2
namespace=nvs.net80211 key=sta.scan_method type=uint8(0x1) value=0
namespace=nvs.net80211 key=sta.sort_method type=uint8(0x1) value=0

NVS の値には型が付属します。
str型とblob型の最大長は 4096 です。

typedef enum {
    NVS_TYPE_U8    = 0x01,  /*!< Type uint8_t */
    NVS_TYPE_I8    = 0x11,  /*!< Type int8_t */
    NVS_TYPE_U16   = 0x02,  /*!< Type uint16_t */
    NVS_TYPE_I16   = 0x12,  /*!< Type int16_t */
    NVS_TYPE_U32   = 0x04,  /*!< Type uint32_t */
    NVS_TYPE_I32   = 0x14,  /*!< Type int32_t */
    NVS_TYPE_U64   = 0x08,  /*!< Type uint64_t */
    NVS_TYPE_I64   = 0x18,  /*!< Type int64_t */
    NVS_TYPE_STR   = 0x21,  /*!< Type string */
    NVS_TYPE_BLOB  = 0x42,  /*!< Type blob */
    NVS_TYPE_ANY   = 0xff   /*!< Must be last */
} nvs_type_t;

値の追加と削除

nvs_set_*() (型ごとに異なる) で設定し、nvs_erase_key()で削除します。nvs_erase_all() で全体を削除することもできます。

  • 既存のキーを指定した場合は上書き
  • nvs_commit() しないと変更が反映されない

サンプル

void set_value(void) {
    nvs_handle_t nvs_handle;
    char namespace[] = "myapp";
    esp_err_t err = nvs_open(namespace, NVS_READWRITE, &nvs_handle);
    if (err != ESP_OK) {
        printf("ERROR: nvs_open(%s): %s\n", namespace, esp_err_to_name(err));
        return;
    }

    nvs_set_u8(nvs_handle, "sample1", 0x40);

    nvs_commit(nvs_handle);
    nvs_close(nvs_handle);
}

void remove_key(void) {
    nvs_handle_t nvs_handle;
    char namespace[] = "myapp";
    esp_err_t err = nvs_open(namespace, NVS_READWRITE, &nvs_handle);
    if (err != ESP_OK) {
        printf("ERROR: nvs_open(%s): %s\n", namespace, esp_err_to_name(err));
        return;
    }

    nvs_erase_key(nvs_handle, "sample1");

    nvs_commit(nvs_handle);
    nvs_close(nvs_handle);
}

はまったところ

stack size の上限

ESP-IDF は、stack size の上限がデフォルトで 3548 になっています。
最初、buf[4096] とか書いていたらスタックオーバフローで死んでいて、小一時間悩みました。

1
  • zakkie さんが 2021/01/17 に 編集 をしました。 (メッセージ: 初版)
ログインしてコメントを投稿する