AUTOSAR中的Mem Stack
可变性和耐久性是ECU内部数据的两种属性,如果期望某个数据既保持可变性,又能让数据在不同的上电周期能够被读取到(也即掉电时数据不丢失),那么数据需要被存储在非易失型数据存储当中(Nvm)。
在AUTOSAR架构当中,应用只能通过NvM模块访问非易失型数据数据,NvM模块提供了数据管理与维护的同步/异步服务。
Memory Stack参考架构图如下:

由于R21-11版本中引入了MemAcc模块,本文参考的最新规范文档当中,并未在上图体现,MemAcc工作在FEE/EA模块之下:

本文主要分析AUTOSAR工程对于NvData的处理,不涉及MemAcc细节,之后有空单独写文章介绍MemAcc的功能。
基本存储对象
我们给NvRam划分不同的Block(块),而对于一个NvRam Block,其包含的最小实体为“基本存储对象”,它可以出现在不同的存储位置(RAM/ROM/NV memory)。
RAM Block
RAM Block代表的是存储在RAM区域,作为NvRam Block一部分的基本存储实体。它包含用户数据,CRC值(可选),NvBlock头部(可选)。它用来存储实时数据,是NvRam Block的可选部分。

ROM Block
ROM Block代表的是存储在ROM区域,作为NvRam Block一部分的基本存储实体。它也是NvRam Block的可选部分。
NV Block
NV Block代表的是存储在非易失型存储的NvRam Block的一部分基本存储实体。它是NvRam Block的必要部分。
NV Block的内容是永久存在的,也可以在程序执行期间被修改,保留在FLASH当中。它包括NV用户数据,CRC值(可选),NV Block头部(可选)。它用来存储可以周期或者基于请求而存储的实时数据。
Administrative Block
这个Block在RAM当中,是NvRam Block的必要部分。
Administrative Block的内容不是永久存在的,它用来保存对应NvRam Block的属性/错误/状态等信息,是Dataset类型的NvRam Block
块管理类型
Nvm支持以下NvRam Blcok管理类型:
Native NvRam Block
Native NvRam Block是最简单的块管理类型,它允许以最小的代价向非易失型存储中写入或者从这里读取数据。
NVM_BLOCK_NATIVE类型的NvRam存储包括的基本存储对象有:
NV Blocks: 1
RAM Blocks: 1
ROM Blocks: 0..1
Administrative Blocks: 1
Redundant NVRAM block
这个块可以提升Native NvRam Block的故障冗余度,可靠性以及可用性,作用在数据损坏时。NVM_BLOCK_REDUNDANT类型的NvRam存储包含:
NV Blocks: 2
RAM Blocks: 1
ROM Blocks: 0..1
Administrative Blocks:1
当NV Block被视为无效时,会尝试用未损坏的NV Block恢复数据。
Dataset NVRAM block
Dataset NVRAM块是一组等大小数据块的数组。应用可以单个操作即访问到其中某一个数据块。
NVM_BLOCK_DATASET类型的存储包含:
NV Blocks: 1..NvMNvBlockNum
RAM Blocks: 1
ROM Blocks: 0..NvMRomBlockNum
Administrative Blocks: 1
NV + ROM 块的总大小需要在1到255之间。
同步机制
Nvm支持两种写入/读取Nvm模块RAM镜像的同步机制。
隐性同步
在隐性同步机制当中,应用和Nvm模块并行访问同一个RAM Block。通过调用Nvm接口,应用向RAM中写入/读取数据。
在这种场景下,不推荐将RAM块关联到某一SWC,并且共享此RAM块。无论SWC何时通过RAM块访问NvRam,它都需要确保RAM块数据的一致性,直到Nvm完成操作。
隐性同步机制的步骤:
写请求:
应用将待写入数据更新到RAM块
应用调用NvM_WriteBlock/NvM_WritePRAMBlock接口,请求Nvm服务
此后,应用不应当再修改RAM块数据,直到Nvm模块返回成功或失败的结果。当然,这个过程当中,可能还有其他的读取操作
应用可以轮询获取结果,或者设置回调函数等待调用
Nvm模块操作结束后,可以再次修改RAM块数据
多个块写入请求:
EcuM模块调用NvM_WriteAll接口
EcuM模块以轮询方式或者回调函数的方式获取结果
显性同步

在显性同步机制当中,Nvm模块定义一个用来交换应用RAM块数据的RAM镜像。应用将数据写入RAM块,并调用NvM接口,此后Nvm从RAM镜像读取数据,这个数据是从RAM块来的,最终会写入到NV Block。
这种机制的好处是,应用可以更高效地控制RAM块。应用调用ReadRamBlockFromNvM/WriteRamBlockToNvM接口读取/写入数据到RAM镜像中,应用需要保证读取/写入过程中数据的一致性。
至于缺点,则是需要NV Block等大小的额外的RAM消耗,数据拷贝操作也增加了。
当存在NvBlock类型的Swc时,使用这个机制,就可以将NVRAM块共享给不同的应用。
写入请求:
应用将数据写入到RAM块
应用调用NvM_WriteBlock/NvM_WritePRAMBlock接口
在NvM调用NvMWriteRamBlockToNvM接口之前,应用还可以修改RAM块数据的值
如果NvMWriteRamBlockToNvM被NvM调用,那么应用应当向NvM模块指定地址提供数据的拷贝。应用可以返回NOK表示数据不一致,在尝试了NvMRepeatMirrorOperations次数后,Nvm进行下一个请求。
数据写入Nvm之后,应用才能再次读写RAM块
应用可以通过轮询方式或者回调函数来获取结果
多个块写入请求(NvM_WriteAll):
EcuM调用NvM_WriteAll
在任务执行过程中,如果块设置了NvM_WriteRamBlockToNvM回调,那么应用需要向NvM模块指定地址提供数据的拷贝。应用可以返回NOK表示数据不一致,在尝试了NvMRepeatMirrorOperations次数后,Nvm进行下一个请求。
此后,应用可以再次读写RAM块
EcuM可以通过轮询方式或者回调函数来获取结果
其他功能
CRC校验
可选地,NvM内部可以为NVRAM Block生成CRC来作校验。
如果开启了NvMBlockUseCRCCompMechanism选项,基于CRC值,如果检测到数据未发生变化,那么NvM可以跳过写入操作。
错误恢复
如果配置了NvMRomBlockDataAddress或者NvMInitBlockCallback,那么NvM提供隐性的错误恢复功能,为NATIVE和REDUNDANT类型的NVRAM块在发生错误的情况下,载入默认值。
当然,也可以调用NvM_RestoreBlockDefaults接口显性地为所有类型地NVRAM块获取ROM中存储的默认值。对于DATASET类型,必须提供索引号。
写入验证
RAM Block数据被写入NV存储后,数据会被回读,以检查是否和RAM块中的值相同。
如果不相同,那么会再次尝试写入,同事上报DEM事件NVM_E_VERIFY_FAILED。
如果回读操作失败,那么则不会再次尝试。