【CP AUTOSAR】NvM(NVRAMManager)分析和使用
本文介绍了CP AUTOSAR架构下的NvM组件配置经验,基于S32K312芯片和Vector工具链。NvM作为MemoryServices层的关键模块,负责非易失性数据管理,通过MemIf访问FLASH/EEPROM。文章详细阐述了NvM的基本架构、存储对象类型(NV/RAM/ROM/管理块)及三种块管理类型(NATIVE/REDUNDANT/DATASET),并提供了配置参数示例说明NvM与底
文章目录
- 前言
- 一、NvM功能概述
- 二、基本架构
- 三、功能需求
- 四、设计说明
-
- (一)、NvM启动
- (二)、NvM关闭
- (三)、NvM的并行写访问
- (四)、NVRAM块一致性检查
- (五)、错误恢复
- (六)、根据ROM数据恢复RAM块
- (七)、通过ROM默认数据实现RAM块的隐式恢复
- (八)、通过ROM默认数据实现RAM块的显式恢复
- (九)、对NV块的不完整写操作的检测
- (十)、单个块请求的终止
- (十一)、多个块请求的终止
- (十二)、异步请求/任务处理的常规处理
- (十三)、NVRAM块写保护
- (十四)、RAM块数据的验证和修改
- (十五)、应用程序与NvM之间的通信及隐式同步
- (十六)、NVRAM块的正常及扩展运行时准备工作
- (十七)、应用程序与NvM之间的通信及显式同步
- (十八)、Static Block ID检查
- (十九)、重读
- (二十)、写校验
- (二十一)、NvM中的NV数据比较
- (二十二)、NvM和BswM的交互
- (二十三)、块压缩
- (二十四)、块加密
- 五、主要代码和参数描述
- 六、DaVinci Configurator主要配置
- 七、使用例子
- 八、参考资料
- 总结
前言
本文介绍CP AUTOSAR 架构下的NvM组件,基于S32K312芯片、Vector提供的CBD包,使用DaVinci Configurator工具进行配置的经验。
NvM组件位于MemoryServices层里,下层为MemIf,向User提供各种非易失存储器的数据管理。
NvM通过MemIf访问MCU的内外部FLASH和EEPROM,是软件里直接被应用层和Rte访问的模块。
NvM模块应提供同步和异步服务,用于非易失性数据的管理与维护(包括初始化、读取、写入、控制操作)。




上图为CP AUTOSAR存储架构。
一、NvM功能概述
(一)、术语
1、Basic Storage Object
基本存储单元是NVRAM Block的最小组成单元。多个基本存储单元可以组合成一个NVRAM块。一个基本存储单元可以存放在不同的存储位置(RAM/ROM/NV存储器)中。
2、NVRAM Block
NVRAM块指的是整个结构,它用于管理和存储一块NV data。
3、NV data
需要存储在非易失性存储器中的数据。
4、Block Management Type
NVRAM Block的类型。
5、RAM Block
RAM Block是一种基本存储对象。它表示NVRAM Block中位于内存中的那一部分。
6、ROM Block
ROM Block是一种基本存储单元。它表示NVRAM Block中位于ROM中的那一部分。而ROM Block是NVRAM块的一个可选组成部分。
7、NV Block
NV Block是一种基本存储对象。它代表了NVRAM Block中存放在非易失性内存中的那一部分。NV Block是NVRAM Block的一个必选组成部分。
8、NV Block Header
如果Static Block ID机制使能,那么在NV Block中还会包含其他信息。
9、Administrative Block
Administrative Block是一种基本存储对象。它存放在RAM中。管理块是NVRAM Block中必不可少的一部分。
(二)、模块依赖性
NvM下层为MemIf,通过MemIf去访问Fee和Ea。
通过MemIf可以去内外部存储设备,存储设备的驱动代码需要支持写入、读取及擦除操作等接口。
作为可配置选项,NvM模块可使用CRC例程(支持 8 位 / 16 位 / 32 位校验),对NVRAM数据块进行CRC校验值的生成与校验。该CRC生成程序需由外部提供。
(三)、其他
NvM可通过配置,调用其他模块或集成者代码所提供的功能。例如,使用Csm对数据块进行加密和解密操作,或对数据块进行压缩处理。
二、基本架构

(一)、配置参数示例
NvM模块支持最大65536个逻辑数据块,每个逻辑数据块的理论上的最大容量为64Kbyte。
以下为示例说明NvM和MemIf之间的寻址机制,NvMNvBlockBaseNumber、NvMDatasetSelectionBits与EA_BLOCK_NUMBER、FEE_BLOCK_NUMBER之间的对应关系:
对于示例A和示例B,均采用以下简单计算公式:
FEE/EA_BLOCK_NUMBER=(NvMNvBlockBaseNumber<<NvMDatasetSelectionBits)+DataIndex。
示例 A
配置参数NvMDatasetSelectionBits设为2。由此可知,配置参数NvMNvBlockBaseNumber的位数为14位。
NvMNvBlockBaseNumber的取值范围:0x1~0x3FFE。
DataIndex的取值范围:0x0~0x3(2^NvMDatasetSelectionBits - 1 )。
FEE_BLOCK_NUMBER/EA_BLOCK_NUMBER的取值范围:0x4~0xFFFB。
基于上述配置,使用前述公式计算FEE/EA_BLOCK_NUMBER的结果如下:
对于具有NvMNvBlockBaseNumber=2的native NVRAM块:
通过设置FEE/EA_BLOCK_NUMBER=8访问NV块。
对于具有NvMNvBlockBaseNumber=3的redundant NVRAM块:
第1个NV存储块(数据索引为0)通过FEE/EA_BLOCK_NUMBER=12进行访问。第2个NV存储块(数据索引为1)通过FEE/EA BLOCK NUMBER=13进行访问。
对于一个NVRAM块数据集,其NVMNvBlockBaseNumber为4,NVMNvBlockNum为3:
访问了编号为0的NV块(其数据索引为0),此时FEE/EA_BLOCK_NUMBER的值为16。
访问了编号为1的NV块(其中数据索引为1),此时FEE/EA_BLOCK_NUMBER的值为17。
访问了编号为2的NV块(其中数据索引为2)时,此时FEE/EABLOCKNUMBER的值为18。
示例B
配置参数NvMDatasetSelectionBits被设置为4。这导致的结果是,可供配置参数NVMNvBlockBaseNumber使用的位数为12位。
NVMNvBlockBaseNumber的取值范围0x1至0xFFE。
数据索引范围为0x0…0xF(=2^NvMDatasetSelectionBits-1)。
FEE/EA块编号范围为0x10至0XFFEF。
(二)、基本存储对象
1、NV block
NV块是一种基本的存储单元,它代表一个由NV用户数据以及CRC值(可选
的)和NV块头(可选的)组成的内存区域。
2、RAM block
RAM块是一种基本的存储单元,它代表了RAM中的一个区域,该区域包含用户数据以及一个CRC值(可选地)和一个NV块头信息(可选地)。
对RAM块中CRC使用的限制。只有当相应的NV块也具有CRC时,CRC才可用。CRC必须与相应NV块的类型相同。
一个RAM块的用户数据区域可以位于与该RAM块的状态不同的RAM 地址位置(全局数据区域)。
RAM单元的数据区域应能从NVRAM管理器以及应用程序端进行访问(数据可从相应NV单元传入或传出)。

由于NvM模块不支持对齐功能,这个问题可以通过配置来解决,即可以通过添加填充数据来扩大块长度,以满足对齐要求。
RAM块的数据应包含永久性或临时性分配的用户数据。
若存在永久性分配的用户数据,则在配置时即可得知该内存块数据的地址。
若存在临时分配的用户数据,则在配置期间无法得知该内存块数据的地址,而在运行时该地址将被传递给NvM模块。
在全部的RAM区域中,可以为每个RAM块分配内存,且无需考虑地址限制
所配置的RAM块总数无需位于连续的地址空间内。
3、ROM block
ROM块是一种基本存储对象,位于ROM(FLASH)中,用于在NV块为空或损坏的情况下提供默认数据。
4、Administrative block
管理块应位于RAM中,并应包含一个块索引,该索引与数据集的NV块相关联使用。此外,还应包含对应于NVRAM块的属性/错误/状态信息。
NvM模块将利用永久性RAM块或NvM模块内RAM镜像的状态信息(在明确同步(无效/有效)的情况下)来确定永久性RAM块用户数据的有效性。
RAM块状态无效表示该RAM块的数据区域无效。而RAM块状态有效则表示该RAM块的数据区域有效。
无效的值应由除有效之外的所有其他值来表示。
管理块对于应用程序而言是不可见的,它仅由NvM模块用于RAM块和NVRAM块自身的安全及管理目的而使用。
NvM模块应使用一个属性字段来管理NV块的写保护功能,以实现对NV块数据字段的保护或解除保护操作。
NvM模块应使用一个错误和状态字段来管理上一次请求的错误和状态值。
5、NV Block Header
如果启用了Static Block ID机制,则在NV块中应首先包含NV块头信息。

(三)、块管理类型
1、块管理类型概述
NvM模块的实现应支持以下几种NVRAM存储类型:
NVM_BLOCK_NATIVE
NVM_BLOCK_REDUNDANT
NVM_BLOCK_DATASET
NVM_BLOCK_NATIVE类型的NVRAM存储应由以下基本存储对象构成:
NV块:1个
RAM块:1个
ROM块:0~1个
管理块:1个
NVM_BLOCK_REDUNDANT类型的NVRAM存储应由以下基本存储对象构成:
NV块:2个
RAM块:1个
ROM块:0~1个
管理块:1个
NVM_BLOCK_DATASET类型的NVRAM存储应由以下基本存储对象构成:
NV块:1~(m<256) 个
RAM块:1个
ROM块:0~n个
管理块:1个
2、NVRAM块结构
NVRAM块必须包含以下基础存储对象:
NV块、RAM块和管理块。
基本存储对象ROM块为可选配置。
在配置过程中,任何NVRAM块的构成都会由相应的NVRAM块描述符确定。
所有地址偏移量均以NVRAM块描述符中定义的RAM或ROM起始地址为基准,且该起始地址默认设为0。
3、NVRAM块描述符表
在NvM模块的API调用中,需通过提供预先分配的Block ID,来选择待操作的单个NVRAM块。
与NVRAM块描述符表相关的所有结构体,及其在ROM(FLASH)中的地址,均需在NvM模块的配置阶段生成。
4、Native NVRAM Block
Native NVRAM块是最简单的数据块管理类型,仅需最小的额外开销即可实现NV存储器的存储与读取。
Native NVRAM块由1个NV块、1个RAM块和1个管理块构成。
5、Redundant NVRAM block
相较于Native NVRAM块,Redundant NVRAM块具备更高的容错性、可靠性和可用性,能增强数据抗损坏能力。
冗余NVRAM块由2个NV块、1个RAM块和1个管理块构成。

