YTM32B1HA0 执行A/B SWAP后Fls Ecc测试失败问题
-
问题描述
YTM32B1HA0 EccTst 代码,在执行 A/B SWAP 前(代码运行于原 A 面)可正常运行且测试通过;执行 A/B SWAP 切换至原 B 面后,运行相同的 EccTst 测试代码,出现Fls Ecc测试失败。
-
A/B Swap前Fls Ecc测试成功

-
A/B Swap后Fls Ecc测试失败

复现方法
使用云途提供的EccTst_Demo程序,在工程中增加Nvr Fls操作驱动,并在Demo的main函数中增加A/B SWAP代码执行A/B面切换,然后复位MCU,并重新烧录代码到MCU原B面中,然后再次运行EccTest_Demo 代码,此次运行结果中Fls Ecc测试结果显示为失败。
增加的测试代码如下所示:int main(void) { /* USER CODE BEGIN 1 */ Mcu_Init(&Mcu_Config); Mcu_InitClock(0); #if (MCU_NO_PLL == STD_OFF) while (MCU_PLL_LOCKED != Mcu_GetPllStatus()) { /* Busy wait until the System PLL is locked */ } Mcu_DistributePllClock(); #endif /* USER CODE END 1 */ Board_Init(); /* USER CODE BEGIN 2 */ Fls_ReadSwap(&info); if (info == 0u) { Fls_WriteSwap(); Mcu_Lld_SystemReset(); } EccTst_Start(); EccTst_TestSummerResult = EccTst_GetResult(); EccTst_GetDetailsResult(&EccTst_TestDetailResult); EccTst_DeInit(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }原因分析
经与 IP 确认:当STS[BOOT_INFO] = 1时,通过ECCERR_INJECT_ADDR进行 ECC 错误注入,所配置的地址为存储器物理地址,不受 Flash A/B SWAP 切换逻辑影响。
以地址0x2000400为例:A/B SWAP 切换前,该地址归属 A 面存储区间,向ECCERR_INJECT_ADDR配置0x2000400注入错误时,实际作用地址与 EccTst 测试所用地址一致,测试可正常通过。完成 A/B SWAP 切换后,逻辑地址0x2000400映射为 B 面存储地址;但由于错误注入机制不感知 A/B SWAP,此时仍对0x2000400配置注入时,实际会作用于A 面物理地址 0x2100400。测试代码读取逻辑地址0x2000400(B 面)时,无法命中已注入 ECC 错误的存储单元,不会触发 ECC 异常,最终造成 Fls Ecc 测试失败。
进一步验证该现象,在A/B SWAP之后,对0x2000400地址注入错误,实际读取0x2100400能够触发ECC错误,且EFM ECC_ERR_ADDR寄存器捕获到地址为0x2100400

修复方案
根据上述原因分析,可采用如下方案修复该问题:在执行错误注入测试时,若检测到STS[BOOT_INFO] = 1,需由代码对写入ECCERR_INJECT_ADDR的地址执行手动 A/B SWAP 映射处理。
#if defined (CPU_YTM32B1HA0) #define FLASH_PFLASH0_BASE 0x2000000U #define FLASH_PFLASH1_BASE 0x2100000U #define FLASH_PFLASH_BANK_SIZE 0x100000U #endif ECCTST_FUNC static void EccTst_Lld_Fls_TestEnable(uint32 InjectAddr, uint32 InjectData0, uint32 InkectData1) { volatile uint32 TempData = 0; uint32 TempAddr = 0; /*enable the error injection,the one bit ECC error will happen when read data in test address*/ EccTst_Lld_Fls_EnInjectErr(); /*Inject error data and address*/ EccTst_Lld_Fls_InjectData(InjectData0, InkectData1); /*The inject address does not swap with the A/B SWAP*/ if (((EFM->STS & EFM_STS_BOOT_INFO_MASK) >> EFM_STS_BOOT_INFO_SHIFT) == 1U) { if ((InjectAddr >= FLASH_PFLASH0_BASE) && (InjectAddr < FLASH_PFLASH0_BASE + FLASH_PFLASH_BANK_SIZE)) { TempAddr =InjectAddr + FLASH_PFLASH_BANK_SIZE; } else if ((InjectAddr >= FLASH_PFLASH1_BASE) && (InjectAddr < FLASH_PFLASH1_BASE + FLASH_PFLASH_BANK_SIZE)) { TempAddr =InjectAddr - FLASH_PFLASH_BANK_SIZE; } else { TempAddr = InjectAddr; } } else { TempAddr = InjectAddr; } EccTst_Lld_Fls_InjectAddr(TempAddr); __ASM("ISB"); __ASM("DSB"); #if (PLATFORM_ENABLE_CACHE == STD_ON) /* MR12 Rule 11.4 VIOLATION: In this specific case, need to clear the DCACHE for ECC error injection, * and couldn't adhere to M3CM Rule-11.4. */ SCB_InvalidateDCache_by_Addr((uint32 *)InjectAddr, 64); /*PRQA S 0306*/ #endif /*Trigger fls ECC error*/ /* MR12 Rule 11.4 VIOLATION: In this specific case, need to read the InjectAddr to trigger ECC error, * and couldn't adhere to M3CM Rule-11.4. */ TempData = *((uint32 *)InjectAddr); /*PRQA S 0306*/ /*The purpose of the following code is simply to keep the previous line of code from being optimized by the compiler.*/ TempData += 1U; if (TempData != 1U) { __ASM("nop"); } EccTst_Lld_Fls_DisInjectErr(); }影响版本及临时解决方案
本次问题影响的版本如下:
- YTM32B1HA0_SafLib_2_0_0及之前版本。
在本次问题修复版本正式发布前,可按照前文所述修复方案,修改EccTst_Lld_Fls.c文件中的对应函数,作为临时解决方案。
-
-
Y yt0069 从 MCAL Private Issues 移动了该主题
快速上手云途开发生态
发帖前请查看
帮助改进和优化YT CONFIG TOOL,有机会抽取YTM32B1ME0 EVB哦...