2. VM 掉电存储详细说明
- 下面分为4个部分来介绍VM的基本原理与特点:
2.1. VM 记忆的基本原理
SDK提供了 vm掉电记忆存储功能 ,该功能用于在 内置flash里保存断电之后还需要保存的信息。
1、VM会将自己所分得的内部FLASH区域划为A,B两块区域,
2、例如A区域负责记录VM数据,B区域此时处于空闲状态,当A区域数据趋于饱和时,会把A区域的数据整合到B区域(即格式整理),后续B区域记录VM数据,A区域处于空闲状态,以此往复。
3、若此时格式整理后,A区域原有数据没有被擦除(未调用擦除函数)
4、用户去读取数据,会读取到原有区域的数据(即旧数据),导致数据错误或者读不到数据。
2.2. VM 记忆的系统局限性
VM的数据记忆主要记录到系统flash中,系统flash中存放着整个系统的代码,大量的代码需要在系统flash中执行;
VM的数据记忆过程中有可能需要对系统flash进行擦除操作;
系统flash在被擦除时不可以被访问,且不同的flash擦除时间不一致;
基于以上几点 当VM触发到系统flash擦除时,这时系统flash代码是不能执行的 ,典型的现象就是 解码卡音。
为了优化上述的问题,编写新的NEW VM驱动,在一定程度上改善此问题。
2.3. NEW VM的预擦除
为了解决解码时,擦除系统flash可能导致的卡音,new vm尽量不在系统繁忙时对系统flash进行擦除;
new vm提供了预擦除函数nvm_pre_erasure_next,可以在系统空闲时对系统flash当前与空闲区进行 提前预擦除、或 滞后擦除;
new vm的写函数在AB区格式整理时,也不会对老区域进行擦除,而依赖预擦除在空闲时擦除;(未擦除再次上电会有老数据残留风险)
2.4. NEW VM常见BUG
部分客户在使用NEW VM,自己编写功能中,遗忘或者未能合理调用预擦除功能导致,数据不能有效更新;
此问题有两种解决方式:
1、在写入数据后,系统掉电或关机前,调用预擦除;(推荐)
2、打开config_vm_erasure_after_format_en变量,打开此变量后,new vm驱动会在需要擦除时实时擦除系统flash,这样一来NEW VM驱动的行为将和老的VM一直,不再具备对卡音问题的优化;
2.5. VM 掉电存储使用说明
- VM记忆存储使用的步骤分为三步:
第一步:系统初始化时,调用函数vm_init_api()初始化VM功能。
第二步:使用sysmem_write_api()接口把需要保存的数据写入FLASH。
第三步:使用sysmem_read_api()接口读取写入的数据。
可参考”VM简单使用demo:”
2.6. VM 掉电存储版本简单说明
目前SDK中VM有新旧两个版本可以选择:
备注
旧版VM:
可存储id号数量:128个;
单次写入最大数据长度:128个byte;
没有cache管理;
写数据时,会直接擦除flash;
备注
新版VM
可存储id号数量:512个;
单次写入最大数据长度:4096个byte;(若EEPROM分配给VM区域只有8K,则单次写入最大数据长度为:4092个byte);
增加cache管理,提升读取速度;
写数据时,需要擦除flash时,可选择不擦除,之后在空闲时手动调用预擦除功能实现擦除;(解决解码卡音的问题)
增加预擦除功能。
备注
新旧版本VM功能对比:
新版VM id号数量增多;
新版VM 单次写入最大数据长度增多;
新版VM 增加cache管理,提升VM读取速度;
新版VM 增加预擦除功能,可以在系统空闲时进行预擦除操作,可尽可能避免VM整理时关闭flash时间过长导致的卡音问题;
新版ID号 与 旧版index句柄 含义相同;
2.7. 新旧VM文件组成及版本选择
vm模块由vm_api.c和vm_api.h文件构成API层,包含ovm_api.c和nvm_api.c文件;
备注
用户可在 app_config.h 文件里选择使用新 / 旧版VM.
新旧VM功能选择
2.8. VM相关参数介绍
对于新版VM
2.8.1. ID号(vm_api.h)
sysmem_write_api 参数
重要
旧版VM ID号最多128个,新版VM ID号最多512个;(旧版VM index号在新版vm仍可通用)
新版VM ID号最多支持512个,且不再需要自定义对应ID的数据长度。
用户可在sys_memory.h的VM_INDEX里添加自己的id号。
注意: 1~32号ID为系统使用,用户不可修改其顺序
旧版VM掉电存储记忆项的定义(vm_api.h)
2.8.2. 读/写入数据长度
sysmem_write_api 参数length
重要
旧版VM读/写长度最多支持128个byte;
新版VM读/写长度最多支持4096个byte;
2.8.3. vm存储区域大小
重要
VM记忆的数据 是 EEPROM区划分出一定空间大小给VM使用,该区域大小可由下载目录里的isd_config.ini文件配置。 (该配置参数详细说明可参考”isd_config.ini文件介绍”)
- 注意:
VM存储区域大小分配的EEPROM空间不得低于8K字节,且需为4K字节的倍速,即8K,12K,16K等等。
VM区域大小设置”
2.8.4. 新版VM格式整理时缓存空间设置new_vm_buff(new_vm.h)
重要
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.8.5. 新版vm格式整理后是否立即擦除旧半区区域功能
config_vm_erasure_after_format_en
config_vm_erasure_after_format_en 用于控制新版vm格式整理后是否立即擦除旧半区区域;0 : 不立即擦除(默认值)1 : 立即擦除
重要
该功能直观影响为:打开该功能后,vm进行格式整理 会 调用到flash擦除,如果系统此时正在解码,那么解码可能会出现卡音的现象。
而默认关闭该功能后,vm进行格式整理 不会 调用到flash擦除,而是等到 系统空闲时程序员调用预擦除函数进行擦除动作 ,这样就不会影响到系统此时正进行的解码。
关闭该功能后,未在系统空闲时进行擦除动作,那么可能导致下次上电,VM读取到老旧的数据。
2.8.6. 新版vm多段读功能开关
config_vm_multiple_read_en
config_vm_multiple_read_en 用于控制新版vm是否支持多段读功能;0 : 不支持多段读(默认值)1 : 支持多段读
2.9. VM掉电记忆存储接口
函数接口在sys_memory.c
2.9.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.9.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.9.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.9.4. 函数 u32 sysmem_pre_erase_api(void)
此函数用于预擦除设备,在系统空闲时主动调用提前擦除flash,可尽量避免VM做整理时关flash时间过长导致卡音问题;该函数只有在新版VM处生效,旧版VM没有该功能。示例:音乐模式下,500MS消息来时若系统处于空闲状态,则会进行预擦除动作:图2.1 系统空闲预擦除动作
备注
该函数在擦除前会判断要擦除的目标区域是否已经擦除过,如果已经擦除过,则不会继续执行擦除动作,所以该函数可以重复调用,不需要担心每次调用都会对flash进行擦除。
2.9.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.10. VM常见问题介绍
2.10.1. VM简单使用demo:
用户可在app/bsp/start/flash_init.c里的vm_init_api()函数找到demo示例。
vm_demo
2.10.2. 调整VM区域大小设置:
节省VM占用系统空间可以从两个地方入手:
- 减少VM区域大小。
具体参考上面”vm存储区域大小”章节的 vm存储区域大小 部分
- 新版VM可以减少VM格式整理时的缓存new_vm_buff
可以适当减少BIT_MAX_LEN的长度。
具体参考上面”新版VM格式整理时缓存空间设置new_vm_buff(new_vm.h)”章节的 新版VM格式整理时缓存空间设置 部分。
2.10.3. 新版VM在关机或者掉电后可能存在数据丢失BUG:
该问题原因可能有:
AD14v1.7.0、v1.8.0 voice_toy工程 app_ld.c文件缺少(*.data)段(优先排查);
解决办法: FAQ:AD14v1.7.0、v1.8.0 voice_toy工程new_vm存在掉电后读取数据错误问题?
系统在关机前格式整理后没有做预擦除动作。
2.10.4. VM格式整理原理:
VM格式整理原理:
VM功能将EEPROM区域划分为A、B两块,A块记录VM数据,B块处于空闲状态,当A块数据接近饱和时,会擦除B块并将A块的数据整合到B块,后续B块记录VM数据,A块处于空闲状态,以此往复。