2. VM 掉电存储详细说明

下面分为4个部分来介绍VM的基本原理与特点:
  1. VM 记忆的基本原理

  2. VM 记忆的系统局限性

  3. NEW VM的预擦除

  4. NEW VM常见BUG

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一直,不再具备对卡音问题的优化;


下面分为6个部分来介绍VM功能的使用说明:
  1. VM 掉电存储使用说明

  2. VM 掉电存储版本简单说明

  3. 新旧VM文件组成及版本选择

  4. VM相关参数介绍

  5. VM掉电记忆存储接口

  6. VM常见问题介绍

2.5. VM 掉电存储使用说明

VM记忆存储使用的步骤分为三步:
  • 第一步:系统初始化时,调用函数vm_init_api()初始化VM功能。

  • 第二步:使用sysmem_write_api()接口把需要保存的数据写入FLASH。

  • 第三步:使用sysmem_read_api()接口读取写入的数据。

可参考”VM简单使用demo:


2.6. VM 掉电存储版本简单说明

目前SDK中VM有新旧两个版本可以选择:

备注

旧版VM:

  1. 可存储id号数量:128个;

  2. 单次写入最大数据长度:128个byte;

  3. 没有cache管理;

  4. 写数据时,会直接擦除flash;

备注

新版VM

  1. 可存储id号数量:512个;

  2. 单次写入最大数据长度:4096个byte;(若EEPROM分配给VM区域只有8K,则单次写入最大数据长度为:4092个byte);

  3. 增加cache管理,提升读取速度;

  4. 写数据时,需要擦除flash时,可选择不擦除,之后在空闲时手动调用预擦除功能实现擦除;(解决解码卡音的问题)

  5. 增加预擦除功能。

备注

新旧版本VM功能对比:

  1. 新版VM id号数量增多;

  2. 新版VM 单次写入最大数据长度增多;

  3. 新版VM 增加cache管理,提升VM读取速度;

  4. 新版VM 增加预擦除功能,可以在系统空闲时进行预擦除操作,可尽可能避免VM整理时关闭flash时间过长导致的卡音问题;

  5. 新版ID号 与 旧版index句柄 含义相同;


2.7. 新旧VM文件组成及版本选择

vm模块由vm_api.c和vm_api.h文件构成API层,包含ovm_api.c和nvm_api.c文件;

备注

用户可在 app_config.h 文件里选择使用新 / 旧版VM.

"新旧VM功能选择"

新旧VM功能选择

2.8. VM相关参数介绍

对于用户,我们需要关心的参数分别为:

  1. ID号(vm_api.h)

  2. 读/写入数据长度

  3. vm存储区域大小

对于新版VM

2.8.1. ID号(vm_api.h)

"sysmem_write_api 参数 id“

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)“

旧版VM掉电存储记忆项的定义(vm_api.h)


2.8.2. 读/写入数据长度

"sysmem_write_api 参数 length"

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区域大小设置"

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)“

VM掉电存储记忆项的定义(nvm_api.c和new_vm.h)

2.8.5. 新版vm格式整理后是否立即擦除旧半区区域功能

"config_vm_erasure_after_format_en“

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

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 系统空闲预擦除动作“

图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“

vm_demo


2.10.2. 调整VM区域大小设置:

节省VM占用系统空间可以从两个地方入手:

  1. 减少VM区域大小。

    具体参考上面”vm存储区域大小”章节的 vm存储区域大小 部分

  2. 新版VM可以减少VM格式整理时的缓存new_vm_buff

    可以适当减少BIT_MAX_LEN的长度。

    具体参考上面”新版VM格式整理时缓存空间设置new_vm_buff(new_vm.h)”章节的 新版VM格式整理时缓存空间设置 部分。


2.10.3. 新版VM在关机或者掉电后可能存在数据丢失BUG:

该问题原因可能有:

  1. AD14v1.7.0、v1.8.0 voice_toy工程 app_ld.c文件缺少(*.data)段(优先排查);

解决办法: FAQ:AD14v1.7.0、v1.8.0 voice_toy工程new_vm存在掉电后读取数据错误问题?

  1. 系统在关机前格式整理后没有做预擦除动作。

解决办法: FAQ:AD14/15/17/AC104 new_vm功能在关机或者掉电后可能存在数据丢失BUG


2.10.4. VM格式整理原理:

VM格式整理原理:

VM功能将EEPROM区域划分为A、B两块,A块记录VM数据,B块处于空闲状态,
当A块数据接近饱和时,会擦除B块并将A块的数据整合到B块,后续B块记录VM数据,A块处于空闲状态,以此往复。