目录
前言
正文
1.功能简介
2.关键概念
3.功能详解
3.1 内存硬件抽象层Ea/Fee的寻址方案
3.2 基本存储对象Basic storage objects
3.2.1 NV Block
3.2.2 RAM Block
3.2.3 ROM Block
3.2.4 Administrative block
3.2.5 NV Block Header
3.3块管理类型 Block management types
3.3.1NVRAM block structure
3.3.2 NVRAM block descriptor table
3.3.3Native NVRAM block
3.3.4 Redundant NVRAM block
3.3.5 Dataset NVRAM block
3.3.6NVRAM Manager API configuration classes
3.4扫描顺序/优先级方案 Scan order / priority scheme
3.5 功能需求 Functional requirements
3.6 NVM启动 NVRAM manager startup
3.7 NVM关机 NVRAM manager shutdown
3.8 对NvM模块的并行写访问 Parallel write access to the NvM module
3.9 NVM一致性检查 NVRAM block consistency check
3.10 错误恢复 Error Recovery
3.11 用ROM数据恢复RAM块
3.12 使用ROM默认数据隐式恢复RAM块
3.13 使用ROM默认数据显式恢复RAM
3.14 检测对NV块的写操作未完成
3.15 终止单个块请求
3.16 终止一个多块请求
3.17 异步请求/作业处理的一般处理
3.18 NVRAM块写保护
3.19 验证和修改RAM块数据
3.19. 1 The VALID / UNCHANGED state
3.19.2 The VALID / CHANGED state
3.19.3 The INVALID / UNCHANGED state
3.20 应用程序和NVRAM Manager之间的通信和隐式同步
3.20.1 写请求(NvM_WriteBlock or NvM_WritePRAMBlock)
3.20.2 读请求(NvM_ReadBlock or NvM_ReadPRAMBlock)
3.20.3 恢复默认请求(NvM_RestoreBlockDefaults and NvM_RestorePRAMBlockDefaults)
3.20.4 多块读请求 (NvM_ReadAll)
3.20.5 多块写请求(NvM_WriteAll)
3.20.6 删除操作 (NvM_CancelWriteAll)
3.20.7 管理块的修改 Modification of administrative blocks
3.21 NVRAM块的正常和扩展运行时准备
3.22 应用程序和NVRAM管理器之间的通信和显式同步
3.22.1 写请求(NvM_WriteBlock or NvM_WritePRAMBlock)
3.22.2 读请求 (NvM_ReadBlock or NvM_ReadPRAMBlock)
3.22.3 多块读请求(NvM_ReadAll)
3.22.4 多块写请求(NvM_WriteAll)
3.23 静态块ID检查
3.24 读重试
3.25 写校验
3.26 比较NvM中的NV数据
3.27 NvM和BswM交互
3.28 块锁定情况下的NvM行为
3.28.1 用例
3.28.2 使用(DCM)
4.API详解
4.1同步请求函数 Synchronous requests
4.1.1NvM_Init
4.1.2 NvM_SetBlockProtection
4.1.3 NvM_GetErrorStatus
4.1.4 NvM_CancelJobs
4.2异步单块请求 Asynchronous single block requests
4.2.1NvM_ReadBlock
4.2.2NvM_WriteBlock
4.2.3 NvMEraseNvBlock
4.3异步多块请求 Asynchronous multi block requests
4.3.1NvM_ReadAll
4.3.2 NvM_WriteAll
4.3.2NvM_CancelWriteAll
4.4回调函数
4.4.1 NvM_JobEndNotification
4.5期望的接口 Expected Interfaces
4.5.1必需的接口
4.5.2可配置的接口
5.服务接口 Service Interfaces
5.1 Client-Server-Interfaces
5.1.1 NvM_Admin
5.1.2 NvM_Mirror
5.1.3 NvM_NotifyInitBlock
5.1.4 NvM_NotifyJobFinished
5.1.5 NvM_Service
5.2 Implementation Data Types
5.2.1 NvM_RequestResultType
5.2.2 NvM_BlockIdType
5.2.3 ConstVoidPtr
5.3 Ports
5.3.1 NvM_PAdmin_{Block}
5.3.2 NvM_PM_{Block}
5.3.3 NvM_PNIB_{Block}
5.3.4 NvM_PNJF_{Block}
6.NVM配置
6.1NvMCommon
6.2NvMBlockDescriptor
前言
存储协议栈负责ECU中非易失性数据的存储管理。存储协议栈的分享包括NVM、MemI、Ea、Fea、Eep、Fls模块的详细介绍及代码分析,具体的项目实战请关注本号的后续文章,本篇为NVRAM Manager(NVM)模块详细介绍篇。
正文
1.功能简介
NvM模块应根据汽车环境中NV(非易失性)数据的不同需求提供服务,以确保数据的存储和维护。NvM模块应该能够管理EEPROM和/或FLASH EEPROM仿真设备的NV数据。
NvM模块为NV数据(init/read/write/control)的管理和维护提供所需的同步/异步服务。
不同块之间的关系可以在下图中可视化:
2.关键概念
Basic Storage Object: “基本存储对象”是“NVRAM块”的最小实体。几个“基本存储对象”可以用来构建一个NVRAM块。一个“基本存储对象”可以驻留在不同的内存位置(RAM/ROM/NV内存)。
NVRAM Block: NVRAM Block是管理和存储 NV Block所需的整个结构。
NV data: 要存储在Non-Volatile memory的数据。表示NV用户数据和CRC值(可选)组成的存储区。
Block Management Type: 这个是NVRAM Block的类型,它取决于强制/可选Basic Storage Object中 NVRAM Block的(可配置的)单独组成以及该 NVRAM 块的后续处理。
RAM Block: 属于Basic Storage Object,它是NVRAM Block的一部分,常驻于RAM空间。为了应对应用层的快速操作,创建的与NV Block同样大小的RAM空间,用于存储还没有被写入或读取的NV值。表示在RAM中用户数据和CRC值(可选)组成的区域。
ROM Block: 属于Basic Storage Object,它是NVRAM Block的一部分(可选的),常驻于ROM空间。ROM块驻留在ROM(Data Flash)中,用于提供缺省数据以防NV块为空或被破坏。
NV Block: 属于Basic Storage Object,它是NVRAM Block的一部分(必选的),常驻于NV空间。NV Block表示NV用户数据和CRC值(可选)组成的存储区。
NV Block Header: 如果Static Block ID是enable的,这个作为附加信息包含在NV Block中。
Administrative Block: 属于Basic Storage Object,它常驻于RAM,是NVRAM Block必选部分。Administrative Block管理块在RAM中,包含Dataset NV块关联的块索引。也包含相应NVRAM块的属性、错误、状态信息。
3.功能详解
3.1 内存硬件抽象层Ea/Fee的寻址方案
内存抽象接口,底层的Flash EEPROM仿真和EEPROM抽象层为NvM模块提供了一个虚拟线性32位地址空间,该地址空间由一个16位块号和一个16位块地址偏移组成。
Note: NvM模块允许(理论上)最大65536个逻辑块,每个逻辑块(理论上)最大大小为64kbytes。
NvM模块将进一步将16bit Fee/Ea区块号细分为以下部分:
- NV块基数(NVM_NV_BLOCK_BASE_NUMBER),位宽为(16 -NVM_DATASET_SELECTION_BITS)
- 位宽为(NVM_DATASET_SELECTION_BITS)的数据索引
对冗余NVRAM块的处理/寻址应以与数据集NVRAM块相同的方式对内存硬件抽象进行,即冗余NV块应通过使用配置参数NvMDatasetSelectionBits来管理。
FEE/EA_BLOCK_NUMBER = (NvMNvBlockBaseNumber << NvMDatasetSelectionBits)
+ DataIndex.
示例:
配置参数vmdatasetselectionbits配置为2。这将导致14位可作为配置参数nvnvblockbasenumber的范围:
-- Range of NvMNvBlockBaseNumber: 0x1..0x3FFE
-- Range of data index: 0x0..0x3(=2^NvMDatasetSelectionBits-1)
-- Range of FEE_BLOCK_NUMBER/EA_BLOCK_NUMBER: 0x4..0xFFFB
有了这个配置,FEE/EA_BLOCK_NUMBER会使用前面提到的公式计算,如下面的例子所示:
对于NvMNvBlockBaseNumber = 2的Native NVRAM block:
-- NV block is accessed with FEE/EA_BLOCK_NUMBER = 8
8 == 2 << 2 + 0
对于NvMNvBlockBaseNumber = 3的redundant NVRAM block:
-- 1st NV block with data index 0 is accessed with FEE/EA_BLOCK_NUMBER = 12.
12 == 3 << 2 +0
-- 2nd NV block with data index 1 is accessed with FEE/EA_BLOCK_NUMBER = 13.
13 == 3 << 2 + 1
对于NvMNvBlockBaseNumber = 4, NvMNvBlockNum = 3的 dataset NVRAM block:
-- NV block #0 with data index 0 is accessed with FEE/EA_BLOCK_NUMBER = 16
16 == 4 << 2 + 0
-- NV block #1 with data index 1 is accessed with FEE/EA_BLOCK_NUMBER = 17
16 == 4 << 2 + 1
-- NV block #2 with data index 2 is accessed with FEE/EA_BLOCK_NUMBER = 18
16 == 4 << 2 + 2
3.2 基本存储对象Basic storage objects
3.2.1 NV Block
NV块是一个基本的存储对象,表示一个由NV用户数据、CRC值(可选)和NV块报头(可选)组成的内存区域。NV Block是必须存在的模块,数据内容持久存在与flash中,可以在程序执行过程中修改,它的组成:
3.2.2 RAM Block
RAM块是一个基本的存储对象,表示RAM中由用户数据和(可选的)CRC值和(可选的)NV块头组成的区域。
RAM块上CRC使用的限制。只有当相应的NV块也有CRC时,CRC才可用。CRC必须与相应的NV块的类型相同。
RAM块的用户数据区域可以驻留在与RAM块状态不同的RAM地址位置(全局数据段)。
RAM块的数据区域应该可以从NVRAM管理器和应用程序端访问(数据从/传递到相应的NV块)。
RAM块数据应包含永久或临时分配的用户数据。对于永久分配的用户数据,RAM块数据的地址在配置期间是已知的。在临时分配用户数据的情况下,RAM块数据的地址在配置期间是未知的,将在运行时传递给NvM模块。
在没有地址约束的情况下,可以在全局RAM区域内分配每个RAM块。配置的RAM块的总数不需要位于连续的地址空间中。
NV数据的读写是相对较慢的操作,而swc task执行时间较快,如果直接读写太过频繁不可取,所以一般会使用一个同样大小的Ram空间来操作、使用、存放这些还没有被写入或者读取的NV值。
RAM Block 是NV Block在RAM中的一个映射,因为应用层不能直接操作NV(速度太慢),所以基本上是一个1:1的结构。
注意:这个图没有显示RAM块的物理内存布局。这里只显示逻辑集群。
由于NvM模块不支持对齐,这可以通过配置来管理,也就是说,块的长度可以通过添加填充来扩大,以满足对齐要求
3.2.3 ROM Block
ROM块是一个基本的存储对象,位于ROM (FLASH)中,用于在NV块为空或损坏时提供默认数据。
3.2.4 Administrative block
1)专门用于对NVRAM Block 与 RAM blcok 的数据安全性进行管理而设计的,它对应用层并不可见。
2)存在与RAM中,不是持久的,用于保存相应NVRAM块的属性/错误/状态信息,以及‘Dataset’类型的NVRAM块的块索引
2)结构组成
nv block,RAM block 和 Administrative Block必须存在,ROM block为可选项。包含哪些block是在配置阶段完成,相应的NVRAM block descriptor配置完成后,包含block也随之固定。
3.2.5 NV Block Header
如果启用了机制静态块ID,则NV块标头应首先包含在NV块中。
3.3块管理类型 Block management types
NvM数据的管理主要包括三种管理类型,分别是Native NVRAM block、redundant NVRAM block、Dataset NVRAM block。具体对各个Block的使用情况如下图所示。
Block management types | NV block | RAM block | ROM block | Administrative block |
NVM_BLOCK_NATIVE | 1 | 1 | 0/1 | 1 |
NVM_BLOCK_REDUNDANT | 2 | 1 | 0/1 | 1 |
NVM_BLOCK_DATASET | <256 | 1 | 0...n | 1 |
3.3.1NVRAM block structure
NVRAM块由强制性的基本存储对象NV块、RAM块和管理块组成。基本的存储对象ROM Block是可选的。任何NVRAM块的组成在配置期间由相应的NVRAM块描述符固定。所有的地址偏移量都相对于NVRAM块描述符中的RAM或ROM的起始地址给出。假设起始地址为零。
Note:如果需要,相应的设备驱动程序将添加一个设备特定的基本地址或偏移量。
3.3.2 NVRAM block descriptor table
要处理的单个NVRAM块将通过NvM模块API通过提供随后分配的块ID来选择。所有与NVRAM块描述符表及其在ROM (FLASH)中的地址相关的结构都必须在NvM模块配置期间生成。
3.3.3Native NVRAM block
Native NVRAM block是最简单的Block形式,该类型包括1个NV Block,1个RAM Block,1个Administrative Blocks。
3.3.4 Redundant NVRAM block
Redundant NVRAM block该类型包括2个NV Block,1个RAM Block,1个Administrative Blocks,通过该类型可以实现数据的冗余备份存储。
3.3.5 Dataset NVRAM block
Dataset NVRAM是由多个大小相等的数据组成,APP在一次操作中获得其中的一个元素,每一个DataSet的位置可以通过Administrative Blocks获得,NvM可以读取选择的ROM Block。Dataset NVRAM类型的设计可以根据需要对一个数据在NvRAM中以一定的循环偏移进行存储,每一次存储位置可以不同,实现对NvRAM的寿命延长。
3.3.6NVRAM Manager API configuration classes
为了使NvM模块适应有限的硬件资源,需要定义三个不同的API配置类:
- API配置类3:所有指定的API调用都可用。支持最大限度的功能。
- API配置类2:一个中间的API调用集是可用的。
- API配置类1:特别是对于匹配具有非常有限的硬件资源的系统,这个API配置类只提供了在任何情况下都需要的最小的API调用集。
在API配置类1中,不支持块管理类型NVM_BLOCK_DATASET。NvM模块应该只包含处理配置的块类型所需的代码。
3.4扫描顺序/优先级方案 Scan order / priority scheme
NvM模块应支持基于优先级的作业处理。
通过配置参数nvmjobpriority,基于优先级的作业处理将被启用/禁用。
在基于优先级的作业处理顺序的情况下,NvM模块应该使用两个队列,一个用于立即写作业(崩溃数据),另一个用于所有其他作业(包括立即读/擦除作业)。
如果通过配置禁用了基于优先级的作业处理,NvM模块将不支持立即写作业。在本例中,NvM模块按FCFS(First Come, First Service)顺序处理所有作业。
对于来自NvM_ReadAll和NvM_WriteAll的多个块请求,作业队列长度应该是一个(只有一个作业在排队)。
NvM模块不能中断由NvM_ReadAll请求引起的其他请求的任务。
注意:唯一的例外是具有直接优先级的写作业,它将抢占正在运行的读/写作业。被抢占的任务随后将由NvM模块恢复/重启。
NvM模块不能中断来自其他请求的NvM_WriteAll请求。
NvM模块应该对正在进行的NvM_ReadAll请求中请求的读任务进行排队,然后执行它们。
NvM模块应该对正在进行的NvM_WriteAll请求中请求的写作业进行排队,然后执行它们。
NvM模块应该对正在进行的NvM_ReadAll请求中请求的写作业进行排队,然后执行它们。
NvM模块应该对正在进行的NvM_WriteAll请求中请求的读作业进行排队,然后执行它们。
注意:NvM_WriteAll请求可以通过调用NvM_CancelWriteAll来终止。在这种情况下,当前块被完全处理,但不再写入其他块
提示:它将被允许退出队列的请求,如果他们成为过时的完成有关NVRAM块。
被抢占的任务随后将由NvM模块恢复/重启。这种行为既适用于单块请求,也适用于多块请求。
3.5 功能需求 Functional requirements
对于每个异步请求,在任务完成后通知调用者应该是一个可配置选项。
NvM模块应提供一个回调接口。
提示:NvM模块的环境只能通过NvM模块访问非易失性内存。不允许任何模块(除了NvM模块)直接访问非易失性内存。
NvM模块只提供了一种隐式的方式来访问NVRAM和共享内存(RAM)中的块。这意味着,NvM模块将一个或多个块从NVRAM复制到RAM,反之亦然。
应用程序直接访问RAM数据,根据给定的限制(例如同步)。
NvM模块将对所有异步的“单块”读/写/控制请求进行排队,如果具有特定ID的块尚未排队或正在进行(多任务限制)。
只要不发生队列溢出,NvM模块将接受多个异步的“单块”请求。
优先级最高的请求将由NvM模块从队列中获取,并以序列化的顺序处理。
NvM模块应该实现隐式机制来对保存在NV内存中的数据进行一致性/完整性检查。
根据内存堆栈的实现,NvM模块提供和/或调用的回调例程可能在中断上下文中被调用。
提示:提供在中断上下文中调用的例程的NvM模块因此必须确保它们的运行时间相当短。
如果在配置时没有默认的ROM数据可用,或者没有NvMInitBlockCallback定义的回调,那么应用程序将负责提供默认的初始化数据。
在这种情况下,应用程序必须使用NvM_GetErrorStatus()来区分首次初始化和损坏的数据。
在处理NvM_ReadAll的过程中,NvM模块应该能够通过执行校验和计算来检测损坏的RAM数据。
在处理NvM_ReadAll的过程中,NvM模块应该能够通过测试管理块内数据的有效性来检测RAM中的无效数据。
在启动阶段和NvM_ReadAll的正常运行期间,如果NvM模块在NV块内检测到不可恢复的错误,NvM模块将复制默认数据(如果配置)到相应的RAM块。
为了使用OS服务,NvM模块只能使用BSW调度器,而不能直接使用OS对象和/或相关的OS服务。
3.6 NVM启动 NVRAM manager startup
NvM_Init应该由ECU状态管理器独占调用。
由于ECU启动时间的强约束,NvM_Init请求不能包含配置的NVRAM块的初始化。
NvM_Init请求不负责触发底层驱动和内存硬件抽象的初始化。这也应由EcuM处理。
内存数据块的初始化应该由另一个请求完成,即NvM_ReadAll。
如果使用EcuM Fixed, NvM_ReadAll将由EcuM调用,如果使用EcuM Flex,则由集成代码调用。
使用NvM模块的软件组件应负责检查由于NvM模块启动而产生的全局错误/状态信息。ECU状态管理器应该通过使用NvM_GetErrorStatus(预留块ID 0)或回调通知(可配置选项NvM_MultiBlockCallback)来轮询启动过程中产生的全局错误/状态信息。如果使用轮询,NVRAM启动过程的结束将由全局错误/状态NVM_REQ_OK或NVM_REQ_NOT_OK检测(在启动过程NVM_REQ_PENDING期间)。如果回调被选择用于通知,如果指定的NVRAM块已被处理,软件组件将被自动通知。
注1:如果回调被配置为每个NVRAM块在NvM_ReadAll内处理,它们可以被RTE在早期的时间点启动,例如SW-Cs。
注2:为了确保DEM在早期完全运行,即它的NV数据被恢复到RAM中,与DEM相关的NVRAM块应该配置为低ID,在NvM_ReadAll中首先处理。
NvM模块不能以持久的方式自动存储当前使用的Dataset索引。软件组件应该检查他们负责的所有块的特定错误/状态,使用带有特定块id的NvM_GetErrorStatus来确定对应RAM块的有效性。
对于块管理类型为“NVRAM数据集”的所有块,软件组件应负责通过NvM_SetDataIndex设置适当的索引位置。例如,当前索引位置可以被软件组件存储/维护在一个唯一的NVRAM块中。为了获得“数据集块”的当前索引位置,软件组件应该使用NvM_GetDataIndex API调用。
3.7 NVM关机 NVRAM manager shutdown
基本的关闭过程应该由请求NvM_WriteAll完成。
提示:NvM_WriteAll将被ECU状态管理器调用
3.8 对NvM模块的并行写访问 Parallel write access to the NvM module
NvM模块应该通过一个使用排队机制的异步接口来接收请求。NvM模块将根据请求的优先级顺序处理所有请求。
3.9 NVM一致性检查 NVRAM block consistency check
NvM模块应该提供隐式的技术来检查NVRAM块的数据一致性。
NVRAM块的数据一致性检查应通过CRC对其相应的NV块进行重新计算来完成。
数据一致性检查的隐式方式应由内部功能的可配置选项提供。隐式一致性检查对每个NVRAM块都是可配置的,依赖于可配置的参数NvMBlockUseCrc和NvMCalcRamBlockCrc。
当NVRAM块的NvMWriteBlockOnce = TRUE时,应该启用NVRAM块校验NvMBlockUseCrc。当NVRAM块的NvMWriteBlockOnce = TRUE时,应该禁用NVRAM块的NvMBlockWritePort,以便在CRC检查失败的情况下,用户可以向NVRAM块写入数据。
根据可配置参数NvMBlockUseCrc和NvMCalcRamBlockCrc, NvM模块将为使用的最大CRC分配内存。
提示:NvM用户必须不知道关于CRC内存(例如大小,位置)的任何东西,为他们的数据在RAM块。
3.10 错误恢复 Error Recovery
NvM模块应该提供错误恢复的技术。错误恢复取决于NVRAM块管理类型。
NvM模块通过加载默认值,为每一种NVRAM块管理类型提供读取时的错误恢复。
NvM模块将通过加载RAM块的默认值,在读取块管理类型为 NVM_BLOCK_REDUNDANT的NVRAM块时提供错误恢复。
无论NVRAM块管理类型如何,NvM模块都应该通过执行写重试来提供写时的错误恢复。
在RAM块重新验证失败的情况下,NvM模块应在启动时为所有配置了RAM块CRC的NVRAM块提供读取错误恢复。
3.11 用ROM数据恢复RAM块
当NV块出现不可恢复的数据不一致时,NvM模块应提供隐式和显式恢复技术,将ROM数据恢复到相应的RAM块。
3.12 使用ROM默认数据隐式恢复RAM块
在隐式恢复过程中,相应NV块的数据内容保持不变。
在启动(NvM_ReadAll的一部分)时不提供隐式恢复,当没有配置ROM块时(通过参数NvMRomBlockDataAddress或NvMInitBlockCallback),每个NVRAM块都不提供NvM_ReadBlock或NvM_ReadPRAMBlock。
在以下情况下,在启动(NvM_ReadAll的一部分)和NVRAM块的NvM_ReadBlock或NvM_ReadPRAMBlock不会提供隐式恢复: (1)&&(2)
(1) 配置了ROM块(通过参数nvromblockdataaddress或参数NvMInitBlockCallback)
(2) NvM模块中的永久RAM块或RAM镜像的内容(在显式同步的情况下)状态是有效的,CRC(数据)是一致的。
在以下情况下,在启动(NvM_ReadAll的一部分)和NVRAM块的NvM_ReadBlock或NvM_ReadPRAMBlock不会提供隐式恢复: (1)&&(2)&&(3)
(1) 配置了ROM块(通过参数nvromblockdataaddress或参数NvMInitBlockCallback)
(2) NvM模块中的永久RAM块或RAM镜像的内容(在显式同步的情况下)无效,CRC(数据)不一致。
(3) 从NV成功读取尝试。
在以下情况下,隐式恢复应该在启动时(NvM_ReadAll的一部分)或者NVRAM块的NvM_ReadBlock或NvM_ReadPRAMBlock时被提供:
(1)配置了ROM块(通过参数nvromblockdataaddress或参数NvMInitBlockCallback)
(2)NvM模块中的永久RAM块状态或RAM镜像的内容(在显式同步的情况下)是无效的,CRC(数据)不一致。
(3)从NV读取失败。
隐式恢复应该在NvM_ReadBlock()或NvM_ReadPRAMBlock()请求NVM_BLOCK_NATIVE和NVM_BLOCK_REDUNDANT类型的NVRAM块时提供。
3.13 使用ROM默认数据显式恢复RAM
对于使用ROM块数据的显式恢复,NvM模块应该提供NvM_RestoreBlockDefaults和NvM_RestorePRAMBlockDefaults函数来将ROM数据恢复到相应的RAM块。
NvM_RestoreBlockDefaults和NvM_RestorePRAMBlockDefaults函数不会修改对应NV块的数据内容。
提示:应用程序每次需要将ROM数据恢复到相应的RAM块时,使用NvM_RestoreBlockDefaults或NvM_RestorePRAMBlockDefaults函数。
3.14 检测对NV块的写操作未完成
检测NV块的未完成写操作不在NvM模块的范围之内。这是由内存硬件抽象处理和检测的。NvM模块期望从内存硬件抽象中获取信息,如果引用的NV块无效或不一致,并且在请求时无法读取。
SW-Cs可能会使用NvM_InvalidateNvBlock来阻止底层传递旧数据。
3.15 终止单个块请求
NvM模块提供的所有异步请求(除了NvM_CancelWriteAll)都应该在相应的管理块的指定的错误/状态字段中指明结果。
可选配置参数NvMSingleBlockCallback在异步块请求终止时通过回调来配置通知(NvM_CancelWriteAll除外)。
注意:在与应用SW-C通信时,NvMSingleBlockCallback需要映射到Rte_call_<p>_<o> API。
3.16 终止一个多块请求
NvM模块应该使用一个单独的变量来存储异步多块请求的结果(NvM_ReadAll, NvM_WriteAll包括NvM_CancelWriteAll, NvM_ValidateAll)。
函数NvM_GetErrorStatus将返回异步多块请求(包括NvM_CancelWriteAll)的最新错误/状态信息,并将保留的块ID值设置为0。
多块请求的结果只能代表一个常见的错误/状态信息。
NvM模块提供的多块请求应在每个受影响的管理块指定的错误/状态字段中指明其详细的错误/状态信息。
可选配置参数NvMMultiBlockCallback在异步多块请求终止时通过callback配置通知。
3.17 异步请求/作业处理的一般处理
每次在一个请求中处理CRC计算时,如果NVRAM块的长度超过参数NvMCrcNumOfBytes.配置的字节数,NvM模块就会分多次计算CRC。
对于CRC计算,NvM模块应使用CRC模块公布的初始值。
多个并发的单个块请求应该是可排队的。
NvM模块将中断异步请求/任务处理,优先处理具有即时优先级的任务(崩溃数据)。
如果在NvM模块上调用异步函数导致作业队列溢出,该函数将返回E_NOT_OK。
当一个请求成功进入队列时,NvM模块应该将对应NVRAM块的请求结果设置为NVM_REQ_PENDING。
如果NvM模块已经成功处理了一个任务,它将返回NVM_REQ_OK作为请求结果。
3.18 NVRAM块写保护
NvM模块应该提供不同类型的写保护,这些写保护应该是可配置的。每一种写保护都只与NVRAM块的NV部分有关,即RAM块数据可以修改,但不能写入NV内存。
当“NvMWriteBlockOnce”为FALSE时,无论“ NvMBlockWriteProt”配置的值(True/ FALSE)是多少,使用“NvM_SetBlockProtection”功能都允许开启/关闭写保护。
当“NvMWriteBlockOnce”为TRUE时,无论“NvMBlockWriteProt”配置的值是(TRUE /False),使用NvM_SetBlockProtection功能都不允许开启/关闭写保护。
对于所有配置了NVRAM块的NvMBlockWriteProt = TRUE, NvM模块应该启用默认写保护。
NvM模块的环境可以使用NvM_SetBlockProtection功能显式地禁用写保护。
对于配置了NvMWriteBlockOnce == TRUE的NVRAM块,NvM模块只能向相关的NV内存写入一次,即在空白NV设备的情况下。
对于配置了NvMWriteBlockOnce == TRUE的NVRAM块,NvM模块不允许使用NvM_SetBlockProtection功能显式地禁用写保护。
对于配置了MVM_WRITE_BLOCK_ONCE (TRUE)的块,NvM将拒绝第一个读请求之前的任何写/擦除/无效请求。
注意:如果重置,NvM管理块中配置了NVM_WRITE_BLOCK_ONCE (TRUE)的块的写保护标志将被清除。为了重新激活该保护,必须在第一个写/擦除/失效请求被处理之前读取该块,以便设置写保护仅对有效且一致的块有效。第一个读请求可以作为单个块请求完成,也可以作为NvM_ReadAll的一部分完成。
3.19 验证和修改RAM块数据
下图描述了RAM块的状态转换。
由于进入和保持一种状态可以基于多种条件,而把它们都放在上面的图中会让人难以理解,所以在下面的小节中会提供更详细的解释。INVALID / CHANGED状态没有详细说明,因为它永远无法到达(如上图所示)。
在初始化之后,RAM块的状态是INVALID/UNCHANGED,直到通过NvM_ReadAll更新它,这将导致转换到VALID/UNCHANGED状态。在这个状态下,不允许WriteAll。如果调用了NvM_SetRamBlockStatus,这个状态是左边的。如果发生CRC错误,RAM块再次改变到无效状态,这可以通过隐式或显式错误恢复机制离开。错误恢复后,块的状态是VALID/CHANGED,因为RAM的内容不同于NVRAM内容。
如果修改RAM块状态的API已经配置好了(通过NvMSetRamBlockStatusApi或NvMBlockUseSetRamBlockStatus), NvM模块在写入一个RAM块或NvM模块中的RAM镜像时(在显式同步的情况下),NvM模块应将其视为有效且被修改,即在NvM_WriteAll期间,NvM模块应将每个永久RAM块写入NV内存。
如果修改RAM块状态的API已经配置好了(通过vmsetramblockstatusapi或
NvMBlockUseSetRamBlockStatus) NvM模块在读取RAM块时将其视为无效的,即在NvM_ReadAll期间,NvM模块将每个NVRAM块复制到RAM中,如果配置了相应的NVRAM块。
如果块读取尝试失败,则应用程序负责在下一次写尝试之前提供有效的数据。
如果一个RAM块成功地复制到NV内存,那么RAM块的状态将被设置为“有效/未修改”。
3.19. 1 The VALID / UNCHANGED state
这种状态意味着RAM块的内容要么与相应的NV块的内容相同,要么——如果应用程序已经访问了RAM块——还没有表明潜在的变化。对于DATASET块,这些条件适用于最后处理的实例的RAM内容。另外,最后一个块操作是成功的,并且该块没有被请求无效。
要进入 VALID / UNCHANGED状态,至少必须发生以下任一情况:
1) NvM_ReadAll()成功读取块
2) 该块的NvM_ReadBlock成功完成
3)块的NvM_WriteBlock成功完成
4) NvM_WriteAll()写块成功
同时满足以下条件时,VALID / UNCHANGED状态被保存:
-- 对BlockID的最后一次读或写是成功的(没有错误,也没有获取默认数据)
-- 应用程序没有表明RAM块自上次读或写以来的潜在变化
3.19.2 The VALID / CHANGED state
这种状态意味着RAM块的内容可能与相应的NV块的内容不同。对于DATASET块,此条件适用于最后处理的实例的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状态被保存:
-- 块所有者指出了RAM块的潜在变化
-- 在上次读取时,会(隐式或显式地)为块检索默认数据
3.19.3 The INVALID / UNCHANGED state
这种状态意味着NV块无效。对于DATASET块,这意味着NV块内容对于处理的最后一个实例无效。
要进入 INVALID / UNCHANGED状态,至少必须发生以下任一情况:
1. 调用NvM_SetRamBlockStatus时为该块设置FALSE
2. NvM_ReadBlock表示用户请求块无效
3.NvM_ReadBlock表示块的数据损坏(如果配置了CRC)
4. NvM_ReadBlock表示该块的StaticID错误(如果配置了)
5. 该块的NvM_WriteBlock完成不成功
6. NvM_WriteAll写块不成功
7. 该块的NvM_InvalidateNvBlock成功完成
8. 该块的NvM_EraseNvBlock成功完成
满足以下任一条件时,INVALID / UNCHANGED状态被保存:
-- 块的状态在当时是未知的(早期初始化,直到ReadAll或第一个操作请求一个给定的块)
-- 该块被检测到损坏或错误的StaticID
-- 对该块的最后一次成功操作是无效的
-- 当前读取失败,没有默认数据
--- 对该块的最后一次成功操作是删除操作
3.20 应用程序和NVRAM Manager之间的通信和隐式同步
为了最小化锁/解锁的开销或使用其他同步方法,应用程序和NvM模块之间的通信必须遵循下面描述的严格的步骤序列。这确保了应用程序和NvM模块之间的可靠通信,避免了RAM块中的数据损坏,并保证了适当的同步。
此访问模型假设双方参与了与RAM块的通信:应用程序和NvM模块。
如果多个应用程序都在使用同一个RAM块,NvM模块就不能确保RAM块的数据完整性。在这种情况下,应用程序必须同步它们对RAM块的访问,并且必须保证在NVRAM期间不会发生对RAM块不合适的访问操作。
特别是当几个应用程序通过使用(不同的)临时RAM块来共享一个NVRAM块时,应用程序之间的同步会变得更加复杂,而且NvM模块也不会处理这个问题。在使用回调作为通知方法的情况下,可能会发生这样的情况:应用程序获得一个通知,尽管该请求尚未由该应用程序发起。所有申请必须遵守以下规则。
3.20.1 写请求(NvM_WriteBlock or NvM_WritePRAMBlock)
应用程序和NVRAM Manager之间的隐式同步在写请求时必须遵守以下规则:
1)应用程序用NvM模块必须写入的数据填充RAM块
2)应用程序发出NvM_WriteBlock或NvM_WritePRAMBlock请求,将控制权转移给NvM模块。
3)从现在开始,应用程序不得修改RAM块,直到发出或通过轮询获得请求的成功或失败。在此期间,可以读取RAM块的内容。
4)应用程序可以使用轮询来获取请求的状态,也可以通过回调函数异步获得通知。
5)在完成NvM模块操作后,RAM块可用于修改。
3.20.2 读请求(NvM_ReadBlock or NvM_ReadPRAMBlock)
在应用程序和NVRAM Manager之间进行隐式同步时,应用程序必须遵守以下规则:
1)应用程序提供了一个RAM块,必须用NvM模块侧的NVRAM数据来填充它。
2)应用程序发出NvM_ReadBlock请求,将控制权转移给NvM模块。
3)从现在开始,在请求成功或失败被通知或通过轮询派生之前,应用程序不能读写RAM块。
4)应用程序可以使用轮询来获取请求的状态,也可以通过回调函数得到通知。
5)在完成NvM模块操作之后,RAM块就可以使用新数据供应用程序使用。
3.20.3 恢复默认请求(NvM_RestoreBlockDefaults and NvM_RestorePRAMBlockDefaults)
在恢复应用程序和NVRAM Manager之间隐式同步的默认请求时,应用程序必须遵守以下规则:
1) 应用程序提供了一个RAM块,它必须用来自NvM模块端的ROM数据填充。
2)应用程序发出NvM_RestoreBlockDefaults或NvM_RestorePRAMBlockDefaults请求,将控制权转移到NvM模块。
3)从现在开始,在请求成功或失败被通知或通过轮询派生之前,应用程序不能读写RAM块。
4) 应用程序可以使用轮询来获取请求的状态,也可以通过回调函数得到通知。
5) 在完成NvM模块操作之后,RAM块就可以与ROM数据一起供应用程序使用。
3.20.4 多块读请求 (NvM_ReadAll)
如果使用EcuM Fixed,这个请求只能由ECU状态管理器触发;如果在系统启动时使用EcuM Flex,则只能由集成代码触发。这个请求用启动所需的数据填充所有配置的永久RAM块。
如果请求失败或请求处理仅部分成功,NVRAMManager将此条件信号给DEM,并向EcuM返回一个错误。DEM和EcuM必须决定采取进一步的措施。这些步骤在DEM和ECU状态管理器的模块中处理。
在应用程序和NVRAM Manager之间进行隐式同步的多块读请求时,应用程序必须遵守以下规则:
ECU状态管理器发出NvM_ReadAll。
-- ECU状态管理器可以使用轮询来获取请求的状态,也可以通过回调函数得到通知。
-- 在NvM_ReadAll过程中,一个单独的块回调(如果配置)将在处理完一个NVRAM块之后被调用。这些回调使RTE能够单独启动每个SW-C。
3.20.5 多块写请求(NvM_WriteAll)
这个请求只能由ECU状态管理器在系统关闭时触发。这个请求将所有修改后的永久RAM块的内容写入NV内存。通过仅在ECU关闭期间调用该请求,ECU状态管理器可以确保在操作结束之前没有SW组件能够修改RAM块中的数据。这些措施在EcuM中处理。
在应用程序和NVRAM管理器之间进行隐式同步的多块写请求时,应用程序必须遵守以下规则:
1. EcuM发出NvM_WriteAll请求,该请求将控制权转移给NvM模块。
2. EcuM可以使用轮询来获取请求的状态,也可以通过回调函数得到通知。
3.20.6 删除操作 (NvM_CancelWriteAll)
这个请求取消了一个挂起的NvM_WriteAll请求。这是一个异步请求,可以调用它来终止一个挂起的NvM_WriteAll请求。
NvM_CancelWriteAll请求只能被EcuM使用。
3.20.7 管理块的修改 Modification of administrative blocks
为了管理目的,管理块是每个配置NVRAM块的一部分。
如果NVRAM块有一个待处理的单块操作,应用程序不允许调用任何修改管理块的操作,如NvM_SetDataIndex, NvM_SetBlockProtection, NvM_SetRamBlockStatus,直到待处理的作业完成。
3.21 NVRAM块的正常和扩展运行时准备
根据两个配置参数NvMDynamicConfiguration和NvMResistantToChangedSw, NVRAM管理器在启动过程中会以不同的方式运行,例如在处理请求 NvM_ReadAll()时。
如果NVRAM NvMDynamicConfiguration设置为FALSE, NVRAM管理器将忽略存储的配置ID,继续正常运行时准备NVRAM块。在这种情况下,RAM块应检查其有效性。如果RAM块内容被检测为无效,则应检查NV块的有效性。一个被检测到有效的NV块将被复制到指定的RAM块中。如果检测到无效的NV块,将加载默认数据。如果NvMDynamicConfiguration设置为TRUE,并且检测到配置ID不匹配,则需要对那些配置了NvMResistantToChangedSw(FALSE)的NVRAM块进行扩展运行准备。在这种情况下,默认数据应该加载独立的有效性分配RAM或NV块。
3.22 应用程序和NVRAM管理器之间的通信和显式同步
与应用程序和NvM模块之间的隐式同步相比,显式同步机制是可选的(即可配置的)。它是通过NvM模块中的RAM镜像实现的。通过NvM模块调用的回调例程,应用程序在两个方向上传输数据。
以下是对这种机制的简短分析:
-- 优点是应用程序可以以更好的方式控制它们的数据。它们负责从NvM模块的RAM镜像中复制一致的数据,因此它们知道时间点。RAM块不会因为并发访问而处于不一致的状态。
-- 缺点是额外的RAM需要与使用这种机制的最大NVRAM块相同的大小,并且每个操作都需要在两个RAM位置之间进行额外的拷贝。
这种机制特别允许不同应用程序共享NVRAM块,如果有一个模块对这些应用程序进行同步,并且从NvM模块的角度来看,它是NVRAM块的所有者。
对于每个NVRAM块,都应该有可能通过参数NvMBlockUseSyncMechanism来配置显式同步机制的使用。
如果没有配置块使用显式的同步机制,NvM模块不能分配RAM镜像。
如果至少有一个块被配置为使用显式同步机制,NvM模块应该只分配一个RAM镜像。这个RAM镜像不能超过配置为使用显式同步机制的最长NVRAM块的大小。
NvM模块应该使用内部镜像作为所有读写NVRAM块的RAM块的操作的缓冲区,这些NVRAM块带有NvMBlockUseSyncMechanism== TRUE。该缓冲区不能用于其他NVRAM块。
NvM模块需要调用NvMWriteRamBlockToNvM例程,以便使用NvMBlockUseSyncMechanism== TRUE将所有NVRAM块的数据从RAM块复制到镜像。这个例程不能用于其他NVRAM块。
NvM模块需要调用NvM的NvMReadRamBlockFromNvM例程,以便用NvMBlockUseSyncMechanism == TRUE将所有NVRAM块的数据从镜像复制到RAM块。这个例程不能用于其他NVRAM块。
在单个块请求过程中,如果例程NvMReadRamBlockFromNvM返回E_NOT_OK,那么NvM模块应该重试例程调用NvMRepeatMirrorOperations次数。之后,单块读作业将块特定的请求结果设置为NVM_REQ_NOT_OK,并向DEM报告NVM_E_REQ_FAILED。
在NvM例程返回E_NOT_OK的情况下,NvM模块应该在下次调用NvM_MainFunction时重试例程调用。
在单个块请求过程中,如果例程NvMWriteRamBlockToNvM返回E_NOT_OK,那么NvM模块将重试例程调用NvMRepeatMirrorOperations次数。之后单块写作业将块特定的请求结果设置为NVM_REQ_NOT_OK,并向DEM报告NVM_E_REQ_FAILED。
在这种情况下,NvMWriteRamBlockToNvM例程返回E_NOT_OK, NvM模块应该在下次调用NvM_MainFunction时重试例程调用。
在一个多块请求(NvM_WriteAll)中,如果例程NvMWriteRamBlockToNvM返回E_NOT_OK,那么NvM模块将重试例程调用NvMRepeatMirrorOperations次数。之后,函数NvM_WriteAll的任务将block特定请求结果设置为NVM_REQ_NOT_OK,并向DEM报告NVM_E_REQ_FAILED。
在一个多块请求(NvM_ReadAll)中,如果例程NvMReadRamBlockFromNvM返回E_NOT_OK,那么NvM模块应该重试例程调用NvMRepeatMirrorOperations次数。之后NvM_ReadAll函数的任务将block特定请求结果设置为NVM_REQ_NOT_OK,并向DEM报告nvm_req_failed。
如果一个块为它配置了显式的同步,那么它一定没有配置永久RAM映像。
3.22.1 写请求(NvM_WriteBlock or NvM_WritePRAMBlock)
在写请求过程中,应用程序和NVRAM Manager之间必须遵循以下规则进行显式同步:
1) 应用程序用NvM模块必须写入的数据填充RAM块。
2) 应用程序发出NvM_WriteBlock或NvM_WritePRAMBlock请求。
3) 应用程序可能会修改内存块,直到例程NvMWriteRamBlockToNvM被NvM模块调用。
4) 如果例程NvMWriteRamBlockToNvM被NvM模块调用,那么应用程序必须提供一个一致的RAM块副本到NvM模块请求的目的地。应用程序可以使用返回值E_NOT_OK来表示数据不一致。NvM模块将接受这个NvMRepeatMirrorOperations次数,然后推迟请求并继续它的下一个请求。
5) 延续仅当数据复制到NvM模块时:
6) 从现在开始,应用程序可以再次读写RAM块。
7) 应用程序可以使用轮询来获取请求的状态,也可以通过回调例程异步获得通知。
注意:如果请求了NvM_WriteBlock或NvM_WritePRAMBlock,但还没有被NvM模块处理,应用程序可能会将多个写请求组合到一个RAM块的不同位置。如果没有调用回调例程NvMWriteRamBlockToNvM,则请求未被处理。
3.22.2 读请求 (NvM_ReadBlock or NvM_ReadPRAMBlock)
在应用程序和NVRAM Manager之间进行显式同步时,应用程序必须遵守以下规则:
1)应用程序提供了一个RAM块,必须用NvM模块侧的NVRAM数据来填充它。
2)应用程序发出NvM_ReadBlock或NvM_ReadPRAMBlock请求。
3)应用程序可能会修改RAM块,直到NvM模块调用NvMReadRamBlockFromNvM例程。
4)如果例程NvMReadRamBlockFromNvM被NvM模块调用,那么应用程序将数据从NvM模块指定的目的地复制到RAM块。应用程序可以使用返回值E_NOT_OK来表示没有复制数据。NvM模块将接受这个NvMRepeatMirrorOperations次数,然后推迟请求并继续它的下一个请求。
5)只有从NvM模块复制数据时才会延续:
6)现在,应用程序在RAM块中查找NV块值。
7)应用程序可以使用轮询来获取请求的状态,也可以通过回调例程得到通知。
注意:如果请求了NvM_ReadBlock或NvM_ReadPRAMBlock,但还没有被NvM模块处理,应用程序可能会将多个读请求组合到一个NV块的不同位置。如果回调例程NvMReadRamBlockFromNvM没有被调用,请求就没有被处理。
注意:NvM_RestoreBlockDefaults和NvM_RestorePRAMBlockDefaults的工作原理与NvM_ReadBlock类似。
3.22.3 多块读请求(NvM_ReadAll)
这个请求只能由EcuM在系统启动时触发。
这个请求用启动所需的数据填充所有配置的永久RAM块。
如果请求失败或请求处理仅部分成功,NVRAMManager将此条件信号给DEM,并向EcuM返回一个错误。DEM和EcuM必须决定采取进一步的措施。这些步骤在DEM和EcuM中处理。
正常的操作:
1) EcuM发出NvM_ReadAll。
2) EcuM可以使用轮询来获取请求的状态,也可以通过回调函数得到通知。
3)在NvM_ReadAll任务中,如果为一个块配置了同步回调(NvM_ReadRamBlockFromNvm),它将被NvM模块调用。在这个回调中,应用程序将从NvM模块给出的目的地复制数据到RAM块。应用程序可以使用返回值E_NOT_OK来表示没有复制数据。NvM模块将接受这个NvMRepeatMirrorOperations次数,然后报告读取操作失败。
4)现在,如果读取操作成功,应用程序将在RAM块中查找NV块值。
5) 在NvM_ReadAll过程中,一个单独的块回调(如果配置)将在处理完一个NVRAM块之后被调用。这些回调使RTE能够单独启动每个SW-C。
3.22.4 多块写请求(NvM_WriteAll)
这个请求只能由EcuM在系统关闭时触发。这个请求将所有修改后的永久RAM块的内容写入NV内存。通过仅在ECU关闭期间调用该请求,EcuM可以确保在操作结束之前没有SW组件能够修改RAM块中的数据。这些措施在EcuM中处理。
正常的操作:
1)ECU状态管理器发出NvM_WriteAll请求,该请求将控制权转移给NvM模块。
2)在NvM_WriteAll作业期间,如果为一个块配置了一个同步回调(NvM_WriteRamBlockToNvM),它将被NvM模块调用。在这个回调中,应用程序必须提供一个一致的副本将RAM块发送到NvM模块请求的目的地。应用程序可以使用返回值E_NOT_OK来表示数据不一致。NvM模块将接受这个NvMRepeatMirrorOperations次数,然后报告写操作失败。
3)现在应用程序可以再次读写RAM块了。
4)ECU状态管理器可以使用轮询来获取请求的状态,也可以通过回调函数得到通知。
3.23 静态块ID检查
注意:NVRAM Manager存储NV块头,包括静态块ID在NV块每次写入NV内存的时候。当读取一个块时,将其静态块ID与请求的块ID进行比较。这允许检测导致读取错误块的硬件故障。
NVRAM Manger应该在每次将块写入NV内存时存储块头的静态块ID字段。
NVRAM Manger应该在每次从NV内存读取区块时检查区块头。
如果静态块ID检查失败,则向DEM报告失败的NVM_E_WRONG_BLOCK_ID。
如果静态块ID检查失败,则启动读取错误恢复。
提示:配置时需要检查,确保所有的Static Block id都是唯一的。
3.24 读重试
如果NVRAM Manger在从NV内存读取操作期间检测到失败,CRC错误,那么在继续读取冗余NV块之前,将进行一次或多次额外的读取尝试,如NVM_MAX_NUM_OF_READ_RETRIES配置的那样。
如果NVRAM Manger在从NV内存读取操作期间检测到失败,CRC错误,那么在继续读取ROM块之前,将进行一次或多次额外的读取尝试,如NVM_MAX_NUM_OF_READ_RETRIES所配置的。
如果NVRAM Manger在从NV内存读取操作中检测到失败,静态块ID检查,然后在继续读取冗余的NV块之前,根据NVM_MAX_NUM_OF_READ_RETRIES配置,进行一次或多次额外的读取尝试。
如果NVRAMManger在从NV内存读取操作中检测到一个失败,一个静态块ID检查,然后在继续读取ROM块之前,根据NVM_MAX_NUM_OF_READ_RETRIES配置,进行一次或多次额外的读取尝试。
3.25 写校验
当一个RAM Block被写入NV内存时,NV块会被立即读回来,并与RAM Block中的原始内容进行比较,前提是该行为被NVM_WRITE_VERIFICATION激活。
RAM Block中的原始内容与回读的块的比较应分步骤进行,以保证读取和比较的字节数不大于配置参数NVM_WRITE_VERIFICATION_DATA_SIZE所指定的字节数。
如果RAM Block中的原始内容与读回来的内容不相同,那么将向DEM报告生产代码错误NVM_E_VERIFY_FAILED。
如果RAM块中的原始内容与回读不相同,则应按照本文档的规定执行写重试。
如果回读操作失败,则不应执行读重试。
如果RAM块中的原始内容与回读不相同,对于初始的写尝试以及所有配置的重试,则NvM应将请求结果设置为NVM_REQ_NOT_OK。
3.26 比较NvM中的NV数据
为了避免在NV内存中进行不必要的写操作,如果特定RAM块的NV数据在运行时没有更新,NvM模块提供了一种基于CRC的比较机制,可以在处理写作业时应用。
NvM模块应该提供一个选项,通过实现基于CRC的比较机制来跳过写入未改变的数据。
注意:一般来说,有一个风险,RAM块的一些改变的内容导致相同的CRC作为初始内容,所以更新可能会丢失,如果使用这个选项。因此,这个选项应该只用于可以容忍这种风险的区块。
对于每个NVRAM块,都应该有可能通过参数NvMBlockUseCRCCompMechanism配置基于CRC比较机制的使用。
NvM模块应该为NVRAM块提供基于CRC的比较功能,且参数NvMCalcRamBlockCrc和NvMBlockUseCrc设置为true。
3.27 NvM和BswM交互
当NvM需要通知BswM一个多块请求状态变化时,它应该使用BswM API BswM_NvM_CurrentJobMode()。
如果NvMBswMMultiBlockJobStatusInformation为true, NvM将不会调用配置的多块回调。
当NvM需要通知BswM单个块请求接受(正在等待中)和结果时,它应该使用BswM API BswM_NvM_CurrentBlockMode()。
如果NvMBswMMultiBlockJobStatusInformation为true,当NvM接受一个多块操作时,NvM应该通过调用BswM_NvM_CurrentJobMode(具有相关服务ID,作为模式,为NVM_REQ_PENDING)来通知BswM接受的多块操作正在等待。
如果NvMBswMMultiBlockJobStatusInformation为true,当一个多块操作结束或被取消时,NvM将通过调用BswM_NvM_CurrentJobMode,将多块操作的结果通知给BswM,该BswM使用相关的服务ID和作为模式的多块操作的结果。
如果NvMBswMBlockStatusInformation为true,当NvM接受单个块操作时,NvM应该通过调用BswM_NvM_CurrentBlockMode(带有相关的block ID和作为模式的NVM_REQ_PENDING)来通知BswM接受的单个块操作正在等待。
如果NvMBswMBlockStatusInformation为true,当单个块操作完成或被取消时,NvM将通过调用BswM_NvM_CurrentBlockMode将单个块操作的结果通知BswM,该BswM调用带有相关块ID的BswM_NvM_CurrentBlockMode,作为模式,表示单个块操作的结果。
如果NvMBswMBlockStatusInformation为true,并且NvM有一个正在进行的多块操作,对于每一个由于多块操作而处理的块,NvM应该在开始处理该待处理的块时通知BswM,通过调用BswM_NvM_CurrentBlockMode与相关的块ID和作为模式的NVM_REQ_PENDING。
如果NvMBswMBlockStatusInformation为true,并且NvM有一个正在进行的多块操作,对于每一个由于多块操作而处理的块,NvM应该通过调用BswM_NvM_CurrentBlockMode来通知BswM该块处理完成的结果,该BswM使用相关的块ID和作为模式的单块操作的结果。
3.28 块锁定情况下的NvM行为
NvM_SetBlockLockStatus API服务只能被BSW组件使用,它没有作为服务发布在SWC-Description中。因此,它将不能通过RTE访问。
如果该API被调用时参数Locked为TRUE, NVM必须保证与BlockId标识的NVRAM块相关的NV内容不会被任何请求修改。在NvM_WriteAll过程中,Block应该被跳过,其他的请求,如NvM_WriteBlock, NvM_WritePRAMBlock, NvM_InvalidateNvBlock, NvM_EraseNvBlock,应该被拒绝。
如果API被调用时参数Locked为TRUE, NVM应该保证在下次启动时,在处理NvM_ReadBlock或NvM_ReadPRAMBlock时,这个NVRAM块应该从NV内存中加载。
如果Locked参数的值为FALSE,则NVM必须保证该NVRAM块按照AUTOSAR的规定正常处理。
使用该服务的设置不能被NvM_SetRamBlockStatus或NvM_SetBlockProtection改变。
3.28.1 用例
通过诊断服务为NVRAM块保存新数据到NV内存。这些数据应在下一次ECU启动时提供给swc (s),即它们既不能被来自swc的请求覆盖,也不能在关机期间被永久RAM块的数据覆盖(NvM_WriteAll)。
3.28.2 使用(DCM)
1)DCM请求NvM_SetBlockLockStatus(<BlockId>, FALSE),以重新启用对该块的写入。(之前执行这个过程可能会锁定它)。
2) DCM请求NvM_WriteBlock(<blockId>, <DataBuffer>)
3)DCM轮询完成写请求(使用NvM_GetErrorStatus())
4) 当成功(NVM_REQ_OK), DCM发出NvM_SetBlockLockStatus(<BlockId>, TRUE)
4.API详解
如下表所示,NVM的API接口主要分为几大类型。
4.1同步请求函数 Synchronous requests
4.1.1NvM_Init
函数原型:
void NvM_Init(
const NvM_ConfigType* ConfigPtr
)
函数参数:
ConfigPtr:指向选定配置集的指针。
函数描述:用来重置所有内部变量的服务。
函数NvM_Init应将所有内部变量,例如队列、请求标志、状态机,重置为其初始值。它应在内部发出“初始化完成”的信号,例如,以启用作业处理和队列管理。
函数NvM_Init不应修改永久RAM块内容或调用显式同步回调,因为这将在NvM_ReadAll上完成。
函数NvM_Init应将NVM_BLOCK_DATASET类型的所有NVRAM块的数据集索引设置为零。
函数NvM_Init不得初始化其他模块(假设底层层已经初始化)。
提示:耗时的NVRAM块初始化和根据块描述符设置应该由NvM_ReadAll请求完成。
4.1.2 NvM_SetBlockProtection
函数原型:
Std_ReturnType NvM_SetBlockProtection(
NvM_BlockIdType BlockId,
boolean ProtectionEnabled
)
函数返回值:
E_OK: The block was enabled/disabled as requested
E_NOT_OK: An error occured.
函数参数:
BlockId:块标识符唯一地标识一个NVRAM块描述符。NVRAM块描述符包含有关单个NVRAM块的所有所需信息。
ProtectionEnabled:TRUE: Write protection shall be enabled
FALSE: Write protection shall be disabled
函数描述:用于设置/重置NV块的写入保护的服务。
功能NvM_SetBlockProtection通过在相应的NVRAM块的管理部分设置写保护属性,为相应的NV块设置/重置写保护。
NvM模块的环境应在调用函数NvM_SetBlockProtection之前已初始化NvM模块。
4.1.3 NvM_GetErrorStatus
函数原型:
Std_ReturnType NvM_GetErrorStatus(
NvM_BlockIdType BlockId,
NvM_RequestResultType* RequestResultPtr
)
函数返回值:
E_OK:已成功读取与块相关的错误/状态信息。
E_NOT_OK:发生错误。
函数参数:
BlockId:块标识符唯一地标识一个NVRAM块描述符。NVRAM块描述符包含有关单个NVRAM块的所有所需信息。
函数描述:提供以下服务来读取与块相关的错误/状态信息。
函数NvM_GetErrorStatus应在NVRAM块的管理部分中读取与块相关的错误/状态信息。NVRAM块的状态/错误信息应由以前或当前的异步请求来设置。
NvM模块的环境应在调用函数NvM_GetErrorStatus之前已初始化NvM模块。
4.1.4 NvM_CancelJobs
函数原型:
Std_ReturnType NvM_CancelJobs(
NvM_BlockIdType BlockId
)
函数返回值:
E_OK:该作业已被成功地从队列中删除。
E_NOT_OK:在队列中找不到该作业。
函数参数:
BlockId:块标识符唯一地标识一个NVRAM块描述符。NVRAM块描述符包含有关单个NVRAM块的所有所需信息。
函数描述:服务取消所有等待NV块的作业。
函数NvM_CancelJobs应取消指定NV块的队列中所有待定的作业。如果被请求,则对已取消的块的结果类型为NVM_REQ_CANCELED。
当前处理的作业将在NvM_CancelJobs调用之后继续。
如果请求被接受,功能NvM_CancelJobs的工作应提前将指定NVRAM块的块特定请求结果设置为NVM_REQ_CANCELED。
提示:目的只是在清理阶段清空队列,以防终止或重新启动分区,以避免稍后结束作业通知。
4.2异步单块请求 Asynchronous single block requests
4.2.1NvM_ReadBlock
函数原型:
Std_ReturnType NvM_ReadBlock(
NvM_BlockIdType BlockId,
void* NvM_DstPtr
)
函数返回值:
E_OK:请求已被接受。
E_NOT_OK:请求未被接受
函数参数:
BlockId:块标识符唯一地标识一个NVRAM块描述符。NVRAM块描述符包含有关单个NVRAM块的所有所需信息。
NvM_DstPtr:指向RAM数据块的指针
函数描述:将NV块的数据复制到其相应的RAM块的服务。
函数NvM_ReadBlock将接管给定的参数,将读请求放入作业队列中并返回。
4.2.2NvM_WriteBlock
函数原型:
Std_ReturnType NvM_WriteBlock(
NvM_BlockIdType BlockId,
const void* NvM_SrcPtr
)
函数返回值:
E_OK:请求已被接受。
E_NOT_OK:请求未被接受
函数参数:
BlockId:块标识符唯一地标识一个NVRAM块描述符。NVRAM块描述符包含有关单个NVRAM块的所有所需信息。
NvM_SrcPtr:指向RAM数据块的指针
函数描述:将RAM块的数据复制到其相应的NV块的服务。
NvM_WriteBlock函数应测试相应RAM块管理部分的NV块的写入保护属性。如果出现故障,应报告NVM_E_WRITE_PROTECTED/(在生产过程中)错误。
4.2.3 NvMEraseNvBlock
函数原型:
Std_ReturnType NvM_EraseNvBlock(
NvM_BlockIdType BlockId
)
函数返回值:
E_OK:请求已被接受。
E_NOT_OK:请求未被接受
函数参数:
BlockId:块标识符唯一地标识一个NVRAM块描述符。NVRAM块描述符包含有关单个NVRAM块的所有所需信息。
函数描述:要擦除NV块的服务。
4.3异步多块请求 Asynchronous multi block requests
4.3.1NvM_ReadAll
函数原型:
void NvM_ReadAll(
void
)
函数描述:启动一个多块读取请求。
多块服务NvM_ReadAll应提供两种不同的功能:
-- 初始化所有NVRAM块的管理数据
-- 将数据复制到永久RAM块,或为相应配置的NVRAM块调用显式同步回调(NvM_ReadRamBlockFromNvm)。
函数NvM_ReadAll将向NvM模块发出请求信号并返回。NVRAM Manager将延迟处理请求的ReadAll直到所有单个块作业队列为空。
4.3.2 NvM_WriteAll
函数原型:
void NvM_ReadAll(
void
)
函数描述:启动一个多块写入请求。
函数NvM_WriteAll的作业应将永久RAM块的内容同步到它们相应的NV块上,或者在关闭时调用显式同步回调(NvM_WriteRamBlockToNvm)。
如果NVRAM block ID 1(包含内存布局的配置ID)被标记为“在NvM_WriteAll期间写入”,则NvM_WriteAll函数的作业将在最后一步(最后一次写操作)写入该block,以防止在写操作过程中发生掉电故障时内存布局不匹配。
函数NvM_WriteAll应向NvM模块发出请求信号并返回。NVRAM管理器应延迟请求的处理,直到所有单个块作业队列为空。
4.3.2NvM_CancelWriteAll
函数原型:
void NvM_CancelWriteAll(
void
)
函数描述:
取消正在运行的NvM_WriteAll请求。
4.4回调函数
4.4.1 NvM_JobEndNotification
函数原型:
void NvM_JobEndNotification(
void
)
函数描述:底层内存抽象使用该函数表示作业结束,没有错误。
回调函数NvM_JobEndNotification被底层内存抽象用来指示作业结束。
注:作业结束时关于内存抽象的通知成功:
- -- Read finished & OK
- -- Write finished & OK
- -- Erase finished & OK
这个例程可以在中断上下文中被调用,这取决于调用函数。所有内存抽象模块都应该配置为使用相同的模式(回调/轮询)。
如果通过NvMPollingMode禁用了轮询模式,NvM模块只能提供回调函数NvM_JobEndNotification。NvM_JobEndNotification功能受常用配置参数的影响。
4.5期望的接口 Expected Interfaces
4.5.1必需的接口
4.5.2可配置的接口
Single block job end notification
函数原型:
Std_ReturnType NvM_SingleBlockCallbackFunction(
uint8 ServiceId,
NvM_RequestResultType JobResult
)
函数返回值:
E_OK:回调函数已成功处理
任何其他:回调函数已处理失败
函数参数:
ServiceId: NVRAM Manager服务的唯一服务ID。
JobResult: 覆盖以前处理的单块作业的请求结果。
函数描述:每个块回调例程通知上层异步单块请求已经完成。
Multi block job end notification
函数原型:
void NvM_MultiBlockCallbackFunction(
uint8 ServiceId,
NvM_RequestResultType JobResult
)
函数参数:
ServiceId: NVRAM Manager服务的唯一服务ID。
JobResult: 覆盖以前处理的单块作业的请求结果。
函数描述:公共回调例程,通知上层一个异步的多块请求已经完成。
Callback function for block initialization
函数原型:
Std_ReturnType InitBlockCallbackFunction(
void
)
函数返回值:
E_OK:回调函数已成功处理
任何其他:回调函数已处理失败
函数描述:每个块回调例程,当需要在RAM中恢复默认数据时,NvM模块将调用该块回调例程,即使配置了ROM块。
注意:在这里,如果没有配置ROM块,应用程序应该将默认数据复制到RAM块,并且/或者它可以设置一些标志来知道默认数据已经恢复。
5.服务接口 Service Interfaces
本章是对NvM模块规范的补充。尽管该规范的其他部分定义了相应的基本软件模块的行为和c接口,但本章以SWC模板的形式指定了相应的AUTOSAR服务。这里描述的接口将在VFB上可见,并用于生成应用程序软件和NvM模块之间的RTE。
5.1 Client-Server-Interfaces
5.1.1 NvM_Admin
5.1.2 NvM_Mirror
5.1.3 NvM_NotifyInitBlock
5.1.4 NvM_NotifyJobFinished
5.1.5 NvM_Service
5.2 Implementation Data Types
5.2.1 NvM_RequestResultType
5.2.2 NvM_BlockIdType
5.2.3 ConstVoidPtr
5.3 Ports
5.3.1 NvM_PAdmin_{Block}
5.3.2 NvM_PM_{Block}
5.3.3 NvM_PNIB_{Block}
5.3.4 NvM_PNJF_{Block}
5.3.5 NvM_PS_{Block}
6.NVM配置
NvMBlockDescriptor: 容器的管理结构,配置组成一个给定的NVRAM块管理类型。它的多样性描述了配置的NVRAM块的数量,每一个块需要配置。NVRAM块描述符压缩在NVRAM块描述符表中。
NvMCommon: 通用配置选项的容器。配置NVM模块的公共属性。
NvmDemEventParameterRefs: DemEventParameter元素的引用容器,当发生相应的错误时,应该使用API Dem_SetEventStatus调用该元素。EventId取自引用的DemEventParameter的DemEventId符号值。标准化错误在此容器中提供,可以通过特定于供应商的错误引用进行扩展。实际项目中基本不配置。
6.1NvMCommon
NvMApiConfigClass: 预处理器开关,启用一些与NVM API配置类相关的API调用。
NvMBswMMultiBlockJobStatusInformation: 该参数指定是否告知BswM多块作业的当前状态。
True:如果ReadAll和WriteAll被启动、完成、取消,调用BswM_NvM_CurrentJobMode
False:完全不通知BswM
NvMCompiledConfigId: NV内存布局的配置ID。这个配置ID应该被发布,例如,一个SW-C应该有可能把它写入NV内存。
NvMCrcNumOfBytes: 如果为至少一个NVRAM块配置了CRC校验,则该参数定义了一个作业处理周期内需要处理的最大字节数。
NvMDatasetSelectionBits: 定义在内存硬件抽象接口内为NVRAM块的特定数据集寻址时应使用的最低有效位数。
0 . .8:用于数据集或冗余块寻址的位数。
0:不配置数据集或冗余NVRAM块,不需要选择位。
1:配置了冗余NVRAM块,但没有配置dataset NVRAM块
NvMDrvModeSwitch: 在执行NvM_ReadAll和NvM_WriteAll时,预处理器开关使内存驱动切换到快速模式。
true: Fast mode enabled.
false: Fast mode disabled.
NvMDynamicConfiguration: 预处理器开关,启用由NvM_ReadAll请求处理的动态配置管理。
true: Dynamic configuration management handling enabled.
false: Dynamic configuration management handling disabled.
该参数会影响所有与ID为1的Block相关的NvM进程,以及所有与抗更改软件相关的NvM进程。如果关闭了Dynamic Configuration, Block 1不能被NvM使用
NvMJobPrioritization: 预处理器开关,以启用作业优先级处理
true: Job prioritization handling enabled.
false: Job prioritization handling disabled.
NvMMultiBlockCallback: 每个异步多块请求终止时调用的公共回调例程的入口地址
NvMPollingMode: 预处理器开关,以启用/禁用NVRAM管理器中的轮询模式,同时禁用/启用底层可使用的回调函数
NvMRepeatMirrorOperations: 定义应用程序在延迟当前作业之前向NvM模块的镜像复制数据或从镜像复制数据的重试次数。
NvMSetRamBlockStatusApi: 预处理器开关,以启用API NvM_SetRamBlockStatus。
NvMSizeImmediateJobQueue: 定义直接优先级作业队列的队列条目数。如果NVM_JOB_PRIORITIZATION被关闭,则该参数应超出作用范围。
NvMSizeStandardJobQueue: 定义标准作业队列的队列条目数。
6.2NvMBlockDescriptor
NvMBlockCrcType: 定义NVRAM块的CRC数据宽度。默认值:NVM_CRC16,即当NVM_BLOCK_USE_CRC==为true时,将使用CRC16
NvMBlockHeaderInclude: 定义头文件,其中NVRAM块的所有者拥有永久RAM数据块、ROM数据块(如果配置)和每个配置回调的回调函数原型的声明。
如果没有配置永久RAM块、ROM块或回调函数,则该配置参数将被忽略。
NvMBlockManagementType: 定义NVRAM块的块管理类型。
NvMBlockUseAutoValidation: 定义在关闭阶段是否自动验证RAM块。
True:使用了自动验证机制。
False:没有使用自动校验机制。
NvMBlockUseCrc: 定义NVRAM块的CRC使用情况,即在RAM和NV内存中保留用于CRC的内存空间。
true:该NVRAM块将使用CRC。
false:该NVRAM块不使用CRC。
NvMBlockUseCRCCompMechanism: 定义在写作业期间是否将RAM块的CRC与最后一个成功读或写作业期间计算的CRC进行比较。
True:使用比较机制,
False:没有使用比较机制
NvMBlockUseSetRamBlockStatus: 定义改块是否使用NvMSetRamBlockStatusApi。
注意:如果NvMSetRamBlockStatusApi被禁用,这个配置参数将被忽略。
true:调用该RAM块的NvMSetRamBlockStatus将设置该RAM块的状态。
false:该RAM块的NvMSetRamBlockStatus调用将被忽略。
NvMBlockUseSyncMechanism: 定义NV块是否使用带有RAM镜像的显式同步机制和用于向NvM模块的RAM镜像传输数据的回调例程。如果使用同步机制,则为True,否则为false。
NvMBlockWriteProt: 定义NV块的初始写保护
true:启用块初始写保护。
false:关闭块初始写保护。
NvMBswMBlockStatusInformation: 此参数指定是否通知BswM指定块的当前状态。
True:在更改时调用BswM_NvM_CurrentBlockMode
Fasle:不通知BswM
NvMCalcRamBlockCrc: 定义永久RAM块或NVRAM块的CRC(重)计算,它们被配置为使用显式同步机制。
true:这个永久RAM块将(重新)计算CRC。
false:不会(重新)为这个永久RAM块计算CRC。
NvMInitBlockCallback: 块特定回调例程的入口地址,如果没有ROM数据可用于NVRAM块的初始化,将调用该回调例程。如果没有配置,则不需要调用特定的回调例程来初始化具有默认数据的NVRAM块。
NvMMaxNumOfReadRetries: 定义读重试的最大次数。
NvMMaxNumOfWriteRetries: 定义一个NVRAM块的写重试的最大次数。无论配置如何,对于请求NvM_WriteAll和NvM_WriteBlock处理的每个块,都会强制执行一致性检查(可能还有写重试)。
NvMNvBlockLength: 以字节为单位定义NV块数据长度。
NvMNvBlockNum: 根据给定的块管理类型定义连续区域内多个NV块的数量。1-255用于配置块管理类型为nvm_block_datasset .1的NVRAM块配置块管理类型为NVM_BLOCK_NATIVE的NVRAM 2配置块管理类型为nvm_block_redundancy的NVRAM
NvMNvramBlockIdentifier: 通过唯一块标识符标识NVRAM块。实现类型:NvM_BlockIdType。
min = 2 max = 2^(16- NVM_DATASET_SELECTION_BITS)-1预留NVRAM块id:
0 ->通过NvM_GetErrorStatus获得多块请求结果
1 ->冗余NVRAM块,保存配置ID(生成工具应该检查该块从类型、CRC和大小角度正确配置)
NvMNvramDeviceId: 定义NVRAM块所在的NVRAM设备ID。
计算公式: value = TargetBlockReference.[Ea/Fee]BlockConfiguration.[Ea/Fee]DeviceIndex
NvMRamBlockDataAddress: 定义RAM块数据的起始地址。如果不配置,则没有永久RAM数据块可用于所选的块管理类型。
NvMReadRamBlockFromNvCallback: 块特定回调例程的入口地址,为了让应用程序将数据从NvM模块的镜像复制到RAM块,需要调用该回调例程。实现类型:Std_ReturnType
E_OK:拷贝成功
E_NOT_OK:复制不成功,将再次调用回调例程
NvMResistantToChangedSw: 定义一个NVRAM块是否应该被处理为抵抗配置更改。如果在配置时没有可用的缺省数据,则应用程序应负责提供缺省初始化数据。在这种情况下,应用程序必须使用NvM_GetErrorStatus()来区分第一次初始化和损坏的数据。
true: NVRAM块抵抗更改的软件。
false: NVRAM块不抵抗更改的软件。
NvMRomBlockDataAddress: 定义ROM块数据的起始地址。如果不配置,则所选的块管理类型没有可用的ROM块。
NvMBlockDescriptor: 根据给定的块管理类型定义连续区域中的多个ROM块的数量。0 ~ 254用于配置块管理类型为NVM_BLOCK_DATASET的NVRAM块。
0-1配置块管理类型为NVM_BLOCK_NATIVE的NVRAM块0-1配置块管理类型为nvm_block_redundancy的NVRAM块。
NvMSelectBlockForFirstInitAll: 定义一个块是否由NvM_FirstInitAll处理。即使没有永久RAM和/或显式同步,也可以配置块被处理。
TRUE: block将被NvM_FirstInitAll处理
FALSE:块不被NvM_FirstInitAll处理
NvMSelectBlockForReadAll: 定义在NvM_ReadAll期间是否处理NVRAM块。此配置参数仅对配置为具有永久RAM块或配置为使用显式同步机制的NVRAM块有影响。
true: NVRAM块将由NvM_ReadAll处理
false: NvM_ReadAll不处理NVRAM块
NvMSelectBlockForWriteAll: 定义在NvM_WriteAll期间是否处理NVRAM块。此配置参数仅对配置为具有永久RAM块或配置为使用显式同步机制的NVRAM块有影响。
true: NVRAM块将由NvM_WriteAll处理
false: NvM_WriteAll不处理NVRAM块
NvMSingleBlockCallback: 块特定回调例程的入口地址,该例程应在每个异步单个块请求终止时调用
NvMStaticBlockIDCheck: 定义是否启用静态块ID检查。
false:禁用静态块ID检查。
true:启用静态块ID检查。
NvMWriteBlockOnce: 定义首次写后的写保护。NVRAM管理器会在第一次写入NV块之后设置写保护位,或者在对NV块进行读取时,如果该块已经写入并且检测到它是有效的和一致的,那么NVRAM管理器就会设置写保护位。
true:定义首次写后的写保护。
false:定义禁用首次写后的写保护。
NvMWriteRamBlockToNvCallback: 块特定回调例程的入口地址,为了让应用程序将数据从RAM块复制到NvM模块的镜像,需要调用该回调例程。实现类型:Std_ReturnType
E_OK:拷贝成功
E_NOT_OK:复制不成功,将再次调用回调例程
NvMWriteVerification: 定义是否启用写验证。
false:关闭写校验。
true:启用写校验功能。