本笔记学习 Zephyr 的 NVS (Non-Volatile Storage),用于键值对存储。
zephyr/samples/subsys/nvs/
| 特性 | 说明 |
|---|---|
| 键值存储 | ID + 数据模式 |
| 历史记录 | 可读取历史值 |
| 损耗平衡 | 自动均衡写入 |
| 断电安全 | 写入操作原子性 |
| 特性 | NVS | LittleFS |
|---|---|---|
| 数据模型 | 键值对 | 文件系统 |
| 使用复杂度 | 简单 | 较复杂 |
| 历史记录 | ✅ 支持 | ❌ |
| 目录结构 | ❌ | ✅ |
#include <zephyr/fs/nvs.h>
static struct nvs_fs fs;
#define NVS_PARTITION storage_partition
#define NVS_PARTITION_DEVICE FIXED_PARTITION_DEVICE(NVS_PARTITION)
#define NVS_PARTITION_OFFSET FIXED_PARTITION_OFFSET(NVS_PARTITION)
int nvs_init(void)
{
struct flash_pages_info info;
int rc;
// 设置 Flash 设备
fs.flash_device = NVS_PARTITION_DEVICE;
if (!device_is_ready(fs.flash_device)) {
printk("Flash device not ready\n");
return -1;
}
// 设置偏移量
fs.offset = NVS_PARTITION_OFFSET;
// 获取扇区大小
rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
if (rc) {
printk("Unable to get page info\n");
return -1;
}
fs.sector_size = info.size;
fs.sector_count = 3; // 3 个扇区
// 挂载
rc = nvs_mount(&fs);
if (rc) {
printk("NVS mount failed: %d\n", rc);
return -1;
}
return 0;
}
#define ADDRESS_ID 1
char ip_addr[] = "192.168.1.1";
int rc = nvs_write(&fs, ADDRESS_ID, ip_addr, strlen(ip_addr) + 1);
if (rc > 0) {
printk("Written %d bytes\n", rc);
}
#define KEY_ID 2
uint8_t key[8] = {0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8};
int rc = nvs_write(&fs, KEY_ID, key, sizeof(key));
#define COUNTER_ID 3
uint32_t counter = 0;
nvs_write(&fs, COUNTER_ID, &counter, sizeof(counter));
char buf[16];
int rc = nvs_read(&fs, ADDRESS_ID, buf, sizeof(buf));
if (rc > 0) {
printk("Address: %s\n", buf);
} else {
printk("Not found\n");
}
// 读取第 N 个历史值
uint32_t counter, hist_counter;
int n = 0; // n=0 最新, n=1 上一个...
int rc = nvs_read_hist(&fs, COUNTER_ID, &hist_counter,
sizeof(hist_counter), n);
if (rc > 0) {
printk("History[%d]: %d\n", n, hist_counter);
}
int rc = nvs_delete(&fs, KEY_ID);
if (rc == 0) {
printk("Deleted\n");
}
#include <zephyr/fs/nvs.h>
#include <zephyr/storage/flash_map.h>
static struct nvs_fs fs;
#define COUNTER_ID 1
int main(void)
{
uint32_t boot_count = 0;
int rc;
// 初始化 NVS
fs.flash_device = FIXED_PARTITION_DEVICE(storage_partition);
fs.offset = FIXED_PARTITION_OFFSET(storage_partition);
struct flash_pages_info info;
flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
fs.sector_size = info.size;
fs.sector_count = 3;
rc = nvs_mount(&fs);
if (rc) {
printk("NVS mount failed\n");
return 0;
}
// 读取启动计数
rc = nvs_read(&fs, COUNTER_ID, &boot_count, sizeof(boot_count));
if (rc > 0) {
printk("Boot count: %u\n", boot_count);
} else {
printk("First boot\n");
}
// 更新计数
boot_count++;
nvs_write(&fs, COUNTER_ID, &boot_count, sizeof(boot_count));
printk("Next boot will be: %u\n", boot_count);
return 0;
}
/ {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
storage_partition: partition@0 {
label = "storage";
reg = <0x00000000 0x00010000>;
};
};
};
上面的
storage_partition仅作为示例,实际偏移和大小应按当前板卡分区表来定。
# prj.conf
CONFIG_NVS=y
CONFIG_NVS_LOG_LEVEL_INF=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
| ID 范围 | 用途 |
|---|---|
| 1-99 | 系统配置 |
| 100-199 | 用户数据 |
| 200-299 | 日志数据 |
| 300+ | 扩展使用 |
*小白 🤖 - 2026-03-16*