参考:AUTOSAR standard spec_v4.4 ——《AUTOSAR_EXP_NVDataHandling.pdf》
总结
应用方式推荐
如果有并发访问,只能选case3;
如果没有并发访问,建议优先选case2,相对于case3少了一个SWC,且不用回调函数,配置相对简单很多;
case1a不支持
NvM_ReadAll
及NvM_WriteAll
,一般难以满足需求,不建议选用;case1b 相对于case2需要定义更多回调函数,用起来相对麻烦。
case1
NvM 都是以 ServiceSwComponent 的形式配置的。任何想要向 NVRAM 读/写数据的应用程序 SW-C 都需要使用C/S(Client/Service)接口来利用标准NvM 服务。
根据所使用的 NvM 块同步类型,上述用例可进一步分为两种情况:
case 1a
应用SWC访问没有永久RAM块的NVRAM块,且使用隐式同步:
SWC直接与NV Block交互,比如读取时,直接读取物理存储中的NV Block值,并赋值给SWC中定义的变量。
在读写时需要传入变量地址,应用形式:
NvM_ReadBlock(BlockId, NvM_DstPtr);
NvM_WriteBlock(BlockId, NvM_DstPtr);
由于没有固定分配RAM,无法使用NvM_ReadAll 及NvM_WriteAll
注意:图上ROM Block存储的是默认数据(在本篇中均不涉及,看图时可以忽略),NV Block对应FLS Block为实际物理存储。
配置
case 1b
应用SWC访问没有永久RAM块的NVRAM块,使用显式同步:
没有为RAM Block固定分配RAM,但是在NvM中定义了RAM Mirror,SWC通过RAM Mirror与 NV Block交互。
应用方式与case 1a一样,也是SWC中定义变量(RAM)用于读写MvM,在读写时也需要传入变量地址。
不同之处在于case1b是可以使用NvM_ReadAll
及NvM_WriteAll
的,在使用时会调用配置的回调函数,在回调函数中进行与SWC中定义变量的数据交换。比如NvM_ReadAll时,依次次触发所有block的读取回调,在回调中实现将数据复制给SWC中变量。
配置
cfg中配置显式同步回调函数:
case 2
同case1,NvM 也是以 ServiceSwComponent 的形式配置的。
不同的是,应用SWC访问具有永久RAM块的NVRAM块,永久RAM块定义在RTE中。这种方式只能使用隐式同步。
代码应用方式有所不同,由于配置了永久RAM块,因此读写操作不再需要传入地址:
NvM_ReadPRAMBlock(BlockId);
NvM_WritePRAMBlock(BlockId);
此外,如果用户需要提供临时RAM 块,即使系统中已配置永久RAM 块 , 也可使用NvM_ReadBlock/NvM_WriteBlock
API 来提供临时 RAM 块地址。此类 API 优先于 NvM_ReadPRAMBlock/NvM_WritePRAMBlock
。
可以使用NvM_ReadAll
及NvM_WriteAll
,其进行的是RAM Block与NV Block直接的数据交换。比如NvM_ReadAll
,是将NV Block数据读到RAM Block中。
配置
写策略示例
uint8 CheckNvBlockReadySts(NvM_BlockIdType BlockId)
{
uint8 res = E_NOT_OK;
NvM_RequestResultType RequestResultPtr;
if(NvM_GetErrorStatus(BlockId, &RequestResultPtr) == E_OK)
{
if(RequestResultPtr != NVM_REQ_PENDING)
{
res = E_OK;
}
}
return res;
}
void CDD_E2_HzrdSts_CheckWrite(UInt8 data)
{
if(Rte_CDD_E2_HzrdSts_MirrorBlock != data && !CheckNvBlockReadySts(NvMConf_NvMBlockDescriptor_CDD_E2HzrdSts))
{
Rte_CDD_E2_HzrdSts_MirrorBlock = data;
NvM_WritePRAMBlock(NvMConf_NvMBlockDescriptor_CDD_E2HzrdSts);
// 或 Rte_Call_NvMService_AC2_SRBS_HzrdSts_WriteBlock(NULL_PTR);
}
}
本例中
Rte_CDD_E2_HzrdSts_MirrorBlock
为定义在在Rte中的固定ram blockBswM初始化阶段
BswM_INIT_NvMReadAll
,Rte_CDD_E2_HzrdSts_MirrorBlock
被赋值需要写时先复制给
Rte_CDD_E2_HzrdSts_MirrorBlock
,然后调用NvM_WritePRAMBlock
,实现将Rte_CDD_E2_HzrdSts_MirrorBlock
写入NvBlock这里通过NvM_GetErrorStatus判断是否操作完成,以避免在Pending状态再次请求导致出错,也可用jobEnd回调实现
注意:
理论上按照AutoSAR文档,读写操作应调用NvM_ReadPRAMBlock/NvM_WritePRAMBlock
,但Vector工具链实际生成的RTE接口为直接调用NvM_ReadBlock/NvM_WriteBlock
。各家工具链与AutoSAR标准都会存在一定偏差,可以理解。
据官方解释,这里调用RTE接口时传入参数为空即可:
Rte_Call_NvMService_AC2_SRBS_HzrdSts_WriteBlock(NULL_PTR);
关于ServiceSwComponent
根据AutoSAR文档介绍,SWC可通过ServiceSwComponent及NvBlockSwComponent 两种方式与NvM交互。对于上述介绍的case1/2 ,均是采用ServiceSwComponent。
如下case2框图,框图中体现了一个ServiceSwComponentType类型的模块,但在Davinci实际应用中,NvMSWC并不是一个需要额外定义的SWC,而是配置了NvM后,Developer中会对应自动生成的一个SWC,并且改SWC不需要手动配置,是可以忽略的存在,应用时在SWC1/2 中配置NvM Service Need即可。
这里NvMSWC应该就是:
S/C接口的连接状态(这里CDD_E2就是框图中SWC1/2的角色,其与NvM Service连接):
case 3
即上一节提到的采用NvBlockSwComponent 的应用方式。
在这种情况下,RTE 中的NvBlockSwComponent 用于创建RAM 块 , 作为其NvBlockDescriptor 的一部分,可由单个或多个 SW-C 使用NV-Data 接口部分或全部写入/读取。这些 RAM 块可通过 NvM 中的镜像进行访问。
NvM 块描述符已配置为针对此用例的显式同步。每当 NvM 被触发从 NVRAM 中写入或读取数据时,它都会通过回调(Rte_GetMirror/Rte_SetMirror)获取/更新 RAM 块,回调在 RTE 中实现。
如果进行了配置,Rte 还可以使用 NvBlockSwComponent 在内部触发数据写入NvM,这样SWC就不必明确利用C/S(Client/Service)接口进行写入。
注意: 在使用 NvBlockSwComponentType 时,不建议使用隐式同步。
此外,与case2类似,如果用户需要提供临时RAM 块,即使系统中已配置镜像 , 也可使用NvM_ReadBlock/NvM_WriteBlock
API 来提供临时 RAM 块地址,在这种情况下, NvM 会使用 RAM 块参数而不是镜像。此类 API 优先于 NvM_ReadPRAMBlock/NvM_WritePRAMBlock
。
总结与case2差异:
case3最大的优势在于其支持多个SWC对同一个NV_Block的并发访问。
NvBlockSwComponent 可以通过S/R(Send/Receive)向上与应用SWC连接。
下图显示了用于用户访问 NvM 接口的端口配置(SWC1 /SWC2 /SWC3),此处 NvM 被配置为 NvBlockSwComponent。
根据应用软件访问 RAM 块所使用的发送方-接收方通信类型和各自的写入策略,这种情况可进一步分类:
case 3a:使用Rte 显式S/R 通信(即
Rte_Write/Rte_Read/Rte_DRead
)case 3b:使用Rte 隐式S/R 通信(即
Rte_IWrite/Rte_IWriteRef/Rte_IRead
)
配置
这里只简单介绍思路。
创建一个NvBlockSwComponentType类型的SWC。
SWC中,向上实现与应用SWC的S/P接口及连接,向下实现与NvM C/S接口及连接。