若与Redundant NVRAM块关联的某一个NV块被判定为无效(例如读取时检测到数据损坏),NvM模块应尝试使用另一个未损坏NV块中的数据恢复该无效NV块。
若恢复操作失败,NvM模块应通过DEM上报故障,故障码为NVM_E_LOSS_OF_REDUNDANCY。
Recovery指重新建立冗余机制,通常意味着将恢复后的数据写回无效的NV块中。
6、Dataset NVRAM block
Dataset NVRAM块是由多个大小相等的数据块(NV/ROM)组成的数组,应用程序同一时间仅能访问其中一个元素。
Dataset NVRAM块由以下部分构成:多个NV user块、CRC区(可选的)、NV块头(可选的)、1 个RAM 块和1个管理块。
通过相应的管理块中的一个单独字段可以得知数据集的索引位置。
NvM模块应能读取所有已分配的NV块。
只有在未启用写保护的情况下,NvM模块才能对所有分配的NV块进行写入操作。
如果将基本存储对象的ROM区块设为可选部分,通常用于选择数据集的索引范围将扩展至ROM 区域,从而能够选择ROM块而非NV块。该索引涵盖了所有可能构成NVRAM Dataset块的NV/ROM块。
NvM模块仅能对可选的ROM块执行读取操作(ROM块通常用于存储默认数据集,不可写)。
NvM模块应将对ROM块的写入操作视为对受保护的NV块的写入操作。
已配置的数据集(NV块 + ROM块)应在1~255的范围内。
若存在可选的ROM块,则索引范围从0到NVMNvBlockNum-1的数据区域代表NV存储中的NV块及其对应的 CRC。索引范围从NVMNvBlockNum到NVMNvBlockNum+NVMRom BlockNum-1的数据区域则代表ROM块。

7、NvM API配置类
为使NvM模块能适应有限的硬件资源,需定义三种不同的API配置类:
API configuration class 3:支持所有规定的API调用,提供最完整的功能.
API configuration class 2:支持中等范围的API调用(功能介于类 1 和类 3 之间)。
API configuration class 1:对于硬件资源极其有限的匹配系统而言,此API配置类仅提供了一组在
任何情况下都必需的最少API调用。
API configuration class 3的API:
API configuration class 2的API:
API configuration class 1的API:

