2. VM 掉电存储详细说明
AW31N SDK提供了VM 掉电存储模块。
2.1. VM 掉电存储作用和数据存储
SDK提供了 vm掉电记忆存储功能 ,该功能用于在 内置flash里保存断电之后还需要保存的信息。
使用VM存储的数据会记忆在FLASH的”EEPROM”区域,该区域大小可由下载目录的”isd_config.ini”文件配置,使用VM功能时EEPROM空间不得低于8K字节,且需为8K字节的倍数(即8K,16K,24K 以此类推)。
EEPROM_ADR=AUTO; EEPROM_LEN=24K; EEPROM_OPT=1;
2.2. VM 掉电存储使用说明
- VM记忆存储使用的步骤分为三步:
第一步:系统初始化时,调用函数vm_init_api()初始化VM功能。
第二步:使用sysmem_write_api()接口把需要保存的数据写入FLASH。
第三步:使用sysmem_read_api()接口读取写入的数据。
可参考”VM简单使用demo:”
2.3. VM 掉电存储版本简单说明
目前SDK中VM有新旧两个版本可以选择,
默认选择新版本
:
Note
旧版VM:
可存储id号数量:128个;
单次写入最大数据长度:128个byte;
没有cache管理;
没有预擦除功能;
Note
新版VM
可存储id号数量:512个;
单次写入最大数据长度:4096个byte;(若EEPROM分配给VM区域只有8K,则单次写入最大数据长度为:4092个byte);
增加cache管理,提升读取速度;
增加预擦除功能。
Note
新旧版本VM功能对比:
新版VM id号数量增多;
新版VM 单次写入最大数据长度增多;
新版VM 增加cache管理,提升VM读取速度;
新版VM 增加预擦除功能,可以在系统空闲时进行预擦除操作,可尽可能避免VM整理时关闭flash时间过长导致的卡音问题;
新版ID号 与 旧版index句柄 含义相同;
2.4. 新旧VM文件组成及版本选择
vm模块由vm_api.c和vm_api.h文件构成API层,包含vm_api.c和nvm_api.c文件;
Note
用户可在 board_awxxx_cfg.h 文件里选择使用新 / 旧版VM.
#define USE_NEW_VM 1
#define USE_OLD_VM 2
#define SYS_MEMORY_SELECT USE_NEW_VM
2.5. VM相关参数介绍
对于新版VM
2.5.1. ID号(vm_api.h)
sysmem_write_api 参数
Important
旧版VM ID号最多128个,新版VM ID号最多512个;(旧版VM index号在新版vm仍可通用)
新版VM ID号最多支持512个,且不再需要自定义对应ID的数据长度。
用户可在sys_memory.h的VM_INDEX里添加自己的id号。
注意:
1~32号ID为系统使用,用户不可修改
33~99号ID为 开发者使用
,用户可修改,在user_cfg_id.h可添加
100~号ID为 sdk保留配置项
,用户不可修改
2.5.2. 读/写入数据长度
sysmem_write_api 参数length
Important
旧版VM读/写长度最多支持128个byte;
新版VM读/写长度最多支持4096个byte;
2.5.3. vm存储区域大小
Important
VM记忆的数据 是 EEPROM区划分出一定空间大小给VM使用,该区域大小可由下载目录里的isd_config.ini文件配置。 (该配置参数详细说明可参考” isd_config.ini文件介绍 “)
- 注意:
VM存储区域大小分配的EEPROM空间不得低于8K字节,且需为8K字节的倍速,即8K,16K,24K等等。
补充说明:因为要做擦除备份,实际可用存储数据的空间大小只能是配置的一半,例如配置了8K,则可用存储空间即是4K。
VM区域大小设置”
2.5.4. 新版VM格式整理时缓存空间设置new_vm_buff(new_vm.h)
Important
new_vm_buff,该buff用于vm格式整理时数据的缓存。
该buff由 用户自定义最大id数量(BIT_MAP_SIZE) + 单个id在整理时数据缓存的最大长度(BIT_MAX_LEN) 两部分组成。
BIT_MAP_SIZE :即BIT_MAP:vm最多可以存储的id数量,固定为512个。
BIT_MAX_LEN :即VM格式整理时数据缓存的大小,该值越大,则整理速度越快,该值越小,则整理速度越慢。(注意:该buf与读/写数据最大长度为两个概念)
VM掉电存储记忆项的定义(nvm_api.c和new_vm.h)
2.5.5. 新版vm格式整理后是否立即擦除旧半区区域功能
config_vm_erasure_after_format_en
config_vm_erasure_after_format_en 用于控制新版vm格式整理后是否立即擦除旧半区区域;0 : 不立即擦除(默认值)1 : 立即擦除而默认关闭该功能时,系统在vm操作时,进行VM格式整理却不会进行擦除动作,而是等到系统空闲时进行擦除动作。
2.5.6. 新版vm是否支持多段读功能
config_vm_multiple_read_en
config_vm_multiple_read_en 用于控制新版vm是否支持多段读功能;0 : 不支持多段读(默认值)1 : 支持多段读
2.6. VM掉电记忆存储接口
函数接口在sys_memory.c
2.6.1. 函数u32 syscfg_vm_init(u32 mem_addr, u32 mem_size)
此函数用来初始化vm虚拟存储系统,其中参数:
1. eeprom_saddr:vm区域的起始地址。 2. eeprom_size:vm区域的空间长度。 3. 返回值: 成功:0; 失败:错误号,可参考errno-base.h;
2.6.2. 函数u32 sysmem_write_api(u32 id,u8 *data_buf, u32 len)
此函数用来把对应hdl的数据存储到vm虚拟存储系统,其中参数:
1. hdl:访问vm的id。 2. buf:vm读数据buffer。 3. len:数据长度。 4. 返回值: 成功:成功写入VM数据长度; 失败:错误号,可参考errno-base.h;
2.6.3. 函数u32 sysmem_read_api(u32 id ,u8 *data_buf, u32 len)
此函数用来把对应hdl的数据从vm虚拟存储系统读出来,其中参数:
1. id:访问vm的id。 2. buf:vm读数据buffer。 3. len:数据长度。 4. 返回值: 成功:成功获取到的数据长度; 失败:错误号,可参考errno-base.h;
2.6.4. 函数 u32 sysmem_pre_erase_api(void)
此函数用于预擦除设备,在系统空闲时主动调用提前擦除flash,可尽量避免VM做整理时关flash时间过长导致卡音问题;该函数只有在新版VM处生效,旧版VM没有该功能。示例:音乐模式下,500MS消息来时若系统处于空闲状态,则会进行预擦除动作:图2.1 系统空闲预擦除动作
2.6.5. 函数void nvm_pre_erasure_next(NEW_VM_OBJ *p_nvm, u16 using_next, u16 idle_next)
此函数为NEW VM中独有接口,由2.4 函数 u32 vm_pre_erase() 调用,用于系统空闲时选择擦除当前VM已存储的数据往后的flash扇区,以及空闲VM需要往后擦除的flash扇区数,用户可自行修改需要擦除的flash扇区数,其中参数:
1、p_nvm:NEW VM句柄指针; 2、using_next:当前VM存储块需要往后擦除的flash扇区数; 3、idle_next:空闲VM存储块需要往后擦除的flash扇区数; 4、返回值:无
2.7. VM常见问题介绍
2.7.1. VM简单使用demo:
用户可在app/bsp/start/flash_init.c里的vm_init_api()函数找到demo示例。
vm_demo
2.7.2. 调整VM区域大小设置:
节省VM占用系统空间可以从两个地方入手:
- 减少VM区域大小。
具体参考上面”vm存储区域大小”章节的 vm存储区域大小 部分
- 新版VM可以减少VM格式整理时的缓存new_vm_buff
可以适当减少BIT_MAX_LEN的长度。
具体参考上面”新版VM格式整理时缓存空间设置new_vm_buff(new_vm.h)”章节的 新版VM格式整理时缓存空间设置 部分。
2.7.3. 新版VM在关机或者掉电后可能存在数据丢失BUG:
2.7.4. VM格式整理原理:
VM格式整理原理:
VM功能将EEPROM区域划分为A、B两块,A块记录VM数据,B块处于空闲状态,当A块数据接近饱和时,会擦除B块并将A块的数据整合到B块,后续B块记录VM数据,A块处于空闲状态,以此往复。
2.7.5. VM卡音问题原因和解决办法:
问题原因:
VM格式整理时 数据整合过程需要关中断并擦除空闲块的flash扇区,时间较长可能会导致解码卡音/蓝牙无法收发等问题;
解决办法:
NEW VM可以在系统空闲状态时调用sysmem_pre_erase_api()函数;该函数作用是提前擦除当前已存储数据往后的flash扇区,以及空闲块的flash扇区数(内部会限制不超出EEPROM区域扇区数),即把格式整理的VM擦除提前处理。SDK上常见操作如:
(一)切换模式时做擦除动作;
(二)500ms时,系统空闲会做擦除动作;
(三)系统关机/睡眠前会做擦除动作;
2.7.6. VM删除id功能:
AW31的新版VM提供了可以删除ID功能,目前暂未提供应用接口,用户可以直接调用底层接口进行删除。 添加接口形式如下图:
vm_delete_id“
使用原理:输入位图(ignore_map),bit几对应id号,置1表示删除该id。
- 使用参数:
1. ignore_map:位图,bit几对应id号2. ignore_len:位图长度(要删除的id号不应超过位图长度)vm_delete_id_demo
使用示例代码:
#include "new_vm.h" void test() { log_info("test\n"); u8 buf1[5] = {1,2,3,4,5}; u8 buf2[5] = {0}; u8 buf3[5] = {0}; u8 buf4[5] = {0}; u8 buf5[5] = {0}; u32 ignore_bit_map[BIT_MAP_SIZE / 4] = {0}; log_info("write 0 1 77 99\n"); nvm_write_api(0, buf1, 5); //往id 0 写入{1,2,3,4,5} nvm_write_api(1, buf1, 5); nvm_write_api(77, buf1, 5); nvm_write_api(99, buf1, 5); log_info("read 0 1 77 99\n"); nvm_read_api(0, buf2, 5); //读取是否写入成功 nvm_read_api(1, buf3, 5); nvm_read_api(77, buf4, 5); nvm_read_api(99, buf5, 5); log_info("read first 0 1 77 99\n"); log_info_hexdump((u8*)buf2 ,sizeof(buf2)); //打印读到的数据 log_info_hexdump((u8*)buf3 ,sizeof(buf3)); log_info_hexdump((u8*)buf4 ,sizeof(buf4)); log_info_hexdump((u8*)buf5 ,sizeof(buf5)); //在位图置上想要删除的id对应的bit位 ignore_bit_map[0] |= BIT(0); //如:删除id 0 ignore_bit_map[2] |= BIT(13); //如:删除id 77 ignore_bit_map[3] |= BIT(3); //如:删除id 99 log_info("delete 0 77 99\n"); nvm_delete_id(ignore_bit_map, BIT_MAP); //调用删除接口 log_info("buff reset\n"); memset(buf2, 0, 5); memset(buf3, 0, 5); memset(buf4, 0, 5); memset(buf5, 0, 5); log_info("read 0 1 77 99\n"); nvm_read_api(0, buf2, 5); //再次读取数据,确认是否删除成功 nvm_read_api(1, buf3, 5); nvm_read_api(77, buf4, 5); nvm_read_api(99, buf5, 5); log_info("read twice 0 1 77 99\n"); log_info_hexdump((u8*)buf2 ,sizeof(buf2)); //打印读到的数据 log_info_hexdump((u8*)buf3 ,sizeof(buf3)); log_info_hexdump((u8*)buf4 ,sizeof(buf4)); log_info_hexdump((u8*)buf5 ,sizeof(buf5)); }