在线时间1364 小时
UID3338155
注册时间2017-7-26
NXP金币1628
TA的每日心情 | 奋斗 前天 13:25 |
---|
签到天数: 594 天 [LV.9]以坛为家II
金牌会员
- 积分
- 7062
- 最后登录
- 2024-4-27
|
本帖最后由 andeyqi 于 2024-1-24 14:14 编辑
S32K146 作为一颗车规级的芯片,芯片自身是支持功能安全相关的特性,芯片的功能安全等级是ASIL-B等级。从以下功能安全手册的描述可以看到S32K14X 芯片的FLASH/SRAM 是支持硬件ECC校验机制,支持 SEC/DED 算法纠正1bit 错误及多bit 错误检出机制。
ECC 功能如果软件要验证的话,正常情况下是不会触发bit 错误异常的,正常情况这个异常是很难触发的,软件如果要验证这个功能需要怎么触发验证呢,EIM是个错误注入模块可以对数据线及ECC码进行注入错误验证,确保ECC功能的安全可靠,以下是EIM模块的框体,从框图能够看出EIM 模块可以控制对应的bit 读取的数据发生位反转。从如下框图也可以看出来CPU 通过LMEM(Local Memory Controller) 单元访问RAM 资源中间是途经EIM模块,从而EIM 完成对应的路径的注错验证诊断RAM ECC 功能。
EIM 能够注入错误,朱武的错误如何被检出报告,S32K内部还有个ERM模块这个模块能检出SRAM 是否发生了ECC 错误及ECC错误的类型,并具有中断信号输出通知到CORE 的能力,ERM 的介绍如下:
我们使用SDK 的配置接口,使能配置EIM/ERM 通过EIM 注入1bit 错误,然后读取ERM 状态寄存器判断注入错误状态是否成功是否按照预期的检测出ECC错误,对应的测试代码如下:
eim config:
- /**
- * @page misra_violations MISRA-C:2012 violations
- *
- * @section [global]
- * Violates MISRA 2012 Advisory Rule 8.7, External variable could be made static.
- * The external variables will be used in other source files in application code.
- *
- */
- /* Channel configurations */
- const eim_user_channel_config_t eim_InitConfig0[EIM_CHANNEL_COUNT0] =
- {
- /* Channel configuration 0 */
- {
- .channel = 0U,
- .checkBitMask = 0U,
- .dataMask = 1U,
- .enable = true
- }
- };
复制代码 erm config:
- /* Interrupt configurations */
- /* Interrupt configuration 0 */
- const erm_interrupt_config_t erm_Interrupt0 =
- {
- .enableSingleCorrection = true,
- .enableNonCorrectable = true
- };
- /* ERM configurations */
- /* ERM configuration 0 */
- const erm_user_config_t erm_InitConfig0[ERM_CHANNEL_COUNT0] =
- {
- /* Channel configuration 0 */
- {
- .channel = 0U,
- .interruptCfg = &erm_Interrupt0
- }
- };
复制代码 测试代码:
- #include <stdio.h>
- #include <rtthread.h>
- #include <rtdevice.h>
- #include <board.h>
- int eim_correct(void)
- {
- uint32_t test;
- uint32_t addr;
- erm_ecc_event_t retValue = ERM_EVENT_NONE;
- /* Initialize address used to test */
- *(uint32_t *)0x1FFFFFF0U = 0U;
- /* Hardware initialization */
- /* Initial for ERM module */
- ERM_DRV_Init(INST_ERM_CONFIG_1, ERM_CHANNEL_COUNT0, erm_InitConfig0);
- /* Initial for EIM module */
- EIM_DRV_Init(INST_EIM_CONFIG_1, EIM_CHANNEL_COUNT0, eim_InitConfig0);
- /* Read any address on RAM */
- /* Enable read region Ram (0x1FFF8000 - 0x20006FFF) when debug equal Flash */
- test = *(uint32_t *)0x1FFFFFF0U;
- (void)test;
- /* Deinit EIM module */
- EIM_DRV_Deinit(INST_EIM_CONFIG_1);
- /* Check error and get address which EIM injection error */
- retValue = ERM_DRV_GetErrorDetail(INST_ERM_CONFIG_1, 0U, &addr);
- rt_kprintf("erm status %s error addr is 0x%08x\n",\
- retValue == ERM_EVENT_NONE ? "ERM_EVENT_NONE" :\
- (retValue == ERM_EVENT_SINGLE_BIT ? "ERM_EVENT_SINGLE_BIT" :\
- (retValue == ERM_EVENT_NON_CORRECTABLE ? "ERM_EVENT_NON_CORRECTABLE" : "ERM_EVENT_NONE")),\
- addr);
- return 0;
- }
- MSH_CMD_EXPORT_ALIAS(eim_correct, eim1 ,eim correct test);
复制代码
运行上述测试代码,输入eim1 测试命令,ERM 模块已经按照预期的检测到单bit 错误。
在上述代码的基础上追加ERM 中断使能,查看中断函数能否被正常执行,对应代码修改如下:
输入测试命令,中断处理函数内部已经捕获到但比特错误并清除掉该错误标志。如果看的仔细会发现中断的形式EPM宝出来的地址和直接查询状态时对应的地址时不同的,中断的方式我们用来triger 读取的是0x1FFFFFF0U 的测试地址,为什么中断报出来的是0x1fff00f0,这个是因为触发中断的时候回去读取中断向量表,我们的中断向量表是在SRAM里,我们debug 查下0x1fff00f0存储的是不是对应的中断函数。通过下图可知道确实是中断向量,所以EPM 记录的是最后一次触发的一场地址。
验证完了单bit ECC异常,我们修改EIM 的配置往ECC区域注入多bit 错误 看看是否也会跟上面一样触发中断。
修改EIM 配置:
- const eim_user_channel_config_t eim_InitConfig1[EIM_CHANNEL_COUNT1] =
- {
- /* Channel configuration 0 */
- {
- .channel = 0U,
- .checkBitMask = 3U,
- .dataMask = 0U,
- .enable = true
- }
- };
复制代码 添加如下测试指令eim2:
- /*!
- \brief The ERM_ISR funcion invert state Led
- *- Clear event when have notify interrupt
- */
- void erm_doublebit_isr(void)
- {
- uint32_t addr;
- erm_ecc_event_t retValue = ERM_EVENT_NONE;
- /* Deinit EIM module */
- EIM_DRV_Deinit(INST_EIM_CONFIG_1);
- /* Check error and get address which EIM injection error */
- retValue = ERM_DRV_GetErrorDetail(INST_ERM_CONFIG_1, 0U, &addr);
- rt_kprintf("erm isr status %s error addr is 0x%08x\n",\
- retValue == ERM_EVENT_NONE ? "ERM_EVENT_NONE" :\
- (retValue == ERM_EVENT_SINGLE_BIT ? "ERM_EVENT_SINGLE_BIT" :\
- (retValue == ERM_EVENT_NON_CORRECTABLE ? "ERM_EVENT_NON_CORRECTABLE" : "ERM_EVENT_NONE")),\
- addr);
- /* The interrupt notification will be cleared.*/
- ERM_DRV_ClearEvent(INST_ERM_CONFIG_1, 0U, ERM_EVENT_NON_CORRECTABLE);
- }
- int eim_double_bit(void)
- {
- uint32_t test;
- uint32_t addr;
- erm_ecc_event_t retValue = ERM_EVENT_NONE;
- /* Initialize address used to test */
- *(uint32_t *)0x1FFFFFF0U = 0U;
- /* Install IRQ Handlers for ERM and SysTick */
- INT_SYS_InstallHandler(ERM_double_fault_IRQn, erm_doublebit_isr, (isr_t *)0);
- /* Enable ERM IRQ */
- INT_SYS_EnableIRQ(ERM_double_fault_IRQn);
- /* Hardware initialization */
- /* Initial for ERM module */
- ERM_DRV_Init(INST_ERM_CONFIG_1, ERM_CHANNEL_COUNT0, erm_InitConfig0);
- /* Initial for EIM module */
- EIM_DRV_Init(INST_EIM_CONFIG_1, EIM_CHANNEL_COUNT1, eim_InitConfig1);
- /* Read any address on RAM */
- /* Enable read region Ram (0x1FFF8000 - 0x20006FFF) when debug equal Flash */
- test = *(uint32_t *)0x1FFFFFF0U;
- (void)test;
-
- /* Deinit EIM module */
- EIM_DRV_Deinit(INST_EIM_CONFIG_1);
- /* Check error and get address which EIM injection error */
- retValue = ERM_DRV_GetErrorDetail(INST_ERM_CONFIG_1, 0U, &addr);
- rt_kprintf("erm status %s error addr is 0x%08x\n",\
- retValue == ERM_EVENT_NONE ? "ERM_EVENT_NONE" :\
- (retValue == ERM_EVENT_SINGLE_BIT ? "ERM_EVENT_SINGLE_BIT" :\
- (retValue == ERM_EVENT_NON_CORRECTABLE ? "ERM_EVENT_NON_CORRECTABLE" : "ERM_EVENT_NONE")),\
- addr);
- return 0;
- }
- MSH_CMD_EXPORT_ALIAS(eim_double_bit, eim2 ,eim uncorrect test);
复制代码 输入eim2 命令验证:
从上面的log 可知,已经按照预期的触发了不可纠正ECC错误,对应的地址和上面的单bit 一场的地址是相同的原因对应的是中断向量表的地址。
/* 资料分割线 */
|
|