API configuration class 1无需设置队列,也无法立即写入数据。此外,API调用NvM SetRamBlockStatus()仅在通过NvMSetRamBlockStatusApi进行配置的情况下才可用。
在API configuration class 1中,不支持NVM_BLOCK_DATASET这种块管理类型。
NvM模块中仅应包含处理所配置的块类型所需的代码。
(四)、Scan order / priority scheme
NvM模块应支持基于优先级的任务处理机制。
应通过配置参数NvMJobPrioritization启用或禁用基于优先级的任务处理。
若启用基于优先级的任务处理,NvM模块需使用两个任务队列:
一个队列用于立即写入任务(如紧急数据,需紧急存储);
另一个队列用于所有其他任务(包括立即读取任务、擦除任务等)。
若通过配置禁用基于优先级的任务处理,NvM模块不支持立即写入任务,此时所有任务均按先到先服务(FCFS)的顺序处理。
对于由NvM_ReadAll()、NvM_ValidateAll()、NvM_FirstInitAll()、NvM_WriteAll()等API发起的多个块请求,其任务队列长度应设为1,即仅能排队一个多块任务(避免多块任务占用过多资源)。
NvM模块不得因其他请求而中断源自NvM_ReadAll()请求的任务。
但是当具有立即优先级的写入任务将抢占正在运行的读/写任务,被
抢占的任务随后将由NvM模块重新运行。
NvM模块不得因其他请求而中断源自NvM_WriteAll()请求的作业。
若在NvM_ReadAll()执行期间发起新的读取请求,NvM模块应将新请求排队,待当前NvM_ReadAll()完成后再执行。
若在NvM_WriteAll()执行期间发起新的写入请求,NvM模块应将新请求排队,待当前NvM_WriteAll()完成后再执行。
若在NvM_ReadAll()执行期间发起新的写入请求,NvM模块应将新请求排队,待当前NvM_ReadAll()完成后再执行。
若在NvM_WriteAll()执行期间发起新的读取请求,NvM模块应将新请求排队,待当前NvM_WriteAll()完成后再执行。
可通过调用NvM_CancelWriteAll()中止NvM_WriteAll(),中止后,当前正在处理的块会完成操作,但不再处理后续块。
如果相关NVRAM块处理完毕后这些请求已不再有效,则应允许将其移除。
被抢占的任务后续应由NvM模块恢复执行或重新启动,该规则同时适用于单个块请求和多个块请求。
(五)、块类型总结
从以上描述可基本总结如下:
NVRAM块的存储对象有以下构成:
NV块、RAM块、管理块、ROM块,ROM块是可选的,NV块即存储在非易失性内存中的数据,RAM块是供用户读写的区域同时也是和NV块数据传输的源地址需要注意数据的一致性,管理块是存放该NVRAM块信息用的,在RAM里不对外开放即NvM代码里内部使用的,ROM块即存放默认数据的区域当NV块无效或损坏时,RAM块从ROM块里读取数据。
NV块和RAM块由块头、数据区、CRC区构成,块头、CRC区是可选的,其中RAM块的数据区分为永久数据区和临时数据区,如果static id有使能则有块头,如果块头ID不是预期的则该块是无效或损坏的,在从数据区读取数据时如果CRC不对则该块也是无效或损坏的,RAM永久数据区即定义在全局栈里的数组,RAM临时数据区即定义在函数里的数组。
NVRAM块类型分为原始类型、冗余类型、数据集,原始类型是基本的类型,冗余类型即有两个一样的NVRAM块,在写请求时会同时写两个,当读取时如果其中一个是无效或损坏的则读取另一个,数据集即有N个原始类型的NVRAM块,供用户选取其中一个进行读写请求。
一般使用方法是用户读写数据操作的都是RAM区,然后调用读写请求后,NvM在主任务里进行读写操作,期间需要保证数据的一致性。
(六)、NVM的数据安全性
从存储协议栈来看,以FLASH为例,为了保证FLASH的最大利用率,Fee模块会使用模拟EEPROM的方法在FLASH里滚动存储数据,那怎样保证数据在擦写过程中是对的或者读出来是正确的,NvM、Fee、Fls各实现以下功能保证数据的安全性:
NvM是直接面向Rte的模块,供用户的基本请求操作只有读写操作,NvM不能直接对FLASH进行擦除操作。
在读写数据时NvM可以将带有CRC的数据写入,读取时通过比较CRC判断读取的数据对不对。
也可以使能写校验功能,每次NvM在写入后都会从NV块中回读并于RAM块数据进行比较,如果不一样则块的请求操作为非成功,但该功能会影响写任务时间。
NvM还提供了冗余机制,可以将重要块的数据类型设为冗余块,每次在写操作时会向Fee的两个块写入相同数据,当读取时如果有一个块损坏或无效则读取另外一个块保证数据的安全性。
NvM还提供了默认数据区,如果某个数据在FLASH里丢失(因为模拟EEPROM的特性FLASH扇区数据是一直更新的),该块可以在ROM块中读取默认数据(通常该数据区不会更新)。
NvM作为直接面向用户的模块,考虑的是用户数据的安全性,不需要考虑数据存储机制和存储介质的操作。
Fee是管理FLASH的模块,实现模拟EEPROM功能,需要考虑的是数据的安全性,对FLASH实现最大使用率,对重要数据实现更快的写入等。让上层不需要考虑地址的管理。
由于FLASH的特性,当数据在某个地址写入后必须要擦除才能再写,所以Fee需要在扇区里写满所有数据后再切换到另一个扇区再写,然后旧的扇区执行擦除动作。
每个厂家实现Fee模拟EEPROM算法都不同,如下图是NXP的Fee的数据结构:
Fee的每个块数据都有块头和数据区,通过块头信息保证块数据的合法性比如有效标志位或校验和。
因为Fee的数据在扇区里是滚动存储的,针对最新块如果数据损坏或无效,Fee应该支持读取旧块即读取历史信息(有些厂家可能没有)。
Fee还可以支持坏块的修复,当某个块坏掉时可以从ROM区读取默认值(有些厂家可能没有)。
Fee针对immediate类型数据即标记为重要的数据需要支持快速写入,因为Fee在对某个扇区写满后会执行换扇区动作,FLASH的擦除时间会比较厂,那么在每个扇区需要预留一些空间满足immediate类型数据的写入。
Fls是直接面向FLASH擦写读的模块,只提供操作接口给上层,自己本身不参与FLASH的管理,那么Fls模块怎么考虑FLASH数据的安全性呢。
Fls模块本身尽可能的处理硬件相关的动作,比如FLASH和Cache之间的数据一致性,FLASH写保护使能,FLASH在RAM区的加载,ECC处理等,让上层无需关心硬件层的操作。
有些MCU的FLASH带有ECC功能,即硬件层面的校验码,如果FLASH里的数据发生损坏就会产生ECC错误,这是硬件层的校验机制,产生ECC错误后给上层模块负责处理,比如擦除坏的扇区或者忽略坏的页等。
Fls还可以支持数据写完后进行回读操作保证数据写入是预期的,但这样会拖慢操作时间(有些厂家可能没有)。
Fls还可以支持扇区擦除后进行检查扇区数据是否为FF来保证擦除成功(有些厂家可能没有)。
三、功能需求
对于每个异步请求,任务完成后向调用方发送通知应作为一项可配置选项。
NvM模块应提供回调接口。
不允许任何其他模块直接访问非易失性存储器。
NvM模块仅提供隐式方式访问NVRAM和RAM中的数据块。这意味着,NvM模块会将一个或多个数据块从NVRAM复制到RAM,或从RAM复制到NVRAM。
该应用程序直接访问RAM数据,同时需遵守相关限制条件。
若某特定块及其对应的ID未被排队或当前未处于处理中(存在多任务限制),则NvM模块将对所有异步的单个块的读/写/控制请求进行排队。
只要不出现队列溢出的情况,NvM模块都应能够处理多个异步的单块请求。
最优先级的请求将由NvM模块从队列中获取,并按照串行顺序进行处理。
NvM模块应实现用于检查保存在NV memory中的数据的一致性/完整性机制。
如果在配置时没有可用的默认ROM数据,或者没有由NvMInitBlockCallback定义的回调函数,那么应用程序需负责提供默认的初始化数据。
在此情况下,应用程序必须调用NvM_GetErrorStatus() 函数,以区分首次初始化和数据损坏两种情况。
在执行NvM_ReadAll()操作过程中,NvM模块应能通过计算校验和来检测RAM中的数据是否损坏。
在执行NvM_ReadAll()操作过程中,NvM模块应能通过测试管理块内数据的有效性,来检测RAM中的数据是否无效。
在启动阶段、NvM_ReadAll()正常运行过程中,若NvM模块检测到NV块存在不可恢复的错误,则应将默认数据(若已配置)复制到对应的RAM数据块中。
为使用OS服务,NvM模块应仅使用BSW调度器,而非直接使用OS服务。
对于配置了永久RAM(或通过API参数传入RAM)且其RAM(起始地址)未对齐于NvMBufferAlignmentValue的NVRAM块,在执行所有对其RAM数据块的读写操作时,NvM模块应将内部镜像用作缓冲区。
四、设计说明
(一)、NvM启动
NvM_Init()应由BswM执行。
由于对ECU启动时间有严格限制,NvM_Init()请求中不得包含已配置NVRAM块的初始化操作。
NvM_Init()请求不负责触发存储驱动程序的初始化过程。这部分工作应由BswM来处理。
RAM数据块的初始化操作将由另一项请求来完成,即NvM_ReadAll()。
NvM_ReadAll()只能由BswM执行。
使用NvM模块的软件组件应负责检查由NvM模块启动产生的全局错误/状态信息。BswM应通过轮询方式(使用NvM_GetErrorStatus())或回调通知(可配置选项NvM_MultiBlockCallback)来获取启动过程中产生的全局错误/状态信息。
若使用轮询方式,应通过全局错误/状态值NVM_REQ_OK或NVM_REQ_NOT_OK来判断NVRAM启动过程是否结束(启动期间状态为 NVM_REQ_PENDING)。
如果在NvM_ReadAll()过程中对每个要处理的NVRAM块都配置了回调函数,那么这些回调函数就可以由RTE使用,以便在较早阶段启动例如SW-C等组件。
为确保Dem能在较早阶段完全投入运行(即其NV数据已恢复至RAM中),与Dem相关的NVRAM块应配置为低ID,以确保在NvM_ReadAll()过程中优先被处理。
(二)、NvM关闭
在程序shutdown时应调用NvM_WriteAll()保存数据,NvM_WriteAll()应由BswM调用。
(三)、NvM的并行写访问
NvM模块应通过采用排队机制的异步接口接收请求。NvM模块应根据请求的优先级,以串行方式处理所有请求。
(四)、NVRAM块一致性检查
NvM模块应提供隐式技术来检查NVRAM块的数据一致性。
NVRAM块的数据一致性检查应通过对其相应的NV块进行CRC重计算来实现。
数据一致性检查的隐式方式应由内部函数的可配置选项提供。隐式一致性检查应可针对每个NVRAM块进行配置,并取决于可配置参数NvMBlockUseCrc和NvMCalcRamBlockCrc。
对于NvMWriteBlockOnce = TRUE的NVRAM块,应启用NvMBlockUseCrc。对于NvMWriteBlockOnce = TRUE的NVRAM块,应禁用NvMBlockWriteProt,以便在CRC检查失败时,用户能够向该NVRAM块写入数据。
根据可配置参数NvMBlockUseCrc和NvMCalcRamBlockCrc,NvM模块应为所使用的最大CRC分配内存。
NvM用户无需了解其RAM块中数据的CRC内存相关信息(如大小、位置)。
(五)、错误恢复
NvM模块应提供错误恢复技术。错误恢复方式取决于NVRAM块的管理类型。
NvM模块应通过加载默认值,为各种NVRAM块管理类型提供读操作时的错误恢复功能。
对于管理类型为NVM_BLOCK_REDUNDANT的NVRAM块,NvM模块应通过向RAM块加载默认值,提供读操作时的错误恢复功能。
无论NVRAM块的管理类型如何,NvM模块都应通过执行写重试操作,提供写操作时的错误恢复功能。
对于所有配置了RAM块CRC的NVRAM块,若在启动时发生RAM块重新验证失败,NvM模块应提供读错误恢复功能。
(六)、根据ROM数据恢复RAM块
NvM模块应提供隐式和显式恢复技术,以便在NV块出现不可恢复的数据不一致问题时,将ROM数据恢复到其对应的RAM块中。
(七)、通过ROM默认数据实现RAM块的隐式恢复
在隐式恢复过程中,对应NV块的数据内容应保持不变。
对于未配置默认数据(通过参数NvMRomBlockDataAddress或NvMInitBlockCallback配置)的每个NVRAM块,在启动阶段(属于 NvM_ReadAll()的一部分),以及通过NvM_ReadBlock()或NvM_ReadPRAMBlock()操作时,均不提供隐式恢复功能。
对于满足以下条件的每个NVRAM块,在启动阶段(属于NvM_ReadAll()的一部分),以及通过NvM_ReadBlock()或NvM_ReadPRAMBlock()操作时,均不提供隐式恢复功能:
已配置默认数据(通过参数NvMRomBlockDataAddress或参数NvMInitBlockCallback配置)。
永久RAM块或NvM模块中RAM镜像的内容(在显式同步场景下)状态有效,且CRC数据一致。
对于满足以下条件的每个NVRAM块,在启动阶段(属于NvM_ReadAll()的一部分),以及通过NvM_ReadBlock()或NvM_ReadPRAMBlock()时,均不提供隐式恢复功能:
已配置默认数据(通过参数NvMRomBlockDataAddress或参数NvMInitBlockCallback配置)。
永久RAM块或NvM模块中RAM镜像的内容(在显式同步场景下)状态无效,且CRC数据不一致;
从NV读取的尝试成功。
对于满足以下条件的每个NVRAM块,在启动阶段(属于NvM_ReadAll()的一部分),以及通过NvM_ReadBlock()或NvM_ReadPRAMBlock()时,应提供隐式恢复功能:
已配置默认数据(通过参数NvMRomBlockDataAddress或参数NvMInitBlockCallback配置)。
永久RAM块或NvM模块中RAM镜像的内容(在显式同步场景下)状态无效,且CRC数据不一致。
从NV读取的尝试失败。
对于类型为NVM_BLOCK_NATIVE和NVM_BLOCK_REDUNDANT的NVRAM块,在处理NvM_ReadBlock()或NvM_ReadPRAMBlock()请求时,应提供隐式恢复功能。
(八)、通过ROM默认数据实现RAM块的显式恢复
对于通过ROM块数据进行明确恢复的操作,NvM模块应提供函数NvM_RestoreBlockDefaults()和NvM_RestorePRAMBlockDefaults()用于将ROM数据恢复到相应的RAM块中。
NvM_RestoreBlockDefaults()和NvM_RestorePRAMBlockDefaults()应保持不变,即恢复相应NV块的数据内容。
应用程序应每次需要时使用函数NvM_RestoreBlockDefaults()或NvM_RestorePRAMBlockDefaults()来将ROM数据恢复到相应的RAM块中。
(九)、对NV块的不完整写操作的检测
对NV块的不完整写操作检测,不属于NvM模块的职责范围。该功能由MemIf负责处理和检测。
当被引用的NV块无效、数据不一致,或在请求读取时无法读取时,NvM模块期望从MemIf获取相关信息。
SW-C可调用NvM_InvalidateNvBlock(),以防止底层传递旧数据。
(十)、单个块请求的终止
NvM模块提供的所有异步请求(NvM_CancelWriteAll()除外)应在相应管理块的指定错误/状态字段中表明其结果。
可选配置参数NvMSingleBlockCallback用于配置在异步块请求(以及 NvM_ReadAll())终止时通过回调发送通知。
在与SW-C通信时,ECUC配置参数NvMSingleBlockCallback应配置为相应的 Rte_call_
_ API。
(十一)、多个块请求的终止
NvM模块应使用一个单独的变量来存储异步多块请求(NvM_ReadAll()、NvM_WriteAll()包括NvM_CancelWriteAll()、NvM_ValidateAll())的结果。
NvM_GetErrorStatus()应返回一个异步多块请求(包括NvM_CancelWriteAll())的最新错误 / 状态信息,同时需提供一个
保留的块ID值为0。
多块请求的结果应仅表示一个通用的错误/状态信息。
NvM模块提供的多块请求应在每个受影响的管理块的指定错误/状态字段中指示其详细的错误/状态信息。
可选配置参数NvMMultiBlockCallback用于配置在异步多块请求终止时通过回调发送通知。
(十二)、异步请求/任务处理的常规处理
每当在某一请求内执行CRC计算时,若被引用的NVRAM块长度超过参数NvMCrcNumOfBytes所配置的字节数,NvM模块应分多步计算CRC。
进行CRC计算时,NvM模块应使用由CRC模块发布的初始值。
多个并发的单块请求应支持加入队列(可排队)。
NvM模块应中断当前的异步请求/作业处理,优先处理具有即时优先级的任务(如崩溃数据相关任务)。
若调用NvM模块的异步函数导致任务队列溢出,则该函数应返回错误码E_NOT_OK。
当某一请求成功加入队列后,NvM模块应将对应NVRAM块的请求结果设置为NVM_REQ_PENDING。
若NvM模块成功处理某一任务,则应返回NVM_REQ_OK作为该请求的结果。
(十三)、NVRAM块写保护
NvM模块应提供多种可配置的写保护类型。每种写保护类型仅与NVRAM块的NV部分相关,即RAM块中的数据可修改,但无法写入NV存储器。
当NvMWriteBlockOnce为FALSE时,无论NvMBlockWriteProt的取值为TRUE还是FALSE,均允许通过NvM_SetBlockProtection()启用/禁用写保护。
当NvMWriteBlockOnce为TRUE时,无论NvMBlockWriteProt的取值为TRUE还是FALSE,均不允许通过NvM_SetBlockProtection()启用/禁用写保护。
对于所有配置为NvMBlockWriteProt=TRUE的NVRAM块,NvM模块应启用默认写保护。
NvM模块的运行环境可通过NvM_SetBlockProtection()显式禁用写保护。
对于配置为NvMWriteBlockOnce == TRUE的NVRAM块,NvM模块仅允许对关联的NV存储器执行一次写入操作,即仅在NV设备为空白状态时写入。
对于配置为NvMWriteBlockOnce == TRUE的NVRAM块,NvM模块不允许通过NvM_SetBlockProtection()显式禁用写保护。
对于配置为NVM_WRITE_BLOCK_ONCE(TRUE)的块,在首次读请求执行前,NvM模块应拒绝所有写/擦除/失效请求。
在复位场景下,配置为NVM_WRITE_BLOCK_ONCE(TRUE)的块,其来自NvM管理块的写保护标志会被清除。为重新激活保护,需在处理首次写/擦除/失效请求前先读取该块,以便仅对有效且一致的块设置写保护。首次读取请求可以作为单个块请求进行,也可以作为NvM_ReadAll()的一部分来完成。
(十四)、RAM块数据的验证和修改
以下将展示RAM块的状态转换过程:
由于进入和维持某一状态可能依赖多种条件,若将所有条件均置于上图中会导致理解困难,因此后续小节将提供更详细的说明。其中,INVALID/CHANGED状态不再展开详述,因为该状态始终无法达到(如上图所述)。
初始化完成后,RAM块将处于INVALID/UNCHANGED状态,直至通过NvM_ReadAll()操作更新RAM块后,其状态才会转换为VALID/UNCHANGED。在VALID/UNCHANGED状态下,不允许执行WriteAll操作。若调用NvM_SetRamBlockStatus()函数,RAM块将脱离该状态。
若发生CRC错误,RAM块会再次切换至INVALID状态,之后可通过隐式或显式错误恢复机制脱离该状态。错误恢复完成后,由于RAM块内容与NVRAM内容不一致,该RAM块将处于VALID/CHANGED状态。
若配置中已禁用用于修改RAM块状态的API(通过参数NvMSetRamBlockStatusApi或NvMBlockUseSetRamBlockStatus禁用),则在向对应NV块写入数据时(即执行 NvM_WriteAll()期间),NvM模块应将RAM块或NvM模块中的RAM镜像(适用于显式同步场景)视为有效且已变更,也就是说,在此期间NvM模块需将每个永久RAM块的数据写入NV存储器。
若配置中已禁用用于修改RAM块状态的API(通过参数NvMSetRamBlockStatusApi或NvMBlockUseSetRamBlockStatus禁用),则在从NV块读取数据时(即执行NvM_ReadAll()期间),NvM模块应将RAM块视为无效,也就是说,在此期间若配置允许,NvM模块需将每个NVRAM块的数据复制到RAM中。
若某块的读取尝试失败,则应用程序有责任在下次写入尝试前提供有效的数据。
若某RAM块成功复制到NV存储器,则之后该RAM块的状态应设置为valid/unmodified。
1、VALID/UNCHANGED状态
该状态表示RAM块的内容要么与对应NV块的内容完全一致,要么若应用程序已访问过该RAM块,存在潜在变更但尚未被标记。对于DATASET block,上述条件适用于最后一次被处理的实例的RAM内容。此外,该状态还意味着上一次块操作执行成功,且该块未因请求而被置为无效状态。
要进入VALID/UNCHANGED状态,至少需满足以下任一条件:
(1)、NvM_ReadAll()成功读取该块。
(2)、NvM_ReadBlock()成功完成该块的读取操作。
(3)、NvM_WriteBlock()成功完成该块的写入操作。
(4)、NvM_WriteAll()成功写入该块。
维持VALID/UNCHANGED状态需同时满足以下两个条件:
(1)、针对某一BlockID的上一次读取或写入操作执行成功(无错误,且未调用默认数据).
(2)、自上一次读取或写入操作后,应用程序未标记该RAM块存在潜在变更。
2、VALID/CHANGED状态
该状态表示RAM块的内容可能与对应NV块的内容存在差异。对于DATASET block,此条件适用于最后一次被处理的实例的RAM内容。此外,该状态还意味着该块的上一次操作执行成功,且未因请求而被置为无效状态。块所有者可通过信号标记该块的RAM内容存在潜在变更,从而使块状态转为VALID/CHANGED。
要进入VALID/CHANGED状态,至少需满足以下任一条件:
(1)、对该块调用NvM_SetRamBlockStatus()且参数为TRUE。
(2)、对该块调用NvM_WriteBlock()函数。
(3)、NvM_WriteAll()操作会处理该块。
(4)、对该块调用NvM_ReadBlock()函数后,获取到的是默认数据。
(5)、对该块调用NvM_RestoreBlockDefaults()函数且执行成功。
(6)、NvM_ReadAll()操作处理该块时,获取到的是默认数据。
(7)、NvM_ValidateAll()操作成功处理该块。
维持VALID/CHANGED状态需满足以下任一条件:
(1)、块所有者已标记该RAM块存在潜在变更。
(2)、上一次读取该块时(无论隐式还是显式方式),获取到的是默认数据。
3、INVALID/UNCHANGED状态
该状态表示NV块处于无效状态。对于DATASET block而言,这意味着最后一次被处理的实例所对应的NV块内容无效。
要进入INVALID/UNCHANGED 状态,至少需满足以下任一条件:
(1)、对该块调用NvM_SetRamBlockStatus()函数且参数为FALSE。
(2)、对该块调用NvM_ReadBlock()函数时,系统提示因用户请求导致块无效。
(3)、对该块调用NvM_ReadBlock()函数时,系统提示数据损坏(若已配置CRC校验)。
(4)、对该块调用NvM_ReadBlock()函数时,系统提示Static ID错误(若已配置静态ID校验)。
(5)、对该块调用NvM_WriteBlock()函数且执行失败NvM_WriteAll()操作对该块的写入失败。
(6)、对该块调用NvM_InvalidateNvBlock()函数且执行成功。
(7)、对该块调用NvM_EraseNvBlock()函数且执行成功。
维持INVALID/UNCHANGED状态需满足以下任一条件:
(1)、当前块状态未知(处于早期初始化阶段,直至执行ReadAll操作或对该块发起首次操作请求).。
(2)、检测到该块数据损坏或静态ID错误。
(3)、该块上一次成功执行的操作是Invalidation。
(4)、当前读取操作失败且未获取到默认数据。
(5)、该块上一次成功执行的操作是Erase。
总结:
NVRAM块在INVALID状态下代表该块为无效或损坏,该状态下是不能读取的除非下一次读写成功或调用函数手动置为有效。
在VALID状态下代表该块是有效的,可以正常读写。
在UNCHANGED状态下,代表用RAM块与NV块数据是一样的,调用WriteAll会跳过该块除非调用函数设为CHANGED状态,WriteAll才会将RAM块里的数据写进NV块,CHANGED状态代表永久RAM块和NV块数据是不一样的,调用ReadAll时不会将NV块里数据读到RAM块。
(十五)、应用程序与NvM之间的通信及隐式同步
为最大限度减少锁定/解锁的开销或避免使用其他同步方法,应用程序与NvM模块之间的通信必须遵循下述严格的步骤序列。这能确保应用程序与NvM模块之间通信的可靠性,避免RAM块中的数据损坏,并保障同步机制的正常运行。
该访问模型假设,与RAM块通信涉及两方:应用程序和NvM模块。
若多个应用程序使用同一个RAM块,保障该RAM块的数据完整性并非NvM模块的职责。在此情况下,应用程序必须自行同步对该RAM块的访问,并确保在NVRAM操作期间不会对RAM块进行不当访问。尤其当多个应用程序通过(不同的)临时RAM块共享一个NVRAM块时,应用程序之间的同步会变得更为复杂,而这同样不属于NvM模块的处理范围。若采用回调作为通知方式,可能会出现例如某应用程序收到通知,但该请求并非由其发起的情况。
所有应用程序均须遵守以下规则:
1、写请求(NvM_WriteBlock()或NvM_WritePRAMBlock())
在应用程序与NvM之间通过隐式同步执行写入请求时,应用程序必须遵守以下规则:
(1)、应用程序将需由NvM模块写入的数据填充到RAM块中。
(2)、应用程序发起NvM_WriteBlock()或NvM_WritePRAMBlock()请求,将控制权转移至NvM模块。
(3)、从此时起,在通过信号通知或轮询得知请求成功或失败前,应用程序不应修改该RAM块,但在此期间可读取该RAM块的内容。
(4)、应用程序可通过轮询获取请求状态,也可通过回调函数异步接收状态通知。
(5)、NvM模块操作完成后,该RAM块可重新用于数据修改。
2、读请求(NvM_ReadBlock()或NvM_ReadPRAMBlock())
在应用程序与NvM之间通过隐式同步执行读取请求时,应用程序必须遵守以下规则:
(1)、应用程序提供一个RAM块,该RAM块需由NvM模块侧填入NVRAM数据。
(2)、应用程序发起NvM_ReadBlock()请求,将控制权转移至NvM模块。
(3)、从此时起,在通过信号通知或轮询得知请求成功或失败前,应用程序不应对该RAM块执行读写操作。
(4)、应用程序可通过轮询获取请求状态,也可通过回调函数接收状态通知。
(5)、在完成NvM模块的操作后,RAM块中便有了新的数据,可供应用程序使用。
3、恢复默认请求(NvM_RestoreBlockDefaults()或NvM_RestorePRAMBlockDefaults())
在应用程序与NvM之间通过隐式同步执行恢复默认值请求时,应用程序必须遵守以下规则:
(1)、应用程序提供一个RAM块,该RAM块需由NvM模块侧填入ROM中的默认数据。
(2)、应用程序发起NvM_RestoreBlockDefaults()或NvM_RestorePRAMBlockDefaults(),将控制权转移至NvM模块。
(3)、从此时起,在通过信号通知或轮询得知请求成功或失败前,应用程序不应对该RAM块执行读写操作。
(4)、应用程序可通过轮询获取请求状态,也可通过回调函数接收状态通知。
(5)、NvM模块操作完成后,该RAM块中将存储有ROM默认数据,可供应用程序使用。
4、多块读请求(NvM_ReadAll())
此请求仅应由BswM在系统启动时触发。该请求会为所有已配置的永久RAM块填充启动所需的必要数据。
若该请求执行失败,或仅部分执行成功,NvM会将此状态报告给Dem,并向BswM返回错误信息。Dem与BswM需决定后续应采取的措施,这些步骤超出了NvM模块的职责范围,在Dem与BswM的规范中进行处理。
在应用程序与NvM之间通过隐式同步执行多块读取请求时,应用程序必须遵守以下规则:
BswM发起NvM_ReadAll()。
BswM可通过轮询获取该请求的状态,也可通过回调函数接收状态通知。
在NvM_ReadAll()执行过程中,每完成一个NVRAM块的完整处理后,若配置了单块回调函数,则会调用该函数。这些回调函数可使RTE逐个启动各个SW-C。
5、多块写请求(NvM_WriteAll())
此请求仅应由BswM在系统关闭时触发。该请求会将所有已修改的永久RAM块内容写入NV存储器。通过仅在ECU关闭期间调用此请求,BswM可确保在操作完成前,没有其他软件组件能够修改RAM块中的数据。这些措施超出了NvM模块的范围,在BswM的规范中进行处理。
在应用程序与NvM之间通过隐式同步执行多块写入请求时,应用程序必须遵守以下规则:
BswM发起NvM_WriteAll()请求,将控制权转移至NvM模块。
BswM可通过轮询获取该请求的状态,也可通过回调函数接收状态通知。
6、取消操作(NvM_CancelWriteAll())
此请求会取消当前正在进行的NvM WriteAll()请求。这是一种异步重置操作。
该请求可以被调用以终止一个未完成的NvM WriteAll()请求。
NvM_CancelWriteAll()应该只被BswM调用。
7、管理块的修改
出于管理目的,一个管理块是每个已配置的NVRAM块的一部分
若NVRAM块存在未完成的单块操作,则应用程序不得调用任何会修改
管理块的操作,例如NvM_SetDatalndex()、NvM_SetBlockProtection()、
NvM_SetRamBlockStatus(),直至该未完成的任务完成。
(十六)、NVRAM块的正常及扩展运行时准备工作
根据NvMDynamicConfiguration和NvMResistantToChangedSw这两个配置参数的取值,NvM在启动阶段(即处理NvM_ReadAll()请求期间)应呈现不同的行为:
若NvMDynamicConfiguration设置为FALSE,则NvM应忽略已存储的配置ID,并继续执行NVRAM块的常规运行时准备。在此场景下,需先检查RAM块的有效性:
若检测到RAM块内容无效,则进一步检查NV块的有效性;
若检测到NV块有效,应将其复制到对应的RAM块中;
若检测到NV块无效,则应加载默认数据。
若NvMDynamicConfiguration设置为TRUE,且检测到配置ID不匹配:
对于配置为NvMResistantToChangedSw (FALSE)的NVRAM块,应执行扩展运行时准备。在此场景下,无论对应RAM块或NV块的有效性如何,均应加载默认数据。
(十七)、应用程序与NvM之间的通信及显式同步
与应用程序和NvM模块之间的隐式同步机制不同,系统提供了一种可选的(即可配置的)显式同步机制。该机制通过NvM模块中的RAM镜像实现,应用程序通过NvM模块调用的回调函数在两个方向上传输数据。
以下是对该机制的简要分析:
优点在于,应用程序能够更好地控制其数据。它们负责将一致性数据复制到NvM模块的RAM镜像以及从该镜像复制出来,因此清楚操作的时间点。由于并发访问,RAM块永远不会处于不一致状态。
缺点是需要额外的RAM(其大小需与使用该机制的最大NVRAM块相同),且每次操作都需要在两个RAM位置之间进行额外复制。
该机制特别适用于多个应用程序共享NVRAM块的场景,前提是存在一个模块负责同步这些应用程序,并且从NvM模块的角度来看,该模块是NVRAM块的所有者。
对于每个NVRAM块,应能通过参数NvMBlockUseSyncMechanism来设定是否使用显式同步机制。
若没有配置为使用显式同步机制的块,NvM模块不应分配RAM镜像。
若至少有一个块配置为使用显式同步机制,NvM模块应仅分配一个RAM镜像。该RAM镜像的大小不应超过配置为使用显式同步机制的最长NVRAM块的大小。
对于所有NvMBlockUseSyncMechanism == TRUE的NVRAM块,NvM模块应使用内部镜像作为所有读写其RAM块操作的缓冲区。该缓冲区不应用于其他NVRAM块。
对于所有NvMBlockUseSyncMechanism == TRUE的NVRAM 块,NvM模块应调用NvMWriteRamBlockToNvCallback函数,以将数据从RAM块复制到镜像。该函数不应用于其他NVRAM块。
对于所有NvMBlockUseSyncMechanism == TRUE的NVRAM块,NvM模块应调用NvMReadRamBlockFromNvCallback函数,以将数据从镜像复制到RAM块。该函数不应用于其他NVRAM块。
在单块请求过程中,若NvMReadRamBlockFromNvCallback函数返回E_NOT_OK,NvM模块应重试调用该函数NvMRepeatMirrorOperations次。之后,单块读取任务应将该块的特定请求结果设置为NVM_REQ_NOT_OK,并向DEM报告NVM_E_REQ_FAILED。
若NvMReadRamBlockFromNvCallback函数返回E_NOT_OK,NvM模块应在下次调用NvM_MainFunction()时重试该函数调用。
在单块请求过程中,若NvMWriteRamBlockToNvCallback函数返回E_NOT_OK,NvM模块应重试调用该函数NvMRepeatMirrorOperations次。之后,单块写入任务应将该块的特定请求结果设置为NVM_REQ_NOT_OK,并向DEM报告NVM_E_REQ_FAILED。
若NvMWriteRamBlockToNvCallback函数返回E_NOT_OK,NvM模块应在下次调用NvM_MainFunction()时重试该函数调用。
在多块请求(NvM_WriteAll())过程中,若NvMWriteRamBlockToNvCallback 函数返回E_NOT_OK,NvM模块应重试调用该函数NvMRepeatMirrorOperations次。之后,NvM_WriteAll()的任务应将该块的特定请求结果设置为NVM_REQ_NOT_OK,并向DEM报告NVM_E_REQ_FAILED。
在多块请求(NvM_ReadAll())过程中,若NvMReadRamBlockFromNvCallback函数返回E_NOT_OK,NvM模块应重试调用该函数NvMRepeatMirrorOperations次。之后,NvM_ReadAll()的任务应将该块的特定请求结果设置为NVM_REQ_NOT_OK,并向DEM报告NVM_E_REQ_FAILED。
若某块配置了显式同步机制,则不应为其配置永久RAM镜像。
1、写请求(NvM_WriteBlock()或NvM_WritePRAMBlock())
在应用程序与NvM之间通过显式同步执行写入请求时,应用程序必须遵守以下规则:
(1)、应用程序将需由NvM模块写入的数据填充到RAM块中。
(2)、应用程序发起NvM_WriteBlock()或NvM_WritePRAMBlock()请求。
(3)、在NvM模块调用NvMWriteRamBlockToNvCallback函数之前,应用程序可修改该RAM块。
(4)、若NvM模块调用NvMWriteRamBlockToNvCallback函数,应用程序必须向NvM模块请求的目标位置提供该RAM块的一致性副本。
应用程序可通过返回值E_NOT_OK表示数据不一致。NvM模块会接受该返回值并重试NvMRepeatMirrorOperations次,之后将暂缓处理该请求,并继续执行下一个请求。
(5)、仅当数据已复制到 NvM 模块后,才可继续后续操作。
(6)、从此刻起,应用程序可再次对该RAM块执行读写操作。
(7)、应用程序可通过轮询获取请求状态,也可通过回调函数异步接收状态通知。
若应用程序已发起NvM_WriteBlock()或NvM_WritePRAMBlock()请求,但NvM模块尚未处理(即NvMWriteRamBlockToNvCallback回调函数尚未被调用),则应用程序可将对同一RAM块中不同位置的多个写入请求合并执行。
2、读请求(NvM_ReadBlock()或NvM_ReadPRAMBlock())
在应用程序与NvM之间通过显式同步执行读取请求时,应用程序必须遵守以下规则:
(1)、该应用程序提供了一个RAM块,需要从NvM模块一侧的NVRAM数据中填充此区域。
(2)、应用程序发起NvM_ReadBlock()或NvM_ReadPRAMBlock()请求。
(3)、在NvM模块调用NvMReadRamBlockFromNvCallback函数之前,应用程序可修改该RAM块。
(4)、若NvM模块调用NvMReadRamBlockFromNvCallback函数,应用程序需将数据从NvM模块指定的目标位置复制到RAM块中。
应用程序可通过返回值E_NOT_OK表示数据未完成复制。NvM模块会接受该返回值并重试NvMRepeatMirrorOperations次,之后将暂缓处理该请求,并继续执行下一个请求。
(5)、仅当数据已从NvM模块复制完成后,才可继续后续操作.
(6)、此时,应用程序可在RAM块中获取到NV块的数据值。
(7)、应用程序可通过轮询获取请求状态,也可通过回调函数接收状态通知。
若应用程序已发起NvM_ReadBlock()或NvM_ReadPRAMBlock()请求,但NvM模块尚未处理(即NvMReadRamBlockFromNvCallback回调函数尚未被调用),则应用程序可将对同一NV块中不同位置的多个读取请求合并执行。
NvM_RestoreBlockDefaults()和NvM_RestorePRAMBlockDefaults()的执行逻辑与NvM_ReadBlock()类似。
3、多块读请求(NvM_ReadAll())
此请求仅应由BswM在系统启动时触发。该请求会为所有已配置的永久RAM块填充启动所需的必要数据。
若该请求执行失败,或仅部分执行成功,NvM会将此状态报告给DEM,并向BswM返回错误信息。Dem与BswM需决定后续应采取的措施,这些步骤超出了NvM模块的职责范围,Dem与BswM的规范中进行处理。
正常操作流程:
(1)、BswM发起NvM_ReadAll()请求。
(2)、BswM可通过轮询获取该请求的状态,也可通过回调函数接收状态通知。
(3)、在NvM_ReadAll()任务执行期间,若某一数据块配置了同步回调函数(NvM_ReadRamBlockFromNvm),NvM模块会调用该函数。在此次回调中,应用程序需将数据从NvM模块指定的目标位置复制到RAM块中。
应用程序可通过返回值E_NOT_OK表示数据未完成复制,NvM模块会接受该返回值并重试NvMRepeatMirrorOperations次,之后将报告读取操作失败。
(4)、若读取操作成功,此时应用程序可在RAM块中获取到NV块的数据值。
(5)、在NvM_ReadAll()执行过程中,每完成一个NVRAM块的完整处理后,若配置了单块回调函数,则会调用该函数。这些回调函数可使RTE逐个启动各个SW-C。
(6)、处理完最后一个数据块并调用其单块回调函数(若已配置)后,若配置了多块回调函数,则会调用该多块回调函数。
4、多块写请求(NvM_WriteAll())
此请求仅应由BswM在系统关闭时触发。该请求会将所有已修改的永久RAM块内容写入NV存储器。通过仅在ECU关闭期间调用此请求,BswM可确保在操作完成前,没有软件组件能够修改RAM块中的数据。这些措施超出了NvM模块的范围,在BswM的规范中进行处理。
正常操作流程:
(1)、BswM发出NvM_WriteAll()请求,将控制权转移至NvM模块。
(2)、在NvM_WriteAll()任务执行期间,若某块配置了同步回调函数(NvM_WriteRamBlockToNvM()),NvM模块会调用该函数。在此次回调中,应用程序必须向NvM模块请求的目标位置提供RAM块的一致性副本。
应用程序可通过返回值E_NOT_OK来表示数据不一致。NvM模块会接受此返回值,并重试NvMRepeatMirrorOperations次,之后将报告写入操作失败。
(3)、此时,应用程序可再次读写该RAM块。
(4)、BswM可通过轮询获取请求状态,也可通过回调函数接收通知。
(十八)、Static Block ID检查
每次将数据块写入NV存储器时,NvM会在该NV块中存储包含Static Block ID的NV Block Header。读取数据块时,会将其Static Block ID与请求读取的block ID进行比对。通过此机制,可检测出因硬件故障导致读取到错误数据块的问题。
每次将块写入NV存储器时,NvM均应存储Block Header中的Static Block ID字段。
每次从NV存储器读取块时,NvM均应检查该数据块的块头。
若Static Block ID检查失败,则应向DEM报告故障码NVM_E_WRONG_BLOCK_ID。
若Static Block ID检查失败,则应启动读错误恢复流程。
(十九)、重读
若NvM在从NV存储器读取数据的过程中检测到故障(如CRC错误),则应在继续读取redundant NV块之前,按照NVM_MAX_NUM_OF_READ_RETRIES的配置,执行一次或多次额外的读取尝试。
若NvM在从NV存储器读取数据的过程中检测到故障(如 CRC 错误),则应在继续读取ROM块之前,按照NVM_MAX_NUM_OF_READ_RETRIES的配置,执行一次或多次额外的读取尝试。
若NvM在从NV存储器读取数据的过程中检测到故障(如Static Block ID检查失败),则应在继续读取redundant NV块之前,按照NVM_MAX_NUM_OF_READ_RETRIES的配置,执行一次或多次额外的读取尝试。
若NvM在从NV存储器读取数据的过程中检测到故障(如Static Block ID检查失败),则应在继续读取ROM块之前,按照NVM_MAX_NUM_OF_READ_RETRIES的配置,执行一次或多次额外的读取尝试。
(二十)、写校验
若通过NVM_WRITE_VERIFICATION配置启用了该行为,则当某一RAM块的数据被写入NV存储器后,应立即将该NV块的数据读回,并与RAM块中的原始内容进行比较。
RAM块原始内容与读回块内容的比较应分步执行,确保每次读取和比较的字节数不超过配置参数NVM_WRITE_VERIFICATION_DATA_SIZE所规定的数值。
若RAM块中的原始内容与读回内容不一致,则应向DEM报告生产代码错误NVM_E_VERIFY_FAILED。
若RAM块中的原始内容与读回内容不一致,则应按照本文档中的规定执行写入重试操作。
若读回操作本身失败,则不执行读重试操作。
若无论是首次写入尝试,还是所有已配置的重试操作,RAM块中的原始内容与读回内容均不一致,则NvM模块应将请求结果设置为NVM_REQ_NOT_OK。
(二十一)、NvM中的NV数据比较
为避免对NV存储器执行不必要的写入操作,若某一特定RAM块的NV数据在运行期间未发生更新,NvM模块可提供一种基于CRC的比较机制,该机制可在处理写入任务时启用。
NvM模块应提供一项选项,通过实现基于CRC的比较机制,跳过对未变更数据的写入操作。
通常存在一种风险,RAM块中某些已变更的内容可能与初始内容生成相同的CRC值,若启用此选项,可能导致数据更新丢失。因此,该选项仅应在可容忍此风险的数据块上使用。
对于每个NVRAM块,若参数NvMBlockUseCrc设置为true,则应能通过参数NvMBlockUseCRCCompMechanism,配置是否使用基于CRC的比较机制。
(二十二)、NvM和BswM的交互
当NvM模块需要向BswM通知多块请求状态变更时,应调用BswM的BswM_NvM_CurrentJobMode()。
若NvMBswMMultiBlockJobStatusInformation为true,则NvM模块不应调用已配置的多块回调函数。
当NvM模块需要向BswM通知单块请求的接收状态(处于待处理状态)及处理结果时,应调用BswM的BswM_NvM_CurrentBlockMode()。
若NvMBswMMultiBlockJobStatusInformation为true,当NvM模块接收多块操作请求后,应通过调用BswM_NvM_CurrentJobMode()向BswM通知该请求已被接收且处于待处理状态,调用时需传入相关的多块请求类型,并将mode参数设为NVM_REQ_PENDING。
若NvMBswMMultiBlockJobStatusInformation为true,当多块操作完成或被取消时,NvM模块应通过调用BswM_NvM_CurrentJobMode()向BswM通知多块操作的处理结果,调用时需传入相关的多块请求类型,并将mode参数设为多块操作的最终结果。
若NvMBswMBlockStatusInformation为true,当NvM模块接收单块操作请求后,应通过调用BswM_NvM_CurrentBlockMode()向BswM通知该请求已被接收且处于待处理状态,调用时需传入相关的Block ID,并将mode参数设为NVM_REQ_PENDING。
若NvMBswMBlockStatusInformation为true,当单块操作完成或被取消时,NvM模块应通过调用BswM_NvM_CurrentBlockMode()向BswM通知单块操作的处理结果,调用时需传入相关的Block ID,并将mode参数设为单块操作的最终结果。
若NvMBswMBlockStatusInformation为true,且NvM模块正在执行多块操作,则对于该多块操作中待处理的每个数据块,在开始处理该块时,NvM模块应通过调用BswM_NvM_CurrentBlockMode()向BswM通知该块已进入待处理状态,调用时需传入相关的Block ID,并将mode参数设为NVM_REQ_PENDING。
若NvMBswMBlockStatusInformation为true,且NvM模块正在执行多块操作,则对于该多块操作中处理完成的每个数据块,在该块处理结束时,NvM模块应通过调用BswM_NvM_CurrentBlockMode()向BswM通知该块的处理结果,调用时需传入相关的Block ID,并将mode参数设为该单块操作的最终结果。
(二十三)、块压缩
在将块数据写入NV存储器之前,需先对其进行压缩处理。压缩类型(块拆分、常规压缩、增量压缩)由供应商自行定义。
该功能的应用场景针对较大数据块且仅小部分数据发生变化的情况(例如行驶循环日志记录)。其设计目标是避免将整个数据块写入NV存储器,从而减少总体写入次数。
块拆分(Block Split):将完整数据块划分为多个子块,仅写入发生变化的子块。
增量压缩(Delta Compression):仅写入发生变化的增量数据。
除此之外,也可采用任意类型的数据压缩算法。
该机制的缺点是:无论写入还是读取数据,其运行时间都会相应增加(因需额外执行压缩 / 解压缩操作)。

