本文根据AUTOSAR4.4(Classic Platform)(https://www.autosar.org/standards/classic-platform/classic-platform-440/)标准中的 :
AUTOSAR_EXP_NVDataHandling.pdf
文章整理。仅为个人理解,不当之处,还请指正,感谢!
目录
3 支持的同步机制(Synchronization Mechanism)
4.4.1 During startup phase (NvM_ReadAll)
4.4.2 During shutdown phase (NvM_WriteAll)
4.5 Resistant to changed software
1 Acronyms and abbreviations
Abbreviation / Acronym: | Description: |
NvM | NVRAM Manager |
NV | Non-volatile |
NVRAM | Non-volatile Random Access Memory |
NVRAM Block | The NVRAM Block is the entire structure, which is needed to administrate and to store a block of NV data. |
NV Block | The NV Block is a Basic Storage Object. It represents the part of a “NVRAM Block” which resides in the NV memory |
RAM Block | The RAM Block is a Basic Storage Object. It represents the part of a “NVRAM Block” which resides in the RAM. |
RAM Mirror | RAM mirrors are NvM internal buffer used for operations that read and write the RAM block of NVRAM blocks with NvMBlockUseSyncMechanism set TRUE. |
ROM Block | The ROM Block is a Basic Storage Object. It represents the part of a “NVRAM Block” which resides in the ROM. |
ROM | Read-Only Memory |
RTE | Runtime Environment |
SW-C | Software Component |
App | Application |
RTE | Run Time Environment |
2 NvM Stack Overview
上图同时展示了整个 NvM Stack 的构成。
如上图所示,AUTOSAR规定,App只能通过NvM(NVRAM Manager)来访问NV Memory(比如FLASH)。
3 支持的同步机制(Synchronization Mechanism)
根据App对NvM Block‘’s RAM的访问方式,数据同步机制可以分为两种:
- 隐式同步(Implicit synchronization)
- 显示同步(Explicit synchronization)
3.1 Implicit synchronization
AUTOSAR规范:在隐式同步机制下,一个NvM Block的 RAM 被映射到一个固定的 SWC,不建议共享RAM。 每当SW-C使用RAM block(temporary/permanent)访问NVRAM时,都必须确保RAM块的数据一致性,直到NvM完成正在进行的操作为止。
说人话:
在隐式同步机制下,RAM block 和 SWC 之间是一一对应的关系,其他SWC不能访问该RAM。SWC要保持数据的一致性是说,从SWC调用NvM接口到NvM内部操作完成前,SWC不能再改变该RAM中的值。但是该RAM可以被read。
补充(个人理解):
temporary RAM:一般指局部变量;
permanent RAM:一般指全局变量。
使用隐式同步机制时分参考步骤:
3.2 Explicit synchronization
AUTOSAR 规范:在显式同步中,NvM会定义一个RAM mirror,用于与App的RAM block交换数据。 App将数据写入RAM block,然后调用NvM Write API(NvM_WriteBlock / NvM_WritePRAMBlock)。 NvM 调用API(NvMWriteRamBlockToNvM)将数据从 RAM Block 拷贝到RAM Mirror,进而写入 NV Block。
显示同步的优点:
- App可以更好地管理自己的RAM block。在App调用NvM_WriteBlock / NvM_WritePRAMBlock 到NvM 调用NvMWriteRamBlockToNvM()这段期间,App仍然可以修改RAM block中的数据。
- 几个SWC可以共享一个NvM Block;
显示同步的缺点:
- 浪费内存:除了RAM block,又多了一个RAM Mirror(additional RAM),且RMA Mirror需要和使用显示同步机制的最大的NvM Block 具有相同的大小;
- 多了一步RAM间的拷贝操作:即多了RAM block 和 RAM mirror之间的拷贝操作;
4. 其他机制
4.1 CRC 机制
NvM模块内部使用CRC生成例程(8/16/32bit)来对 NvM Block 进行相关的检查。当然是否使用CRC是可以配置的。NvM模块内的配置选项为 NvMBlockUseCRCCompMechanism,启用后,如果将要写入的数据(即RAM中的数据)没有改变,则NvM写入请求会被跳过。 基于此,使用CRC的风险在于:如果RAM中的数据内容改变了,但是改变前后计算得出的CRC一致,就会导致数据无法正常写入。因此,此选项应仅用于可以容忍此风险的 NvM Block 。
4.2 错误恢复
4.2.1 对于 Read 操作的错误恢复机制
1. 隐式错误恢复:
NvM 模块对于 Native 和 Redundant 类型的NvM Block 的 Read 操作提供隐式的错误恢复机制,即如果配置了 NvMRomBlockDataAddress 或者NvMInitBlockCallback,则加载对应的默认数据。
2. 显示错误恢复:
对于任何管理类型(NATIVE,Redundant,dataset)的NvM Block,如果其配置了ROM数据,都可以使用显示数据恢复机制来恢复数据,方法是调用 NvM_RestoreBlockDefaults()这个API。当然,对于 Dataset类型的NvM block,在调用API之前必须设置相应的Index(指向ROM Block)。
3. 其他
NvM 模块对于Redundant 类型的NvM Block 的 Read 操作还提供一种错误恢复机制,即将默认数据加载到RAM中。
4.2.2 对于 Write 操作的错误恢复机制
即重新重写写操作,不区分NvM Block的管理类型。
4.3 写验证
写验证即为,将RAM block中的数据写入NV block后,立刻将其回读并与RAM Block的原数据内容做比较,如果比较结果不一致:则再次执行写操作,如果启用DET,则同时回向DEM模块报告错误 NVM_E_VERIFY_FAILED;
如果回读比较失败,则不会再次执行读操作。
4.4 NvMSetRamBlockStatusApi
4.4.1 During startup phase (NvM_ReadAll)
对于某些NVRAM块,可能需要保留相应RAM块的数据内容,以免其在NvM_ReadAll() 期间被覆盖,尤其是在NV块中的数据早于RAM块中的数据的场景下(例如当RAM中的数据尚未写入NV block时发生了热复位)。 在这种情况下,必须将RAM block分配在复位安全(non-initialized)的RAM区域中,并且必须将配置参数CalcRamBlockCrc==TRUE 和 NvMSetRamBlockStatusApi==TRUE。(·CalcRamBlockCrc==TRUE,意味着相应的NV块也具有/具有 CRC配置)
每当RAM中的数据发生变化时都需要调用NvM_SetRamBlockStatus(blockID,TRUE),NvM 模块会重新计算RAM中的CRC并将其存储在一个内部变量(该变量存储在 reset-fase 区域)。当然前提 NVRAM Block 配置了PIM或启用显示同步机制。
在ReadAll()期间,会重新计算RAM的CRC,如果计算得出的CRC和之前存储的CRC一致,则RAM block的内容不会改变。如果不一致,则会将NV Block中的值读到RAM中(即RAM会重写),如果读失败,则会将使用默认数据恢复RAM(即将ROM中的值读到RAM中或者调用InitBlock )
4.4.2 During shutdown phase (NvM_WriteAll)
如果 NvMSetRamBlockStatusApi == FALSE,则 NvM_WriteAll() 会将所有 NVRAM Block 的RAM的内容拷贝到 NV Block中。当然前提是的这些 NVRAM Block 的要求配置: NvMSelectBlockForWriteAll ==TRUE 并且 配置了NvMRamBlockDataAddress 或者使用显示同步机制。
当然,为了提高 NvM_WriteAll() 的速度,我们可以将那些只有 RAM Block的内容发生变化的 NVRAM Block写到 NV Memory中,这就需要配置 NvMSetRamBlockStatusApi==TRUE。这种场景下,每当 RAM中的内容发生变化时,用户就需要调用 NvM_SetRamBlockStatus(BlockID, TRUE),从而告诉 NvM 模块在 NvM_WriteAll()时要处理该 NVRAM Block。
4.5 Resistant to changed software
NvM 模块的 start-up(即NvM_ReadAll() 的处理过程)行为受2个配置参数 NvMDynamicConfiguration 和 NvMResistantToChang 的影响。
在ECU项目中,如果如何处理NVRAM block的配置变更并不重要,则必须配置参数 NvMDynamicConfiguration==FALSE。对于每个NVRAM Block 的配置参数NvMCalcRamBlockCrc:
- NvMCalcRamBlockCrc == FALSE,直接检查NV block 的有效性(validty)。 如果检测结果为:
- NV Block有效,则将NV block中的数据加载到 其对应的RAM Block。
- NV Block无效,则将默认数据加载到RAM中(默认数据通过参数NvMRomBlockDataAddress或参数NvMInitBlockCallback进行配置)。
- NvMCalcRamBlockCrc == TRUE ,NvM首先检查其 RAM block 的有效性(validty)。 如果检测结果为:
- RAM block内容有效,不再检查NV block 的有效性,也不再从NV Block加载数据。
- RAM block内容无效,则继续检查NV block 的有效性。 如果:
- NV Block无效,则将默认数据加载到RAM中(默认数据通过参数NvMRomBlockDataAddress或参数NvMInitBlockCallback进行配置)。
- NV Block有效,则将NV block中的数据加载到 其对应的RAM Block。
如果更改了NVRAM block 的配置,而已经存储在NV memory(比如FLASH)中的 NV block 仍与旧配置相对应,则在NvM_ReadAll()过程中可能会出现严重问题。 例如,当添加新的NVRAM块时,许多其他块的标识符可能会隐式更改,这可能导致从NV存储器读取错误的数据。
在这种情况下,可以配置NvM模块,使其不使用NV memory 中的数据初始化RAM block。即配置参数 NvMDynamicConfiguration == TRUE。 这时候集成商要修改配置参数NvmCompiledConfigID 从而告诉 NvM模块 NVRAM配置已经更改。 NvM模块使用单独的NVRAM block 将 NvmCompiledConfigID 的值存储在NV memory中。 每次执行启动过程(NvM_ReadAll)时,NvM模块都会将存储在NV memory中的值与配置参数NvmCompiledConfigID的值进行比较。 如果两个值不相同,则NV memory 中的值将在下一个shutdown过程(NvM_WriteAll)中被新的配置值所覆盖。
在这种情况下,NvM 在 NvM_ReadAll()过程中会根据配置参数 NvMResistantToChangedSw 来决定如何初始化 NVRAM Blocks:
- NvMResistantToChangedSw == FALSE:不管 RAM Block是否有效,都将忽略NV Block中的值,使用默认数据(ROM或InitBlockCallback)加载RAM Block,则必须配置 ;
- NvMResistantToChangedSw == TRUE:必须将 NV Block中的数据加载到RAM中,即便是在配置变更的情况下。如此,NvM模块会像没有发生配置变更一样处理 NvM_ReadAll()。
因此,一旦将某个 NVRAM Block 配置为 NvMResistantToChangedSw == TRUE,则集成商必须确保在ECU的整个生命周期内不得更改以下配置参数,否则可能将无法成功地从NV memory 中恢复数据:
- NvMResistantToChangedSw (must not be changed from TRUE to FALSE)
- ShortName
- NvMBlockUseCrc
- NvmBlockCrcType (if NvMBlockUseCrc is set to TRUE)
- NvMStaticBlockIDCheck
- NvmNvramDeviceId
- NvmBlockManagementType
- NvmNvBlockLength
- NvmNvBlockBaseNumber
注意:根据所使用的NvM,Fee和Ea模块的具体实现,可能会施加其他约束。 请参考相应的用户手册。
总结一下:
NvMNvM_ReadAll()的过程如下:
- 首先检查NvmCompiledConfigID,看从NV Block中读出的ID和现在配置的ID(RAM中)是否一致:
- 一致,认为没有发生配置变更,正常加载所有NVRAM Block。
- 不一致,认为发生了配置变更,首先检查配置参数 NvMDynamicConfiguration:
- NvMDynamicConfiguration == FALSE,配置已变更,不会读取NV Block中的值到RAM,使用默认数据(ROM或InitBlockCallback)加载RAM Block(具体过程待定,要结合NvM模块的具体实现);
- NvMDynamicConfiguration==TRUE,对于每一个 NVRAM Block,查看参数 NvMResistantToChangedSw:
- NvMResistantToChangedSw == FALSE,不管 RAM Block是否有效,都将忽略NV Block中的值,使用默认数据(ROM或InitBlockCallback)加载RAM Block;
- NvMResistantToChangedSw == TRUE,将 NV Block中的数据加载到RAM中,NvM模块会像没有发生配置变更一样处理 NvM_ReadAll()。