FlashDB 与 NVM 存储方案
FlashDB 概述
FlashDB 为应用提供统一的 NVM(非易失性存储器)操作接口,支持初始化、读写、删除、重置等功能,适配不同存储场景(如随机存储、时序存储)。
核心接口说明
FlashDB 提供两类接口:通用 NVM 操作(app_flashdb_xxx
)和时序数据库操作(app_tsdb_xxx
),具体如下:
rt_err_t app_flashdb_init(void *db,);
作用:用于开机时候初始化使用。当使能kvdb的时候,需要对对应的kvdb以及tsdb进行初始化
去初始化
void app_flashdb_deinit(void *db,);
作用:用于关机的时候去初始化使用。当使能kvdb的时候,需要对对应的kvdb以及tsdb进行去初始化
重置flashdb
size_t app_flashdb_reset(void *db,);
作用:用于恢复出厂设置的时候,重置db_name对应的flashdb。
删除flashdb
rt_err_t app_flashdb_del(void *db, const char *key_name);
作用:删除db_name对应的flashdb。
读flashdb
size_t app_flashdb_read(void *db, const char *key_name, const void *data, uint32_t len);
作用:读取db_name对应的flashdb。
写flashdb
rt_err_t app_flashdb_write(void *db, const char *key_name, const void *data, uint32_t len);
作用:写db_name对应的flashdb。
清除tsdb的内容
void app_tsdb_clean(void *db);
作用:清除db对应的tsdb。
删除tsdb中start_time到end_time的内容
size_t app_tsdb_del(void *db, fdb_time_t start_time, fdb_time_t end_time, bool mode);
作用:删除db对应的tsdb中start_time到end_time的内容。
读取tsdb中start_time到end_time的内容
size_t app_tsdb_read(void *db, fdb_time_t start_time, fdb_time_t end_time, tsdb_read_cb_t cb);
作用:读取db对应的tsdb中start_time到end_time的内容。
写tsdb
rt_err_t app_tsdb_write(void *db, fdb_time_t timestamp, void *data, uint32_t len);
作用:顺序写内容到tsdb。
存储机制与适用场景
Solution 支持三种 NVM 存储机制,适配不同硬件和需求:
开源 FlashDB
基于键值对(KVDB)和时序(TSDB)两种模式:
KVDB:适用于随机读写的小数据(如配置信息);
TSDB:适用于按时间戳顺序存储的批量数据(如传感器历史)。
特点:无需文件系统,依赖 Flash 分区管理;支持磨损均衡和数据恢复。
默认场景:NOR Flash 方案。
文件系统 SiFli 格式
原理:将每个 NVM 子类(如蓝牙信息、应用配置)存储为独立文件,文件含头信息(长度+CRC),读取时校验完整性。
特点:效率高,但依赖文件系统支持;适合频繁读写场景。
默认场景:NAND/eMMC 方案。
分区裸写格式
自定义实现,直接操作 Flash 分区,无统一框架,需用户自行处理读写逻辑。
Solution 中 NVM 的分类与使用规范
根据数据特性,Solution 将 NVM 分为以下几类,分别对应不同操作接口:
分类序号 |
NVM 用途描述 |
说明 |
---|---|---|
1 |
BLE/BT 固件相关信息 |
为 SDK 提供必要的蓝牙固件基础信息 |
2 |
DFU 升级过程中相关信息 |
存储设备固件升级过程中的临时数据和状态 |
3 |
APP 相关信息 |
包括应用设置、电话号码本、设备信息及应用状态 |
4 |
消息存储 |
用于保存各类应用消息数据 |
5 |
sensor 算法结果相关的历史记录 |
如步数、心率、血氧、睡眠、GPS 轨迹等数据 |
Solution 的系统级 NVM 操作通过以下文件实现,提供统一的访问接口宏,主要用于管理系统共性信息(不直接面向具体应用):
实现文件 |
功能范围 |
核心接口宏(随机存储) |
---|---|---|
|
应用层系统级NVM 操作 |
|
|
BLE 协议栈相关 NVM 操作 |
同上(针对 BLE 固件信息、连接参数等系统数据) |
|
蓝牙协议相关 NVM 操作 |
同上(针对蓝牙配置、配对信息等系统数据) |
|
传感器系统级历史数据操作 |
时序存储接口( |
说明:
上述接口宏和实现文件主要用于存储 Solution 系统运行必需的共性信息(如系统状态信息、协议配置、硬件状态等),不直接支持具体应用(尤其是外置动态应用)的专属数据存储。
若需为具体应用(如动态插件、模块化功能)管理独立 NVM 数据,请参考 七、应用层 NVM 操作接口:app_nvm_read
与 app_nvm_write
,该接口专为应用级数据设计,确保与系统数据隔离。
接口宏说明:
接口宏 |
作用描述 |
---|---|
|
将结构成员 |
|
获取结构成员 |
|
更新基本类型成员 |
|
更新构造类型成员 |
|
判断成员 |
存储策略:
非消息类数据:常驻内存,睡眠前检查更新并写入 Flash(文件系统方案)。
消息类数据:支持实时写或关机时写(关机写依赖内存暂存)。
历史记录:通过
app_tsdb_xxx
接口实时读写(因数据量大、周期长)。
NVM 分区配置
分区需根据存储机制调整,确保效率和可靠性:
使用 FlashDB 时
按“NVM 分类”为每个类型在
flash_map.xls
中分配独立分区。注意:FlashDB 回收旧块时耗时与分区大小正相关,分区需按实际存储量预留少量余量(避免过大)。
使用文件系统 SiFli 格式时
分两个核心分区:
sys
分区:存储恢复出厂设置不删除的数据(如设备唯一标识)。nvm
分区:存储其他频繁更新的 NVM 数据(建议独立分区,减少磨损均衡带来的块搬移)。
通过以上配置和接口,Solution 实现了 NVM 存储的高效、可靠管理,适配不同硬件和应用场景。
应用层 NVM 操作接口:app_nvm_read
与 app_nvm_write
接口特性与适用场景
app_nvm_read
和 app_nvm_write
专为独立应用(尤其是外置动态应用) 设计,核心特点:
数据独立性:存储的 NVM 数据与系统级 NVM 完全隔离,避免冲突;
动态应用适配:适合外置动态应用存储专属数据(如配置、状态等)。
无论是基于 FlashDB(开源 FlashDB )还是独立文件(文件系统 SiFli 格式),均通过 key_name
唯一标识数据,确保不同应用数据互不干扰。
1. 函数原型与参数
/**
* @brief 应用层NVM写入接口(适用于独立应用/动态应用)
* @param key_name 应用专属数据标识(需唯一,建议添加应用前缀避免冲突)
* @param data 待写入的数据缓冲区(支持结构体、数组等任意格式)
* @param length 数据长度(单位:字节)
* @retval RT_EOK 写入成功
* @retval RT_ERROR 写入失败
*/
rt_err_t app_nvm_write(const char *key_name, const void *data, size_t length);
/**
* @brief 应用层NVM读取接口(适用于独立应用/动态应用)
* @param key_name 数据标识(需与写入时的key一致)
* @param data 接收数据的缓冲区(需预先分配内存)
* @param length 期望读取的数据长度(单位:字节)
* @retval 实际读取的字节数(0表示读取失败或无数据)
*/
size_t app_nvm_read(const char *key_name, const void *data, size_t length);
2. 使用例程
存储应用配置(使用 app_nvm_write
)
// 定义应用专属配置结构体(示例)
typedef struct
{
uint8_t brightness; // 亮度设置(0-100)
uint8_t volume; // 音量设置(0-30)
bool auto_start; // 自动启动开关
} dyn_app_config_t;
/**
* 功能:将应用配置写入 NVM
*/
void dyn_app_save_config(void)
{
// 1. 准备配置数据
dyn_app_config_t config =
{
.brightness = 80,
.volume = 20,
.auto_start = true
};
// 2. 写入 NVM(使用应用专属 key:"dyn_app_config")
rt_err_t ret = app_nvm_write("dyn_app_config", &config, sizeof(config));
if (ret == RT_EOK)
{
LOG_I("配置保存成功");
} else
{
LOG_E("配置保存失败");
}
}
读取应用配置(使用 app_nvm_read)
/**
* 功能:从 NVM 读取并恢复应用配置
*/
void dyn_app_load_config(void) {
// 1. 定义接收缓冲区
dyn_app_config_t config;
memset(&config, 0, sizeof(config));
// 2. 读取 NVM(key 与写入时一致:"dyn_app_config")
size_t read_len = app_nvm_read("dyn_app_config", &config, sizeof(config));
// 3. 处理读取结果
if (read_len == sizeof(config))
{
LOG_I("配置读取成功:亮度=%d, 音量=%d, 自动启动=%d",
config.brightness, config.volume, config.auto_start);
// 此处可添加配置生效逻辑
} else
{
LOG_W("未读取到配置,使用默认值");
// 加载默认配置...
}
}
关键说明
key 唯一性:动态应用需确保
key_name
唯一(如添加应用前缀,例:"weather_app_config"
),避免与系统或其他应用的 key 冲突。数据类型:支持任意结构化数据(如自定义结构体、数组、字符串等),无需关心底层是FlashDB(开源 FlashDB )还是独立文件(文件系统 SiFli 格式)。
使用场景:
应用配置(如界面风格、功能开关);
用户数据(如登录状态、偏好设置);
运行状态(如上次退出位置、临时缓存)。
通过 app_nvm_read
和 app_nvm_write
,内置应用/动态应用可简单高效地实现专属 NVM 数据的持久化管理,无需依赖系统NVM。