2022-09-21 08:23 PM
I have spent a bit of time looking for a solution on how-to deal with BusFault caused by a flash-read ECC event. This is what I would like to share with others in the absence of finding an online solution myself.
void fv_flash_eec_test(void)
{
volatile uint8_t u8_i;
volatile uint32_t u32_addr, u32a_rd[8], u32a_wr[8];
// enable BusFault interrupt to prevent escalation to a HardFault
NVIC_SetPriority(BusFault_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
NVIC_EnableIRQ(BusFault_IRQn);
// enable interrupt
LL_HANDLER_EnableFault(LL_HANDLER_FAULT_BUS);
u32_addr = ADDR_FLASH_SECTOR_4_BANK1;
fu8_flash_erase_sector(FLASH_SECTOR_4, 1);
// no fault triggered
for (u8_i = 0; u8_i < 8; u8_i++)
{
u32a_rd[u8_i] = *(volatile uint32_t *) (u32_addr + (sizeof(uint32_t) * u8_i));
}
memset(&u32a_wr[0], 0x23, sizeof(uint32_t) * 8);
HAL_FLASHEx_Unlock_Bank1();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, u32_addr, (uint32_t) &u32a_wr[0]);
HAL_FLASHEx_Lock_Bank1();
// no fault triggered
for (u8_i = 0; u8_i < 8; u8_i++)
{
u32a_rd[u8_i] = *(volatile uint32_t *) (u32_addr + (sizeof(uint32_t) * u8_i));
}
// corrupt a 32bit segment
u32a_wr[3] = 0xD4;
HAL_FLASHEx_Unlock_Bank1();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, u32_addr, (uint32_t) &u32a_wr[0]);
HAL_FLASHEx_Lock_Bank1();
// this will trigger a BusFault
for (u8_i = 0; u8_i < 8; u8_i++)
{
u32a_rd[u8_i] = *(volatile uint32_t *) (u32_addr + (sizeof(uint32_t) * u8_i));
}
while (1) {}
}
/**
* @brief This function handles Pre-fetch fault, memory access fault.
*/
void BusFault_Handler(void)
{
// check for a double ecc fault
if (FLASH->SR1 & FLASH_SR_DBECCERR)
{
// clear flag
FLASH->CCR1 |= FLASH_CCR_CLR_DBECCERR;
// flash programming is done in block of 256-bits (8 x uint32)
uint32_t u32_addr = SCB->BFAR;
uint32_t u32a_wr[8] = {0};
// place on a 256-bit boundary
u32_addr = (u32_addr >> 5) << 5;
// overwrite all data to zero - this will remove the ecc fault and clear the interrupt
HAL_FLASHEx_Unlock_Bank1();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, u32_addr, (uint32_t) &u32a_wr[0]);
HAL_FLASHEx_Lock_Bank1();
}
// clear any pending interrupts
NVIC_ClearPendingIRQ(BusFault_IRQn);
}
2022-09-22 02:38 PM
Overwriting FLASH in a fault handler sounds dodgy/dangerous to me. And can you really write into flash that has already been written to without erasing it first? Some flash you can change "1" bits to "0" bits, but I didn't think flash with built-in ECC allowed that. You don't say which CPU you are targeting, so we can't verify that. It doesn't look like a G4xx series, as that has ECC on 8 byte blocks and a double ECC failure asserts NMI not a bus fault.
And it looks like you are presuming the error is only triggered on FLASH used as data. What happens if you get a (perhaps momentary) ECC error from program memory? Boom - there goes your code. Not to mention what happens if the fault is somehow triggered during code that is writing to flash (is this a dual-bank device with "read-while-write" capability?).