若NvMBlockUseCompression设置为true,则NvM模块应对存储到NV存储器中的数据进行压缩处理。
(二十四)、块加密
为保障安全性,NvM模块支持通过CSM使用对称的 16 字节对齐算法(如 AES128)进行同步加密和解密操作。
用户始终操作明文数据,而 NV和RAM中存储的是加密数据:
写入数据:NvM模块对用户提供的明文数据进行加密,然后将加密后的数据转发至存储设备。
读取数据:NvM模块从存储设备读取加密数据,对其进行解密,最终向用户提供明文数据。
为检查加密数据的完整性,可按常规方式配置CRC。NvM模块会对加密数据计算CRC,并在解密前重新计算并校验CRC,CRC始终与加密数据匹配。
若已指定NvMBlockCipheringRef,则NvM模块在将写入请求转发至MemIf之前,应使用Csm_Encrypt() (结合NvMCsmEncryptionJobReference中指定的CSM任务)对明文数据进行加密。(若已配置)CRC 计算应基于加密后的数据进行。
若Csm_Encrypt()返回CRYPTO_E_BUSY,NvM模块应重试该操作。在重试次数达到NvMCsmRetryCounter后,NvM模块应终止写入任务,将NvM结果设置为NVM_REQ_NOT_OK,并通过NvM_JobErrorNotification()发出错误信号。
若Csm_Encrypt()返回除CRYPTO_E_BUSY或CRYPTO_E_OK之外的任何错误,NvM模块应终止写入任务,将NvM结果设置为NVM_REQ_NOT_OK,并通过NvM_JobErrorNotification()发出错误信息。
若Csm_Encrypt()成功返回CRYPTO_E_OK,NvM模块应使用NvMNvBlockNVRAMDataLength中指定的新长度继续执行写入任务(例如执行CRC计算)。
若resultLengthPtr中返回的长度与NvMNvBlockNVRAMDataLength不匹配,应触发错误NVM_E_BLOCK_CHIPHER_LENGTH_MISSMATCH。
若已指定NvMBlockCipheringRef,NvM模块在将读取请求转发至应用程序之前,应使用Csm_Decrypt()(结合NvMCsmDecryptionJobReference中指定的CSM任务)对存储的数据进行解密。(若已配置)CRC校验应基于加密后的数据进行。若CRC校验不匹配,NvM模块将不执行解密操作,而是以NVM_REQ_INTEGRITY_FAILED终止任务。
若Csm_Decrypt()返回CRYPTO_E_BUSY,NvM模块应重试该操作。在重试次数达到NvMCsmRetryCounter后,NvM模块应终止读取任务,将NvM结果设置为NVM_REQ_NOT_OK,并通过NvM_JobErrorNotification()发出错误信息。
若Csm_Decrypt()返回除CRYPTO_E_BUSY或CRYPTO_E_OK之外的任何错误,NvM模块应终止读取任务,将NvM结果设置为NVM_REQ_NOT_OK,并通过NvM_JobErrorNotification()发出错误信息。
若Csm_Decrypt()成功返回CRYPTO_E_OK,NvM模块应使用NvMNvBlockLength中指定的新长度继续执行读取任务。
若resultLengthPtr中返回的长度与NvMNvBlockLength不匹配,应触发NVM_E_BLOCK_CHIPHER_LENGTH_MISSMATCH。
五、主要代码和参数描述
(一)、主要函数
1、void NvM_Init(const NvM_ConfigType* ConfigPtr)
NvM模块初始化。
2、Std_ReturnType NvM_SetDataIndex(NvM_BlockIdType BlockId,uint8 DataIndex)
为配置为NVM_BLOCK_DATASET的NVRAM块,设置访问的索引位置,只有设置了索引值才可以进行读写。
3、Std_ReturnType NvM_GetDataIndex(NvM_BlockIdType BlockId,uint8* DataIndexPtr)
为配置为NVM_BLOCK_DATASET的NVRAM块,获取当前配置的索引位置。
4、Std_ReturnType NvM_SetBlockProtection(NvM_BlockIdType BlockId,boolean ProtectionEnabled)
为NV块设置写保护。启用写保护后,NvM模块会拒绝所有针对该NV块的写入、擦除、失效等修改操作。但是RAM块的数据区域都是可写的。
5、Std_ReturnType NvM_GetErrorStatus(NvM_BlockIdType BlockId,NvM_RequestResultType*RequestResultPtr)
读取指定NVRAM块的信息,访问目标NVRAM块管理块中存储的错误/状态字段,获取该块最近一次异步请求的执行结果,或当前的数据完整性状态。
传入ID0,可以获取多块请求的整体执行结果。
返回状态如下:
6、void NvM_GetVersionInfo(Std_VersionInfoType* versioninfo)
获取NvM模块的版本号。
7、Std_ReturnType NvM_SetRamBlockStatus(NvM_BlockIdType BlockId,boolean BlockChanged)
修改RAM块状态。
当BlockChanged为TRUE时,标记RAM块为VALID/CHANGED,表明RAM块数据已更新,后续NvM_WriteAll()或NvM_WriteBlock()会将该RAM块数据同步到NV块,若RAM块配置了CRC,还会触发CRC重计算,由NvM_MainFunction()处理。
当BlockChanged为FALSE 时,标记RAM块为INVALID/UNCHANGED,后续读取操作需从NV块或ROM块加载数据,NvM_WriteAll()会跳过该块的NV同步。
该函数仅对配置了永久RAM块的NVRAM块和配置了显式同步机制的NVRAM块有效。
8、Std_ReturnType NvM_CancelJobs(NvM_BlockIdType BlockId)
取消指定块的所有待处理任务。
9、Std_ReturnType NvM_ReadBlock(NvM_BlockIdType BlockId,void* NvM_DstPtr)
将指定NV块数据复制到对应的临时RAM块中。如果有永久RAM区并且传入指针为NULL,则数据读取到永久RAM区。如果该块是数据集类型,根据索引位置也可以读取ROM块的数据。该接口是异步的。
10、Std_ReturnType NvM_WriteBlock(NvM_BlockIdType BlockId,const void* NvM_SrcPtr)
将指定临时RAM块中的数据复制到对应的NV块中。如果有永久RAM区并且传入指针为NULL,则数据从永久RAM区写到NV块中。该接口是异步的。
11、Std_ReturnType NvM_RestoreBlockDefaults(NvM_BlockIdType BlockId,void* NvM_DestPtr)
将指定NVRAM块的默认数据(来自ROM块或NvMInitBlockCallback回调提供的数据)复制到临时RAM块中。
该接口是异步的。
对于NVM_BLOCK_NATIVE和NVM_BLOCK_REDUNDANT,正常加载默认数据到RAM块,不影响NV块内容。
对于NVM_BLOCK_DATASET,若索引指向NV块,函数会拒绝请求,需先通过NvM_SetDataIndex()将索引切换至ROM块。
若NvMBlockUseSyncMechanism为TRUE,恢复时会调用NvM_ReadRamBlockFromNvCallback,由应用层将默认数据从NvM内部镜像复制到RAM块,若回调返回E_NOT_OK,NvM会重试NvMRepeatMirrorOperations次,重试失败则标记任务失败。
12、Std_ReturnType NvM_EraseNvBlock(NvM_BlockIdType BlockId)
擦除指定NV块数据,该接口是异步的。
如果是Fee类型的,不会进行擦除而是将某块标记为无效。
13、Std_ReturnType NvM_InvalidateNvBlock(NvM_BlockIdType BlockId)
将指定NV块标记为无效状态,使后续对该NV块的读取操作无法获取有效数据,除非重新进行写入操作该块就又变为有效。该接口是异步的。
14、Std_ReturnType NvM_ReadPRAMBlock(NvM_BlockIdType BlockId)
将指定NV块数据复制到其对应的Permanent RAM块中。该接口是异步的。
15、Std_ReturnType NvM_WritePRAMBlock(NvM_BlockIdType BlockId)
将指定Permanent RAM块中数据复制到对应的NV块中。该接口是异步的。
16、Std_ReturnType NvM_RestorePRAMBlockDefaults(NvM_BlockIdType BlockId)
将指定NVRAM块的默认数据(来自ROM块或NvMInitBlockCallback回调)恢复到其对应的Permanent RAM块中。
该接口是异步的。
17、void NvM_ReadAll(void)
初始化NVRAM块的管理数据。
将NV块数据加载到对应永久RAM块或触发显式同步回调完成数据复制)。
该接口是异步的。
18、void NvM_WriteAll(void)
将所有已更改的RAM数据写到NV块中。
该接口是异步的。
19、void NvM_CancelWriteAll(void)
取消正在执行或待处理的NvM_WriteAll()多块写请求。
该接口是异步的。
20、void NvM_ValidateAll(void)
标记所有RAM块为VALID/CHANGED,避免应用层对每个块单独调用NvM_SetRamBlockStatus()而提升效率。
该接口是异步的。
21、void NvM_FirstInitAll(void)
发起多块的初始化操作请求,即对NV块写入默认数据或标记为无效。通常该函数在ECU首次上电时使用。
写入默认数据:若块为NVM_BLOCK_NATIVE或NVM_BLOCK_REDUNDANT,且配置了默认数据或NvMInitBlockCallback回调,则将默认数据写入对应的NV块(冗余型块会写入两个NV块),同时更新RAM块(若有)数据并标记为VALID/UNCHANGED。
标记为无效:若块为NVM_BLOCK_DATASET,或无默认数据(无ROM块且无初始化回调),则通过与NvM_InvalidateNvBlock()相同的机制将NV块标记为无效,若块无永久RAM块且未启用显式同步,仅标记NV块,不修改RAM状态。
22、void NvM_JobEndNotification(void)
当MemIf成功完成NvM发起的请求,如写、读、擦除、无效等,调用该回调函数。
23、void NvM_JobErrorNotification(void)
当MemIf对NvM发起的请求操作失败,如写、读、擦除、无效等,调用该回调函数。
24、void NvM_MainFunction(void)
NvM模块主任务。
六、DaVinci Configurator主要配置

