.. _VM 掉电存储: VM 掉电存储说明 ========================================= 下面分为4个部分来介绍VM的基本原理与特点: 1. ":ref:`VM 记忆的基本原理`" 2. ":ref:`VM 记忆的系统局限性`" 3. ":ref:`NEW VM的预擦除`" 4. ":ref:`NEW VM常见BUG`" .. _VM 记忆的基本原理: VM 记忆的基本原理 ***************************** SDK提供了 vm掉电记忆存储功能 ,该功能用于在 内置flash里保存断电之后还需要保存的信息。 1、VM会将自己所分得的内部FLASH区域划为A,B两块区域, 2、例如A区域负责记录VM数据,B区域此时处于空闲状态,当A区域数据趋于饱和时,会把A区域的数据整合到B区域(即格式整理),后续B区域记录VM数据,A区域处于空闲状态,以此往复。 3、若此时格式整理后,A区域原有数据没有被擦除(未调用擦除函数) 4、用户去读取数据,会读取到原有区域的数据(即旧数据),导致数据错误或者读不到数据。 .. _VM 记忆的系统局限性: VM 记忆的系统局限性 ***************************** VM的数据记忆主要记录到系统flash中,系统flash中存放着整个系统的代码,大量的代码需要在系统flash中执行; VM的数据记忆过程中有可能需要对系统flash进行擦除操作; 系统flash在被擦除时不可以被访问,且不同的flash擦除时间不一致; 基于以上几点 **当VM触发到系统flash擦除时,这时系统flash代码是不能执行的** ,典型的现象就是 **解码卡音**。 为了优化上述的问题,编写新的NEW VM驱动,**在一定程度上改善此问题**。 .. _NEW VM的预擦除: NEW VM的预擦除 ***************************** 为了解决解码时,擦除系统flash可能导致的卡音,new vm尽量不在系统繁忙时对系统flash进行擦除; new vm提供了预擦除函数nvm_pre_erasure_next,可以在系统空闲时对系统flash当前与空闲区进行 **提前预擦除**、或 **滞后擦除**; new vm的写函数在AB区格式整理时,也不会对老区域进行擦除,而依赖预擦除在空闲时擦除;(未擦除再次上电会有老数据残留风险) .. _NEW VM常见BUG: NEW VM常见BUG ***************************** 部分客户在使用NEW VM,自己编写功能中,遗忘或者未能合理调用预擦除功能导致,数据不能有效更新; 此问题有两种解决方式: 1、在写入数据后,系统掉电或关机前,调用预擦除;(推荐) 2、打开config_vm_erasure_after_format_en变量,打开此变量后,new vm驱动会在需要擦除时实时擦除系统flash,这样一来NEW VM驱动的行为将和老的VM一直,不再具备对卡音问题的优化; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 下面分为7个部分来介绍VM功能: 1. ":ref:`VM 掉电存储使用说明`" 2. ":ref:`VM 掉电存储版本简单说明`" 3. ":ref:`新旧VM文件组成及版本选择`" 4. ":ref:`VM相关参数介绍`" 5. ":ref:`VM掉电记忆存储接口`" 6. ":ref:`VM常见问题介绍`" .. _VM 掉电存储使用说明: VM 掉电存储使用说明 ****************************** **VM记忆存储使用的步骤分为三步:** - 第一步:系统初始化时,调用函数vm_init_api()初始化VM功能。 - 第二步:使用vm_write()接口把需要保存的数据写入FLASH。 - 第三步:使用vm_read()接口读取写入的数据。 可参考":ref:`VM简单使用demo`" ^^^^^^^^^^^^^^^^^^^^^^^ .. _VM 掉电存储版本简单说明: VM 掉电存储版本简单说明 ****************************** 目前SDK中VM有新旧两个版本可以选择: .. note:: 旧版VM功能: 1. 可存储id号数量:128个; 2. 单次写入最大数据长度:128个byte; 3. 没有cache管理; 4. 没有预擦除功能; .. note:: 新版VM功能 1. 可存储id号数量:512个; 2. 单次写入最大数据长度:4096个byte;(若EEPROM分配给VM区域只有8K,则单次写入最大数据长度为:4092个byte); 3. 增加cache管理,提升读取速度; 4. 增加预擦除功能。 .. note:: 新旧版本VM功能对比: 1. 新版VM id号数量增多; 2. 新版VM 单次写入最大数据长度增多; 3. 新版VM 增加cache管理,提升VM读取速度; 4. 新版VM 增加预擦除功能,可以在系统空闲时进行预擦除操作,可尽可能避免VM整理时关闭flash时间过长导致的卡音问题; 5. 新版ID号 与 旧版index句柄 含义相同; ^^^^^^^^^^^^^^^^^^^^^^^ .. _新旧VM文件组成及版本选择: 新旧VM文件组成及版本选择 ****************************** vm模块由vm_api.c和vm_api.h文件构成API层,包含ovm_api.c和nvm_api.c文件; .. note:: 在SDK 为 AD14/15/AC104的v1.7.0版本(包括1.7.0版本)以前版本,用户可在 **vm_api.h** 文件里选择使用新 / 旧版VM. .. image:: vm_switch.png :alt: "新旧VM功能选择" :align: center .. centered:: 新旧VM功能选择 .. note:: 在SDK 为 AD14/15/AC104的v1.7.0版本以后,vm配置选项更改位置,用户可在 **app_config.h** 文件里选择使用新 / 旧版VM. .. image:: vm_mode_switch.png :alt: "新旧VM功能选择" :align: center .. centered:: 新旧VM功能选择 .. _VM相关参数介绍: VM相关参数介绍 ****************************** 对于用户,我们需要关心的参数分别为: 1. ":ref:`ID号(vm_api.h)`" 2. ":ref:`vm读/写入数据长度`" 3. ":ref:`vm存储区域大小`" 对于新版VM 4. ":ref:`新版VM格式整理时缓存空间设置`" 5. ":ref:`新版vm格式整理后是否立即擦除旧半区区域功能`" 6. ":ref:`新版vm是否支持多段读功能`" 下面逐一介绍: .. _ID号(vm_api.h): ID号(vm_api.h) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. image:: 1-2-nvm_id.png :alt: "vm_write 参数 id“ :align: center .. centered:: vm_write参数 .. important:: 旧版VM ID号最多128个,新版VM ID号最多512个;(旧版VM index号在新版vm仍可通用) 新版VM ID号最多支持512个,且不再需要自定义对应ID的数据长度。 用户可在vm_api.h的VM_INDEX里添加自己的id号。 **注意:** 1~32号ID为系统使用,用户不可修改其顺序 .. image:: 1-3-nvm_index.png :alt: "旧版VM掉电存储记忆项的定义(vm_api.h)“ :align: center .. centered:: 旧版VM掉电存储记忆项的定义(vm_api.h) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. _vm读/写入数据长度: 读/写入数据长度 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. image:: 1-4-nvm_len.png :alt: "vm_write参数 length" :align: center .. centered:: vm_write参数length .. important:: 旧版VM读/写长度最多支持128个byte; 新版VM读/写长度最多支持4096个byte; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. _vm存储区域大小: vm存储区域大小 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. important:: VM记忆的数据 是 EEPROM区划分出一定空间大小给VM使用,该区域大小可由下载目录里的isd_config.ini文件配置。 (该配置参数详细说明可参考":ref:`isd_config.ini文件介绍`") **注意:** VM存储区域大小分配的EEPROM空间不得低于8K字节,且需为4K字节的倍速,即8K,12K,16K等等。 .. image:: vm_area_config.png :alt: "VM区域大小设置" :align: center .. centered:: VM区域大小设置" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. _新版VM格式整理时缓存空间设置: 新版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与读/写数据最大长度为两个概念) .. image:: 1-1-nvm_api.png :alt: "VM掉电存储记忆项的定义(nvm_api.c和new_vm.h)“ :align: center .. centered:: VM掉电存储记忆项的定义(nvm_api.c和new_vm.h) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. _新版vm格式整理后是否立即擦除旧半区区域功能: 新版vm格式整理后是否立即擦除旧半区区域功能 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. image:: vm_special_cfg.png :alt: "config_vm_erasure_after_format_en“ :align: center .. centered:: config_vm_erasure_after_format_en | config_vm_erasure_after_format_en 用于控制新版vm格式整理后是否立即擦除旧半区区域; | 0 : 不立即擦除(默认值) | 1 : 立即擦除 .. important:: 该功能直观影响为:打开该功能后,vm进行格式整理 **会** 调用到flash擦除,如果系统此时正在解码,那么解码可能会出现卡音的现象。 而默认关闭该功能后,vm进行格式整理 **不会** 调用到flash擦除,而是等到 **系统空闲时程序员调用预擦除函数进行擦除动作** ,这样就不会影响到系统此时正进行的解码。 **关闭该功能后,未在系统空闲时进行擦除动作,那么可能导致下次上电,VM读取到老旧的数据。** ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. _新版vm是否支持多段读功能: 新版vm是否支持多段读功能 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. image:: vm_special_cfg.png :alt: "config_vm_multiple_read_en“ :align: center .. centered:: config_vm_multiple_read_en | config_vm_multiple_read_en 用于控制新版vm是否支持多段读功能; | 0 : 不支持多段读(默认值) | 1 : 支持多段读 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. _VM掉电记忆存储接口: VM掉电记忆存储接口 **************************************************************************************************** 函数u32 syscfg_vm_init(u32 addr, u32 size) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 此函数用来初始化vm虚拟存储系统,其中参数: 1. eeprom_saddr:vm区域的起始地址。 2. eeprom_size:vm区域的空间长度。 3. 返回值: | 成功:0; | 失败:错误号,可参考errno-base.h; 函数u32 vm_write(u32 id,u8 \*buf,u32 len) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 此函数用来把对应hdl的数据存储到vm虚拟存储系统,其中参数: 1. hdl:访问vm的id。 2. buf:vm读数据buffer。 3. len:数据长度。 4. 返回值: | 成功:写入长度; | 失败:错误号,可参考errno-base.h; 函数u32 vm_read(u32 id ,u8 \*buf,u32 len) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 此函数用来把对应hdl的数据从vm虚拟存储系统读出来,其中参数: 1. id:访问vm的id。 2. buf:vm读数据buffer。 3. len:数据长度。 4. 返回值: | 成功:写入长度; | 失败:错误号,可参考errno-base.h; 函数 u32 vm_pre_erase(void) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 此函数用于预擦除设备,在系统空闲时主动调用提前擦除flash,可尽量避免VM做整理时关flash时间过长导致卡音问题; | 该函数只有在新版VM处生效,旧版VM没有该功能。 | 示例:音乐模式下,500MS消息来时若系统处于空闲状态,则会进行预擦除动作: .. image:: 2-1-pre_erase.png :alt: "图2.1 系统空闲预擦除动作“ :align: center .. centered:: 图2.1 系统空闲预擦除动作 函数 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、返回值:无 .. _VM常见问题介绍: VM常见问题介绍 **************************************************************************************************** .. _VM简单使用demo: VM简单使用demo: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 用户可在app/bsp/start/flash_init.c里的vm_init_api()函数找到demo示例。 .. image:: vm_demo.png :alt: "vm_demo“ :align: center .. centered:: vm_demo ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 调整VM区域大小设置: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 节省VM占用系统空间可以从两个地方入手: 1. 减少VM区域大小。 具体参考上面":ref:`vm存储区域大小`"章节的 vm存储区域大小 部分 2. 新版VM可以减少VM格式整理时的缓存new_vm_buff 可以适当减少BIT_MAX_LEN的长度。 具体参考上面":ref:`新版VM格式整理时缓存空间设置`"章节的 新版VM格式整理时缓存空间设置 部分。 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 新版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存在掉电后读取数据错误问题? `_ 2. 系统在关机前格式整理后没有做预擦除动作。 解决办法: `FAQ:AD14/15/17/AC104 new_vm功能在关机或者掉电后可能存在数据丢失BUG `_ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ VM格式整理原理: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **VM格式整理原理:** | VM功能将EEPROM区域划分为A、B两块,A块记录VM数据,B块处于空闲状态, | 当A块数据接近饱和时,会擦除B块并将A块的数据整合到B块,后续B块记录VM数据,A块处于空闲状态,以此往复。