1.NVM内容说明
NvM通过Memif接口来实现对底层硬件flash、eeprom两类非易失性存储设备进行访问。

NVM是非易失性存储器,包含flash和eeprom。
NVRAM是非易失性随机访问存储器,实现这个的有d-flash和eeprom。
NVM将存期数据的基本单元以NVRAM Block方式进行存储,同时将NVRAM Block划分为NV Block、RAM Block、ROM Block、Administrative Block四种类型。
NV Block与RAM Block基本上是1:1的关系。
NVRAM Block存储类型在NVM模块中进行统一管理,可以分为Native,Redundant,Dataset三种类型。
Native是普通的存储类型;Redundant是有备份的,占两份NV Block;Dataset是一组数据类型相同的地址可用。
每种类型都需要NV Block、RAM Block、Administrative Block三种类型各一个。只有Redundant需要两个NV Block。ROM Block都是0或n个。
2.NVM函数调用流程
--> SWC 调用NvM WriteBlock写入数据
--> NvM MainFunction 调用 MemIf_Write() 将数据传输到 FEE 或 EA
--> EA MainFunction 调用 EEP Write将数据传输到 EEP
--> EEP MainFunction将数据通过SPI写入EEPROM
``` C
NvM_SwcICopyDataToRam();
VnM_Test = 1
IC_BswM_NvM_WriteAll();
NvM_WriteAll();
WriteAll_ImmidiateBlock();
set Flag
WriteAll_Block_For_Req();
check Flag
NvM_Ea_AppClass_Ram_Addr_NativeBlock_Ex1_512_1_write();
NvM_WriteBlock(); //BlockID = NvMConf_NvMBlockDescriptor_NvM_Ea_AppClass_NativeBlock_Ex1_512_1//17, data = NvM_Ea_AppClass_Ram_Addr_NativeBlock_Ex1_512_1
NvM_Prv_WriteBlock(); //idService_uo = NVM_SERVICE_ID_WRITE_BLOCK // 7
NvM_Prv_Service_Initiate();
NvM_Prv_Service_CheckBlockData();
NvM_Prv_Service_SetBlockData();
NvM_Prv_Write_SetBlockData();
get_RamBlock
NvM_Prv_Block_SetRequest();
set NvM_Prv_stRequests_au16 Flag
NvM_MainFunction(); Core0_BSW_10mws
|
|
NvM_Prv_MainFunctionIntern();
NvM_Prv_MainFunctionArbitrate();
NvM_Prv_GetNextRequest();
| NvM_Prv_GetNextJob();
| NvM_Prv_Multi_Process();
| NvM_Prv_ProcessUserBlocks();
| NvM_Prv_FindNextBlock
| NvM_Prv_Block_IsRequestPending();
| get NvM_Prv_stRequests_au16 Flag
NvM_Prv_MainFunctionJobStart();
NvM_Prv_Job_DoStateMachine()
NvM_Prv_JobWrite_DoMemIf()
NvM_Prv_JobResource_DoStateMachine()
NvM_Prv_MemIf_DoStateMachine()
NvM_Prv_MemIf_InitiateWrite();
MemIf_Write();
Ea_Write(); ///// 由于Ea_Rb_MigrationStaus_u8 = EA_RB_MIGRATION_ERROR,导致无法正确写入
Ea_Rb_Order_st: Ea_Rb_Order_st.OrderType_en = EA_RB_START_WRITE_ORDER_E;
|
|
Ea_MainFunction()
EA_EEP_WRITE()
EEP_WRITE()
Eep_MainFunction()
Eep_lLocalWrite()
Eep_WriteBytesData()
Eep_lSpiRWData()
Spi_SyncTransmit()
```
3.ETAS工具配置
NvMCommon1:

NvMCommon2:

Descriptor1:

Descriptor2:

