A solution to resolve and exit from the BusFault triggered by am Flash memory double-fault ECC
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);
}