(一)、NvMCommonVendorParams

Data Integrity Buffer:
是否使能内部RAM缓冲区,当有内部RAM缓冲区时,用户调用写操作,在NvM主函数里会把传入数据地址里的数据先复制到内部RAM缓冲区,然后将内部缓冲区里的数据写到内存,这样确保了数据的一致性但是会增加RAM占用和增加操作延时。
Callback Include File List:
这里需要添加存放RAM块和ROM块的头文件。
(二)、NvMCommon

Api Configuration Class:
不同的等级可以使用不同范围的API,Class3能使用全部的API。
Call Cycle of NvM MainFunction[ms]:主函数运行的时间。
Compiled Configuration Id:
该值指定与NV存储器布局相关的配置 ID。
NvM会将配置ID存储在NVRAM中。系统启动时,NvM会将编译后的配置ID与存储的配置ID进行比较:
若两者数值匹配,则执行常规的NvM_ReadAll()服务。
若两者数值不匹配,则表明检测到配置更新,此时会根据参数NvMResistantToChangedSw的设置,执行对应的操作。
Crc Number of Bytes:
用于CRC计算处理的最大字节数, CRC计算的长度。
Csm Retry Counter:
该值指定了CSM加解密任务的重试次数。
Dataset Selection Bits:
该值指定在与MemIf的接口中,用于寻址某一NVRAM Block对应数据集的最低有效位数。
取值范围 0…8:此范围内的数值代表用于数据集寻址或冗余块寻址的位数。
取值 0:表示未配置任何数据集或冗余NVRAM块,因此不需要寻址选择位。
取值 1:表示仅配置了冗余NVRAM块,未配置数据集NVRAM块(此时1位寻址选择位可用于区分不同的冗余块)。
Detected Loss Of Redundancy Callback:
当读取某一存储块时检测到冗余块丢失时,该回调函数将被调用。
NvMCheckLossOfRedundancy启用时才有效。
Development Error Detection:
是否开启Det检查。
Drivers Mode Switch:
是否使能驱动在执行NvM_ReadAll和NvM_WriteAll时切换到快速模式,这是vector才有的选项,也需要存储器驱动支持该功能如果没有该选项勾了也没意义。
Dynamic Configuration Handling:
是否启用动态配置管理处理功能。若被禁用,则NvM无法使用ID为1的存储块。
Job Prioritization:
是否启用优先级处理。
Maximum Number of Write Retries:
NVRAM块的最大写入重试次数。
Multi Block Callback:
此参数定义了在每个异步多块请求终止时应调用的通用回调函数。
Multiblock job Status Information:
此参数决定了BswM是否会知晓多块任务的当前状态。
当ReadAll和WriteAll操作启动、完成或取消时,会调用BswM_NvM_CurrentJobMode()通知BswM。
Repair Redundant Blocks Api:
是否启用冗余块修复API。
Safe BSW Checks:
是否启用安全检查,启用后在执行函数前会对无效参数检查。
SetRamBlockStatus API:
NvM_SetRamBlockStatus()是否启用。
Size Of Immediate Job Queue:
Size Of Standard Job Queue:
定义Immediate和Standard任务的队列长度。
(三)、NvMBlockDescriptors





