【Zephyr 系列 28】MCU 闪存文件系统详解:LittleFS + NVS + 块设备设计实战
🧠关键词:Zephyr 文件系统、LittleFS、NVS、Flash 分区、嵌入式存储、断电保护、wear leveling
📌 1. 为什么 MCU 上需要文件系统?
在嵌入式开发中,很多开发者起初直接操作 Flash 保存参数,但随着需求增长,往往会遇到:
-
参数保存格式混乱,维护困难;
-
写入失败容易造成数据损坏,缺乏断电保护;
-
写入频繁导致 Flash 使用寿命降低;
-
无法保存复杂结构,如日志、配置备份等。
这时,轻量级文件系统显得尤为重要,它可以提供:
-
像 PC 一样的 API 操作接口(open、read、write、seek 等);
-
自动管理擦除、块写入、wear leveling;
-
部分具备容错能力,断电保护;
-
与上位机通信时,可以同步上传/下载配置数据。
在 Zephyr 中,推荐使用的有:
-
LittleFS
:轻量、断电保护、目录支持,适合日志/配置文件 -
NVS
:非易失性存储,类似 KV 键值表,适合保存结构化配置数据
📦 2. Zephyr 文件系统框架概览
Zephyr 的文件系统模块基于 POSIX 风格 API:
#include <fs/fs.h>
核心数据结构:
struct fs_file_t file;
fs_file_t_init(&file);
fs_open(&file, "/config.txt", FS_O_RDWR | FS_O_CREATE);
fs_write(&file, data, len);
fs_close(&file);
支持的文件系统包括:
文件系统 | 特性说明 |
---|---|
LittleFS | 小型、断电保护、可嵌套目录、wear leveling |
NVS | 键值型存储,数据小、安全可靠 |
FATFS | 标准 FAT 文件系统,需挂载 SD 卡或 U 盘 |
通过 fs_mount
函数挂载,并通过 fs_open
等函数操作。
🧪 3. LittleFS 实战:从 Flash 驱动到文件操作
3.1 启用配置
在 prj.conf
中启用:
CONFIG_FILE_SYSTEM=y
CONFIG_FILE_SYSTEM_LITTLEFS=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH=y
3.2 配置 Flash 分区
在 boards/your_board.dts
或 your_board.overlay
中添加:
/ {storage_partition: partition@0007c000 {label = "storage";reg = <0x0007C000 0x00004000>; // 分区地址和大小};
};
在 pm_static.yml
中关联:
flash:storage:address: 0x7C000size: 0x4000
3.3 实现挂载点
#include <fs/littlefs.h>
static struct fs_mount_t littlefs_mnt = {.type = FS_LITTLEFS,.mnt_point = "/lfs",.fs_data = &littlefs_storage,.storage_dev = (void *)FLASH_AREA_ID(storage)
};int ret = fs_mount(&littlefs_mnt);
3.4 文件操作代码示例
struct fs_file_t file;
fs_file_t_init(&file);
fs_open(&file, "/lfs/log.txt", FS_O_WRITE | FS_O_CREATE);
fs_write(&file, "Hello Zephyr\n", 13);
fs_close(&file);
🔐 4. NVS 存储:参数保存更安全
4.1 启用配置
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
4.2 初始化 NVS
#include <storage/flash_map.h>
#include <fs/nvs.h>static struct nvs_fs fs;void nvs_init(void) {fs.offset = FLASH_AREA_OFFSET(storage);fs.sector_size = 4096;fs.sector_count = 2;fs.flash_device = DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller));nvs_init(&fs, DT_LABEL(DT_CHOSEN(zephyr_flash_controller)));
}
4.3 写入与读取
int val = 123;
nvs_write(&fs, 1, &val, sizeof(val));int read_val = 0;
nvs_read(&fs, 1, &read_val, sizeof(read_val));
4.4 清除数据
nvs_delete(&fs, 1);
🔗 5. 多文件系统共存设计:配置+日志+OTA 标志
一个典型的嵌入式系统可能同时用多个存储:
-
/nvs
保存系统配置(蓝牙绑定、版本号等) -
/lfs
保存日志与缓存 -
/ota
保存 OTA 升级中间文件
通过多个 fs_mount_t
实例实现挂载:
fs_mount(&nvs_mnt);
fs_mount(&littlefs_mnt);
需要规划 Flash 分区,并确保设备支持多个挂载点。
🧰 6. 常见问题排查与建议
问题 | 解决建议 |
---|---|
文件系统挂载失败 | 检查 Flash 分区是否冲突 |
写入失败 | 确保对齐块大小;检查返回码 |
文件丢失或损坏 | 使用 fs_format() 重置文件系统 |
分区未初始化 | 检查 fs_mount() 返回值 |
OTA 写入失败 | 检查 Flash 剩余空间与擦除权限 |
🧪 7. 项目实战应用场景
7.1 蓝牙配对信息保存
使用 NVS 保存 BLE_MAC
, 绑定标志
等,断电不丢失。
7.2 OTA 升级状态标记
写入升级中标志位,系统异常时可回滚。
7.3 传感器日志记录
将温度、电量数据按时间戳写入 log.txt
,可上传到云端或导出。
✅ 总结
本章详细解析了 Zephyr 中的嵌入式文件系统机制,帮助开发者:
-
构建稳定的 Flash 数据保存机制;
-
实现参数配置持久化、日志记录与 OTA 管理;
-
学会使用 LittleFS 与 NVS 各自优势;
-
为产品稳定性、安全性提供基础支撑。
📌 下一篇预告
【Zephyr 系列 29】
MCU 网络子系统全解析:Socket 编程 + MQTT + TLS 通信实战