NvmNvramDeciceID:
![]()
如果是0,则表示底层存储硬件使用的是Flash设备,通过FEE机制来实现数据存储;如果是1,则表示底层存储硬件使用的是Eeprom设备,通过EA抽象层来实现数据存储;
NvmNvBlockNum:
![]()
会按照定量关系决定FEE或者EA中的Block Number,否则的话NVM就无法找到正确的FEE或者EA Block进行写入。
NvmNvBlockLength:
![]()
定义该Block的实际长度。
普通队列和立即队列(当前未使用立即队列):
![]()
这个设置在NvmCommon下,如果设置True为使能立即队列
普通队列就是按照“先进先出”原则处理来自上层应用的NVM写入请求,且该请求作为异步请求,会在NVM_Mainfunction函数周期调用中入队出队。
一旦使能了NVM 队列优先级机制,那么此时NVM一般会存在如下两种立即处理队列:
立即写队列:专门存储立即写相关的队列,并按照Block对应的优先级进行优先处理;
立即读/擦队列:主要用于进行Block的读/擦动作,也是按照BLock对应的优先级进行处理;
一般来讲,配置成立即写的Block优先级会高于立即读/擦优先级 的Block请求;
同步机制(当前使用隐式同步):
![]()
此选项设置为true,开启显示同步。
隐式同步单个写入请求:
S1:应用层写入数据至上述RAM block,以便RAM数据能给被传入至NVM模块进行写入操作;
S2:当应用层更新完数据之后,调用NVM函数接口NvM_WriteBlock 或者NvM_WritePRAMBlock 此时便会将控制权传递至NVM模块,NVM模块将从RAM Block数据拷贝至NV Block中,在这个过程中RAM Block数据不应该被再次写入,否则可能会出现数据不一致性问题;
S3:应用层可以通过此时可以通过Polling 方式去轮询当前NVM写入的状态或者通过Callback的方式进行异步通知;
S4:当NVM完成上述写入操作之后,RAM Block便可以被再次更改。
隐式同步多个写入请求:
通过BswM模块或者EcuM模块调用NvM_WriteAll 进行多个Block写入操作,此时控制权便会移交至NVM模块;
BswM模块或者EcuM模块可以通过Polling方式或者Callback的方式来获取当前NVM Block的写入状态。
NvmRamBlockDataAddress
![]()
对于NVM Block中的RAM Block,可分配成Temporary RAM Block 或者Permanent RAM Block,前者则是使用应用层的Buffer,后者则是使用NvmRamBlockDataAddress对应的地址变量;
若使用Temporary RAM Block,NvmRamBlockDataAddress 可以不进行任何配置,调用NVM_WriteBlock传入的数据地址为应用层全局变量地址;
若使用Permanent RAM Block,那么应用层调用NVM_WriteBlock传入的数据地址可以为空,NVM内部将自动使用NvmRamBlockDataAddress 配置的地址,也可以直接传入NvmRamBlockDataAddress 配置的地址;
NvmRomBlockDataAddress
![]()
对于参数NvmRomBlockDataAddress的参数配置不是必须的,其具体数量则根据Block配置类型而有所差异,
该参数一般用于如果当NVM读取某BLock数据出现错误时,一般是CRC错误,那么便会自动赋值默认值,即从NvmRomBlockDataAddress的地址拷贝数据至RAM Block,以防止意外情况发生。
NvM_InitBlockCallback
![]()
此参数的作用类似,就是发生block数据破坏,如CRC不正确,那么就会触发该初始化函数回调进行处理。
注意点:
虽然参数NvM_InitBlockCallback 与NvmRomBlockDataAddress 功能作用基本相同,但是也有其各自的适用场景,对于简单赋值的操作可直接采用NvmRomBlockDataAddress 即可,对于其他复杂操作,那么就需要适用NvM_InitBlockCallback回调函数中完成;
两个参数任意选择一个即可, 无需两个同时配置;
CRC比较机制
![]()
NVM模块可以通过使能参数NvMBlockUseCRCCompMechanism来实现针对相同数据的忽视写入,减少不必要的Flash资源消耗;
若参数NvMBlockUseCRCCompMechanism == TRUE, 那么就会通过计算两次数据的CRC是否相等,如果相等则忽视最新一次的写入,如果不相等则正常处理;
若参数NvMBlockUseCRCCompMechanism == FALSE, 那么无论数据是否发生变化,NVM均会依次处理所有的写入请求;
注意点: 由于采用的CRC比较,CRC可选为8/16/32, 可能会存在即使是不同数据可能CRC还是相同的情况,因此也需要考虑这种机制造成数据丢失的可能性。
Write Protection机制
![]()
![]()
NVM Block的Write Protection功能由参数NvMBlockWriteProt与NvMWriteBlockOnce共同来决定。
若参数NvMWriteBlockOnce == FALSE, 那么应用层可通过调用函数接口NvM_SetBlockProtection来动态实现Block的保护;
若参数NvMWriteBlockOnce == TRUE且不关心 NvMBlockWriteProt的值, 那么应用层调用函数接口NvM_SetBlockProtection来动态保护是不被允许的;
若参数 NvMBlockWriteProt == TRUE, 则该Block默认开启了写保护,不允许被写入,可通过调用函数接口NvM_SetBlockProtection来关闭保护;
对于参数NvMWriteBlockOnce == TRUE的Block仅允许被写入一次,一般用于非常重要且仅被允许写一次的Block;
Write Verification机制
![]()
写验证主要用于实现在写的过程中将写入的数据立即读取上来检查是否跟当前RAM Block数据一致,如果不一致,则会自动上报故障 NVM_E_VERIFY_FAILED至 DEM模块。
一般默认不开启,写进去然后重读验证机制需要消耗更多的时间,除非针对特别重要的Block才会采用该机制;
Block读写Retry机制
写重试
NVM模块通过设置参数NvMMaxNumOfWriteRetries来决定当调用NVM_WriteAll或者NVM_WriteBlock接口返回结果失败可以重试的次数,以便增加系统写入成功的准确性,对于非常重要的Block可以使能。
读重试
NVM模块通过设置参数NvMMaxNumOfReadRetries 来决定调用NVM_ReadBlock或者NVM_ReadBlock接口返回结果失败可以重读的次数,以确保系统读取的稳定性,对于非常重要的Block可以使能。
静态Block ID检查
NVM模块为了防止在读取过程中出现硬件原因导致读取数据失败,因此可以使能在每个NV Block的Header中添加Static Block ID
检查,具体检查过程如下:
S1:写入Block时,会将当前写入的Block ID一并添加在NV Block的Header一并写入到存储设备;
S2:每次读取该Block时,都会去校验下从NV Memory中读取到的Block ID是否与当前请求的Block ID一致,如果一致则正常读取,如果不一致,那么就会想DEM模块上报NVM_E_WRONG_BLOCK_ID故障,在此情况下还可尝试采用上述的读重试机制进行恢复;
注意点:在进行Block配置过程中务必确保每个Block对应的Block ID是唯一的。
Block回调函数配置
NvmSingleBlockCallback
![]()
对于参数NvmSingleBlockCallback 一般用来当某个Block针对物理存储设备操作完成(包括读/写/擦)之后进行回调通知到上层的函数,以便应用层能给做后置处理。
NvMMultiBlockCallback
![]()
同理,对于Multi-Block的相关操作如果需要知道其是否完成,可通过设置Callback函数通知应用层做后置处理,如NVM_WriteAll, NVM_ReadAll等,该参数位于NvMCommon Container下面:
错误恢复机制
关于错误恢复机制在上述内容的讲解过程中已有提及,因此在这里做个系统性总结:
如果NVRAM Block的管理类型为NATIVE或者REDUNDANT,发生CRC错误时便会主动通过NvMRomBlockDataAddress或者NvMInitBlockCallback来赋值其默认值;
对于所有类型的block,均可手动调用NvM_RestoreBlockDefaults进行赋默认值,如果NVRAM Block的管理类型为DATASET,则需要手动提前设置对应的Data Index,其他没有差别;
如果NVRAM Block的管理类型为REDUNDANT,每次写入均会写入两份,如果读取的过程中发现第一份数据错误,就会自动读取第二份,如果第二份还是错误,才会采用上述赋值默认值方式;
上述写重试或者读重试也是一种通用的错误恢复方式,不关心具体的NVRAM Block的管理类型。
NDANT,发生CRC错误时便会主动通过NvMRomBlockDataAddress或者NvMInitBlockCallback来赋值其默认值;
对于所有类型的block,均可手动调用NvM_RestoreBlockDefaults进行赋默认值,如果NVRAM Block的管理类型为DATASET,则需要手动提前设置对应的Data Index,其他没有差别;
如果NVRAM Block的管理类型为REDUNDANT,每次写入均会写入两份,如果读取的过程中发现第一份数据错误,就会自动读取第二份,如果第二份还是错误,才会采用上述赋值默认值方式;
上述写重试或者读重试也是一种通用的错误恢复方式,不关心具体的NVRAM Block的管理类型。
4.NVM状态码
| 值 | 宏 | 出现条件 | 是否导致 ReadAll NOT_OK |
|---|---|---|---|
0 | NVM_REQ_OK | 读取/写入成功 ✅ | 否 |
1 | NVM_REQ_NOT_OK | 操作失败(硬件/校验错) | — |
2 | NVM_REQ_PENDING | 操作进行中 | — |
3 | NVM_REQ_INTEGRITY_FAILED | 数据完整性校验失败 | 是 |
4 | NVM_REQ_BLOCK_SKIPPED | 块被跳过(未使能 ReadAll) | 否(在允许列表中) |
5 | NVM_REQ_NV_INVALIDATED | NVM 数据被标记无效 | 否(在允许列表中) |
6 | NVM_REQ_CANCELED | 操作被取消 | 否(在允许列表中) |
8 | NVM_REQ_RESTORED_DEFAULTS | 数据无效→隐式恢复默认值 | 是(不在允许列表中) |



5879

被折叠的 条评论
为什么被折叠?



