編集履歴一覧に戻る
zakkieのアイコン画像

zakkie が 2021年01月17日08時27分27秒 に編集

初版

タイトルの変更

+

ESP-IDF の NVS を使ってみる

タグの変更

+

ESP32

+

ESP-IDF

記事種類の変更

+

セットアップや使用方法

本文の変更

+

ESP32 で工作していると、ちょっとしたフラグや設定値を保存したいことがあるかと思います。 こういった用途のために NVS という仕組みが用意されていますが、いまいち情報が少ないのでまとめてみました。 なお ESP-IDF v4.1 ベースで書いています。 ### パーティション、名前空間、キー NVS は key-value 式のデータストアです。 NVS 領域はパーティションによって分割することができます。でも分割すると色々と面倒な上、素の状態でもふつーに使う分には困らないので、そのまま使うことにします。 デフォルトのパーティションは `nvs` です。 パーティション内は名前空間で区切ることが出来ます。 キーは同一名前空間内で一意である必要があります。 つまりパーティション ∋ 名前空間 ∋ キー のような階層構造になります。 ### NVS の空き領域を確認する NVS 領域はWiFiやBluetoothも使うので、気付いたら満杯だったみたいなことがあります。 使う前に nvs_get_stats() で一度状態を確認しておくと安心ですね。 **サンプルコード** ```c 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](https://github.com/zakkie/EspNvsSample)に置いたので、良かったらどうぞ。 ``` 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 です。 ```c 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()` しないと変更が反映されない **サンプル** ```c 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]` とか書いていたらスタックオーバフローで死んでいて、小一時間悩みました。