这里定义NVRAM块。
Block Length:
这里定义NV块的长度。如果有RAM块和ROM块需要与这两个块的长度一样。
Block Length Check:
是否使能块长度检查,使能后如果有RAM块和ROM块编译器会自动检查NV块长度是否和RAM块和ROM块一样,不一样的话会报错。
Block NV RAM Data Length:
该值用于指定当加密数据存储在NVRAM中时的块长度,在此情况下,明文数据长度可能与加密数据长度不匹配。
若已为该块启用数据加密与解密功能,则必须填写此值。访问NVRAM时,将使用该值替代NvMNvBlockLength。
Block Status Information:
使能后该块的NvM_RequestResultType类型发生变化时,调用BswM_NvM_CurrentBlockMode()通知BswM。
Block Use CRC Comp Mechanism:
该参数用于定义在写入操作期间,是否需要将RAM块的CRC值与上一次成功执行读取或写入操作时计算的CRC值进行比较。
CRC不匹配的话NvM将执行数据写入操作。
CRC匹配的话NvM不会执行实际的数据写入,但会表现得如同写入操作已完成。
Block Use MAC Comp Mechanism:
该参数用于定义在写入操作期间,是否需要将RAM块的MAC与上一次成功执行读取或写入操作时计算的MAC进行比较。
若MAC不匹配的话NvM将执行数据写入操作。
若MAC匹配的话NvM不会执行实际的数据写入,但会表现得如同写入操作已完成。
Block Use Set Ram Block Status:
该参数用于定义NvMSetRamBlockStatus()是否对该块使用。
Calculate Ram Block Crc:
使能后将对该块的永久RAM块进行CRC重计算。
Check Loss Of Redundancy:
当该块读取冗余块时,使能后会对冗余块的冗余数据进行检查,如果该块的数据存在差异会通过Dem上报但不会自动修复。
Crc Type:
如果该块定义了CRC,则选择是CRC32还是CRC16。
Crc usage:
是否对该块使用CRC功能。
Csm Decryption Job Reference:
Csm Encryption Job Reference:
引用Csm的解密任务,该任务用于在从NVRAM读取加密数据后对其进行解密,然后将明文数据传递给用户,若此参数为空,NvM会将NVRAM中的数据直接提供给用户。
引用Csm的加密任务,该任务用于在明文数据写入NVRAM之前对其进行加密,加密后的数据传递至NVRAM,若此参数为空,NvM会直接将用户提供的数据写入NVRAM。
Csm Mac Generation Job Reference:
Csm Mac Size:
Csm Mac Verification Job Reference:
定义是否使用CSM MAC产生和校验任务,通过MAC确保数据一致性,若启用后就不能使用CRC了。
Datasets:
定义NV块的数量,若是NVM_BLOCK_NATIVE固定为1,若是NVM_BLOCK_REDUNDANT固定为1,若是NVM_BLOCK_DATASET取值1-255。
Init Block Callback:
如果有定义,在执行加载默认块时如果没有ROM数据可用于初始化NVRAM块,会调用该块的回调函数。
在使用NvM_RestoreBlockDefaults()或读取失败时加载默认块。
Invoke Callbacks For Read All:
Invoke Callbacks For Write All:
该参数用于控制在执行NvM_ReadAll()期间,是否调用 NvMSingleBlockCallback和 NvMInitBlockCallback。
该参数用于控制在执行NvM_WriteAll()期间,是否调用NvMSingleBlockCallback。
Management Type:
定义了NVRAM块的块管理类型。
NVM_BLOCK_DATASET或NVM_BLOCK_NATIVE或NVM_BLOCK_REDUNDANT。
Priority:
定义该块的任务优先级,为0优先级最高是Immediate Job。
Ram Block Data:
该参数用于定义永久RAM块数据的变量名称。如果没有定义就是没有永久RAM块。
Read Ram Block From Nv Callback:
定义当从NVM读取数据到RAM时的回调。
Rom Block Data:
该参数用于定义ROM块数据的变量名称。如果没有定义就是没有ROM块。
Select Block For ReadAll:
定义该块在执行NvM_ReadAll()时是否处理该块。如果软件里块数量太多,此选项都勾上的话会延迟软件初始操作,比如第一帧NM报文发送时间都会有影响。
Select Block For WriteAll:
定义该块在执行NvM_WriteAll()时是否处理该块。
Single Block Callback:
定义该块的请求结束时回调函数。
Static Block Id Check:
是否使能静态ID检查。
Use Init Callback:
定义是否使用已配置的Init Block Callback。
Use Job End Callback:
定义是否使用Single Block Callback。
Use Service Ports:
定义该块是否使用服务端口来访问。
Use Synchronization Mechanism:
该参数用于定义是否对此块使用带有RAM镜像的显式同步机制,
Write Block Once:
定义该块是否首次写入后进行写保护。
Write Protection:
定义该块是否第一次就进行写保护。
Write Ram Block From Nv Callback:
定义当从RAM写数据到NVM时的回调。
Name Of Fee Block:
Name Of Ea Block:
此处选择NvM引用的非易失性内存的类型和对应的块引用即Fee还是Ea。
在NvM配置好块后,相应的在Fee或Ea也要添加对应的块,如果NVM有使能CRC,比如4个字节CRC,那么就要增加4个字节的块长度,如果NVM块类型是冗余块,相应的增加同数量的块,比如NvM引用Fee:
这里NvM配置了一个块,长度为2个字节,
带有CRC32校验,冗余类型,
相应的在Fee这里也要有两个6字节的块,
这里的冗余设置有些工具不一定在Fee里生成两倍长度的块,也有可能生成两个长度一样的块供NvM的冗余块使用。
七、使用例子
(一)、这里的伪代码描述第一次上电时,假设某个Nv块没有写入过并且有ROM块和RAM块,那么在调用NvM_ReadAll()后,NvM会使用默认值赋给某个NVRAM块,假设该块ID为2:
/**忽略其他配置**/
uint8 ram[3];/*该数组是块ID2的永久RAM块*/
const uint8 rom[3]={1,2,3};/*该数组是块ID2的永久ROM块*/
NvM_RequestResultType RequestResultPtr;
NvM_Init();
NvM_ReadAll();
do{
Fls_MainFunction();
Fee_MainFunction();
NvM_MainFunction();
NvM_GetErrorStatus(0, &RequestResultPtr);
} while ( RequestResultPtr == NVM_REQ_PENDING);
/**使用后ram数组里值为*1,2,3*/
NvM_ReadBlock(2,NULL);
(二)、这里的伪代码描述下电时,假设某个Nv块已经在RAM块更新过数据,但是还没存入NV块中,那么在调用NvM_WriteAll()后,假设该块ID为2:
/**忽略其他配置**/
uint8 ram[3]={1,2,3};/*该数组是块ID2的永久RAM块*/
NvM_RequestResultType RequestResultPtr;
NvM_Init();
/*触发下电场景*/
/*将块2设为CHANGED*/
NvM_SetRamBlockStatus(2,TRUE);
/*其他更新过RAM数据也要保存的也可以调用接口设为CHANGED*/
/*将CHANGED状态的都保存到NV块*/
NvM_WriteAll();
do{
Fls_MainFunction();
Fee_MainFunction();
NvM_MainFunction();
NvM_GetErrorStatus(0, &RequestResultPtr);
} while ( RequestResultPtr == NVM_REQ_PENDING);
(三)、数据集类型NVRAM块使用,这里假设该块为数据集类型并且没有ROM块,长度为3,数据集为4:
/**忽略其他配置**/
uint8 ram[12];/*该数组是块ID2的永久RAM块*/
uint8 i;
NvM_RequestResultType RequestResultPtr;
NvM_Init();
for(i=0;i<4;i++)
{
NvM_SetDataIndex(2, i);/*如果有ROM块,则索引4-7是访问ROM块*/
NvM_ReadBlock(2, &ram[i*3]);/*将数据集里的内容读到ram数组里*/
}
八、参考资料
AUTOSAR_CP_SWS_EEPROMAbstraction
AUTOSAR_CP_SWS_FlashEEPROMEmulation
AUTOSAR_CP_SWS_MemoryAbstractionInterface
AUTOSAR_CP_EXP_LayeredSoftwareArchitecture
AUTOSAR_CP_SWS_EEPROMDriver
AUTOSAR_CP_SWS_FlashDriver
AUTOSAR_CP_SRS_MemoryServices
AUTOSAR_CP_SWS_RTE
AUTOSAR_CP_SWS_BSWGeneral
TechnicalReference_NvM
TechnicalReference_Fee_30_FlexNor
ProductInformation_2_MICROSAR_FEE-MemoryManagement
UserManual_MemoryArchitecture_NXP_S32K3xx
AN-ISC-8-1207_Synchronization_Cry_Fls
AN-ISC-8-1249_Custom_vMem_Memory_Drivers
UserManual_FlashDriver
AN-ISC-8-1161_FEE_alignments_to_reduce_data_loss_through_ECC
AN-ISC-8-1173_Share_FEE_Blocks_Between_Application_and_Bootloader
ProductInformation_2_MICROSARClassic
总结
本文文字描述多点,更像是本人的使用笔记,仅供参考,如有不对地方欢迎指教。
当前vector代码不支持static id机制,即NV块里没有NV Block Header,最多只有NV Block Data和NV Block Crc。
更多推荐



所有评论(0)