nRF connect SDK:Non-Volatile Storage(NVS)

#nRF connect SDKでは一つのみ
nRF SDKではFLASH ROMの扱い方はいくつか用意されていましたが、nRF connect SDKではNVS一択のようです。nRF SDK時代のデータベース型に似ているものが採用されています。
データベース型のよい点は
・書き込み領域の管理を自動でしてくれる
・型を気にしなくてもよい
という点です。
##ソースコード

```main.c
/*
 * Copyright (c) 2012-2014 Wind River Systems, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr.h>
#include <sys/printk.h>
#include <drivers/flash.h>
#include <fs/nvs.h>
#include <storage/flash_map.h>
#include <string.h>

#define ID01 1
#define ID02 2
#define ID03 3

static struct nvs_fs fs;

void main(void)
{
    printk("Hello World! %s\n", CONFIG_BOARD);

    int rc = 0;
    char value_id01[128];
    uint8_t value_id02[16];
    uint32_t value_id03 = 0U;
    struct flash_pages_info info;

    /* define the nvs file system by settings with:
     *	sector_size equal to the pagesize,
     *	2 sectors
     *	starting at FLASH_AREA_OFFSET(storage)
     */
    fs.offset = FLASH_AREA_OFFSET(storage);
    rc = flash_get_page_info_by_offs(device_get_binding(DT_CHOSEN_ZEPHYR_FLASH_CONTROLLER_LABEL), fs.offset, &info);
    if (rc) {
        printk("Unable to get page info");
    }
    fs.sector_size = info.size;
    fs.sector_count = 2U;

    rc = nvs_init(&fs, DT_CHOSEN_ZEPHYR_FLASH_CONTROLLER_LABEL);
    if (rc) {
        printk("Flash Init failed\n");
    }

    // ID01(String)
    rc = nvs_read(&fs, ID01, &value_id01, sizeof(value_id01));
    if (rc > 0)
    {
        printk("ID: %d, Value: %s\n", ID01, value_id01);
        strcat(value_id01, ".1");
        (void)nvs_write(&fs, ID01, &value_id01, strlen(value_id01) + 1);
    }
    else
    {
        strcpy(value_id01, "192.168.1.1");
        printk("No found, adding %s at ID %d\n", value_id01, ID01);
        (void)nvs_write(&fs, ID01, &value_id01, strlen(value_id01) + 1);
    }

    // ID02(Array)
    rc = nvs_read(&fs, ID02, &value_id02, sizeof(value_id02));
    if (rc > 0)
    {
        printk("ID: %d, Value: ", ID02);
        for (int n = 0; n < sizeof(value_id02); n++)
        {
            printk("%x ", value_id02[n]);
            value_id02[n] ++;
        }
        printk("\n");
        (void)nvs_write(&fs, ID02, &value_id02, sizeof(value_id02));
    }
    else
    {
        printk("No found, adding it at ID %d\n", ID02);
        for (int n = 0; n < sizeof(value_id02); n++)
        {
            value_id02[n] = (0xff - n);
        }
        (void)nvs_write(&fs, ID02, &value_id02, sizeof(value_id02));
    }

    // ID03(Numeric)
    rc = nvs_read(&fs, ID03, &value_id03, sizeof(value_id03));
    if (rc > 0)
    {
        printk("Id: %d, Value: %d\n", ID03, value_id03);
        value_id03++;
        (void)nvs_write(&fs, ID03, &value_id03, sizeof(value_id03));
    }
    else
    {
        printk("No found, adding it at id %d\n", ID03);
        (void)nvs_write(&fs, ID03, &value_id03, sizeof(value_id03));
    }
}
```

```prj.conf
# FLASH
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_NVS=y
CONFIG_MPU_ALLOW_FLASH_WRITE=y
```

#動作を見てみる
このプログラムはnRF52840上で動作させています。nRF52840だと0xF8000から2ページ(4,096バイト×2)分の領域を使用します。なお、1ページでは動かすことができません。ページ単位でフラッシュするので1ページだとページを更新した時に不都合があるからだと思われます。
初めて走らせるときは当然何も書き込まれていません。もし何か書き込まれていたらErase Allで消してしまうことをお勧めします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/5cc2e593-6927-0ecb-23bb-710d8973588c.png)
1回走らせてみたところ・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/b640b234-28e5-3af3-fa80-1842844cc1eb.png)
何やら書き込まれているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/8ca8b5b5-f522-9a0b-110a-4b34c8fbdd7c.png)
リセットボタンを押してもう一度走らせてみると・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/4ee6bbd9-6686-c690-74be-e055465f70de.png)
先ほど書き込んだ値を読み込んで表示しました。
さて、この時フラッシュの中身がどうなっているかと言うと・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/c78d8762-61ee-7406-f692-c6214271d38c.png)
？？？
追記されている・・・？
データベースとして扱っていることで同一アドレスへの上書きは一切しません。未使用領域への追記という形で記録していき、最新のデータおよび履歴をどこか別のところで管理しているようです。
(この管理領域がどこなのかは分かりませんでした・・・)
なお、このサンプルでは書き込んでいる値を加工して再度書き込むのでリセットするたびに値が変わっていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/eb4eb2ac-5dc7-dbe2-c790-d1ec3c743de7.png)