前言
本文档主要针对WS63V100中NV存储模块的使用进行介绍。用于指导工程人员能够快速使用NV模块进行二次开发。
与本文档相对应的产品版本如下。
本文档主要适用于以下工程师:
技术支持工程师
软件工程师
在本文中可能出现下列标志,它们所代表的含义如下。
|
||
|
||
NV简介
NV模块用于本地存储器中存储非易失性数据。NV中的每项数据以类似key-value的方式进行定义,数据项中包含唯一的索引key和自定义数据类型的value。
NV项可通过两种方式进行存储:编译预置和API写入。
编译预置是指开发者可在代码编译阶段,通过修改NV头文件和NV配置文件的方式生成客制化的NV镜像,在镜像烧录的过程中统一烧录到存储介质中。预置的NV在代码运行阶段可通过API接口进行读取和更新。
API写入是指用户可直接在代码中调用API接口写入新的NV项,具体使用方法请参见“NV API指南”。
NV编译预置
编译预置的方式不支持加密NV项的生成。如需写入加密NV项,必须使用API接口。
新增NV项
新增NV项流程
在头文件中新增kvalue的数据类型定义(非必须,如果是通用类型数据可忽略此步骤)。
在json文件中新增NV描述项。
通用数据类型:
unit8_t、unit16_t、unit32_t、bool。
自定义数据类型:
支持自定义枚举(enum)类型和结构体(struct)类型。
自定义数据类型存放路径:
middleware/chips/ws63/nv/nv_config/include/nv_common_cfg.h
当用户使用通用或已定义的数据类型时,不涉及上述文件的修改;当用户要新增枚举或结构体类型时,需在上述文件中定义。
NV描述项文件路径:
middleware/chips/ws63/nv/nv_config/cfg/acore/app.json
定义说明:
表 1 NV配置选项说明
在NV的配置中,每个字段的详细描述如下:
key_id:
以十六进制形式给出的NV项ID。key_id必须唯一,不能重复,因此建议用户在“key_id.h”中预留的用户区间内取值,避免不同模块使用NV互相影响。
key_status:
用于标记是否将该项的NV值编到生成的bin文件中。该字段为“alive”,表示NV项生效,当前固件版本正在使用此key;若为其他的字段或空,则不生效。
structure_type:
NV项的数据类型。已在“新增kvalue数据类型”中详细描述。
attributions:NV项属性值。1 、2、4为互斥关系,三选一。
1:Normal nv(普通NV,可修改)。
2:Permanent nv(不可修改)。
4:Un-upgrade nv(不随版本升级而修改)。
value:
如果value不是上述通用数据类型,任何结构都必须以列表的形式书写,有如下两种情况:
列表所有成员全部赋值。
只对列表前面若干个成员赋值。这表明对末尾未赋值的成员缺省赋值为0。
新增NV项示例
在“middleware/chips/ws63/nv/nv_config/include/nv_common_cfg.h”文件中新增自定义结构体。新增自定义数据类型示例如下:
新增结构体类型且结构体内都为基础类型:
typedef struct { int8_t param1; int8_t param2; int8_t param3; int8_t param4; int8_t param5; uint32_t param6; uint32_t param7; int32_t param8; uint32_t param9; uint32_t param10; uint32_t param11; uint32_t param12; uint32_t param13; uint32_t param14; uint32_t param15; uint32_t param16; uint32_t param17; } sample_type_t;
新增结构体类型且结构体内有数组类型:
typedef struct { uint16_t param1; uint16_t param2; uint16_t param3; uint16_t param4[2]; } sample_two;
新增枚举类型:
typedef enum { PARAM1, PARAM2, PARAM3, PARAM4 } sample_three;
在“middleware/chips/ws63/nv/nv_config/cfg/acore/app.json”文件中添加新的NV项。
编译生成NV镜像
须知: 使用build.py编译非boot目标,如ws63-liteos-app、ws63-liteos-xts等时,会默认编译生成NV镜像并打包,打包时默认仅包含ws63_all_nv.bin,不包含ws63_all_nv_factory.bin,若需打包ws63_all_nv_factory.bin,可在编译命令中加入额外参数进行打包,例如:“python3 build.py -c ws63-liteos-app -def=PACKET_NV_FACTORY;”。
在全量编译时自动生成NV镜像,如图 build_nvbin.py脚本执行成功所示即为成功,即可在输出路径下生成“ws63_all_nv.bin”文件,可直接烧录使用。
输出路径:output\ws63\acore\nv_bin\ws63_all_nv.bin
NV API指南
功能描述
NV 当前支持存储最多16K(存在管理结构体占用空间,实际略小于16K)数据,备份分区大小与NV主区一致,总计占用32K flash 空间,API主要提供以下几种功能:
NV项写入:
保存需要存储的格式化数据。除普通属性的NV外,还可以设置NV项是否永久存储、是否加密存储和是否不可升级。
NV项读取:
从本地存储器读取NV数据。
NV信息查询:
查询NV是否已存储于本地存储器中。
查询NV空间的使用状态。
NV数据备份
对NV数据进行备份,仅在退出产测模式时会自动进行备份,不接受手动备份。
NV数据恢复
对NV数据进行恢复,可实现全量和部分恢复。
NV项的写入接口可设置NV项的属性,对于通过API动态添加的NV项,可在其写入的接口中传入其所拥有的特殊属性。
须知: NV数据写入flash不可避免的会增加flash的擦写次数,消耗flash寿命,甚至缩短产品使用年限。因此,一定要避免频繁写入NV数据。电池类产品设备,运行数据不会丢失,建议只在关机前写入要保存的NV数据,减少数据写入次数
接口说明
使用NV接口需要引用NV接口头文件,路径:include/middleware/utils/nv.h
NV模块主要提供以下API:
errcode_t uapi_nv_write(uint16_t key, const uint8_t *kvalue, uint16_t kvalue_length)
errcode_t uapi_nv_write_with_attr(uint16_t key, const uint8_t *kvalue, uint16_t kvalue_length,nv_key_attr_t *attr, nv_storage_completed_callback func)
errcode_t uapi_nv_read(uint16_t key, uint16_t kvalue_max_length, uint16_t *kvalue_length, uint8_t *kvalue)
errcode_t uapi_nv_read_with_attr(uint16_t key, uint16_t kvalue_max_length, uint16_t *kvalue_length,uint8_t *kvalue, nv_key_attr_t *attr)
errcode_t uapi_nv_get_store_status(nv_store_status_t *status)
errcode_t uapi_nv_set_restore_mode_all(void);
说明:该接口可实现备份区全部数据的恢复,工作区内没有进行备份数据将会被删除,即全量恢复后工作区和备份区的内容完全一致,调用后不会立即恢复,将在重新启动后进行恢复操作。 |
errcode_t uapi_nv_set_restore_mode_partitial(const nv_restore_mode_t *restore_mode);
通过控制恢复标记结构体内region_mode数组中的标记为0或者1,实现对指定的region区的数据恢复出厂。 说明:该接口可实现将备份区内指定region的数据恢复到工作区,标记为0的region区的数据将会保留工作区原数据,标记为1的region区内的数据恢复为备份区的数据(注:该region区域内未备份的数据将会被删除),调用后不会立即恢复,将在重新启动后进行恢复操作。 |
表 1 region区域划分表
说明:
NV恢复出厂时,最小单位为一个region区,不支持进行单独NV项的恢复。
“uapi_nv_set_restore_mode_all”和“uapi_nv_set_restore_mode_partitial”两个函数仅是设置NV恢复出厂的标记,实际恢复出厂的操作需要在复位设备后执行。
开发指引
下述为NV读写接口的使用指引。API调用处以加粗突出。
写入默认Normal类型NV。
uint8_t *test_nv_value; /* 要写入的NV value保存在test_nv_value中 */ uint32_t test_len = 15; /* 长度为test_len ,示例中为15*/ uint16_t key = TEST_KEY; /* TEST_KEY 为该key的ID*/ errcode_t nv_ret_value = uapi_nv_write(key, test_nv_value, test_len); if (nv_ret_value != ERRCODE_SUCC) { return ERRCODE_FAIL; } return ERRCODE_SUCC;
写入带属性NV(配置永久属性,其他略)。
uint8_t *test_nv_value; /* 要写入的NV value保存在test_nv_value中 */ uint32_t test_len = 15; /* 长度为test_len,例中为15 */ uint16_t key = TEST_KEY; nv_key_attr_t attr = {0}; attr.permanent = true;/* 永久属性设为true */ attr.encrypted = false; attr.non_upgrade = false; errcode_t nv_ret_value = uapi_nv_write_with_attr(key, test_nv_value, test_len, &attr, NULL); if (nv_ret_value != ERRCODE_SUCC) { return ERRCODE_FAIL; } /* APP PROCESS */ return ERRCODE_SUCC;
读取NV。
uint16_t key = TEST_KEY; uint16_t key_len= test_len; uint16_t real_len= 0; uint8_t *read_value = malloc(key_len); if (read_value == NULL) { return ERRCODE_MALLOC; } if (uapi_nv_read(key, key_len, &real_len, read_value) != ERRCODE_SUCC) { /* ERROR PROCESS */ uapi_free(read_value); return ERRCODE_FAIL; } /* APP PROCESS */ free(read_value); return ERRCODE_SUCC;
读取NV及属性。
uint16_t key = TEST_KEY; uint16_t key_len = test_len; uint16_t real_len = 0; uint8_t *read_value = malloc(key_len); nv_key_attr_t attr = {false, false, false, 0}; ext_errno nv_ret = uapi_nv_read_with_attr(key, key_len, &real_len, read_value, &attr); if (nv_ret != ERRCODE_SUCC ) { uapi_free(read_value); return ERRCODE_FAIL; } free(read_value); return ERRCODE_SUCC;
说明: 开发指引只是API接口的测试用例,为用户提供简单的sample参考,sample中省略了宏、部分变量、回调函数的定义过程和业务处理过程。
注意事项
uapi_nv_write:默认不对所存储的key添加额外属性(是否永久存储、是否加密存储等)。
uapi_nv_write_with_attr:可同时配置key属性和注册回调函数。在WS63V100中回调函数可以忽略,传NULL即可。
NV项存储在Flash中时,以Flash器件的sector为单位进行管理。NV页的数量默认配置为4页。对于4060Byte的sector,除去管理结构,单个非加密NV项的有效数据最大不应超过4060Byte。
NV属性结构体和NV空间状态结构体说明详见“nv.h”文件。