Firmware Self-Upgrade from RAM sometimes fails with hard fault
Hi!
I want to update the firmware of my STM32H743 device over I2C. The way I would like to do this is:
- Transfer the new firmware (~200 KB) over I2C and store it in RAM (all in user code)
- Execute a function which is executed from RAM (ITCM to be specific)
- This function clears and reprograms flash, then issues a system reset to load the new firmware
The function looks like this:
__attribute__ ((section(".itcm"))) void UpdateFirmware(uint8_t* buffer, int size)
{
__disable_irq();
HAL_FLASH_Unlock_ITCM();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGSERR);
for (int i = 0; i < size; i += FLASH_SECTOR_SIZE)
{
FLASH_Erase_Sector_ITCM(FLASH_SECTOR_0 + i, FLASH_BANK_1, VOLTAGE_RANGE_3);
}
for (int i = 0; i < size; i += FLASH_PROGRAM_BYTE_SIZE)
{
HAL_FLASH_Program_ITCM(FLASH_TYPEPROGRAM_FLASHWORD, FLASH_ADDRESS + i, (uint32_t)(buffer + i));
}
HAL_FLASH_Lock_ITCM();
SystemReset_ITCM();
}The functions with the '_ITCM' suffix are essentially copies of the regular HAL functions that have the '__attribute__ ((section(".itcm")))' applied to them. The '.itcm' section is defined in my linker file, and is copied to ITCM at startup. The idea is that the whole 'UpdateFirmware' function can run entirely from RAM after the flash is erased.
I know that my code works in principle, because often it does work absolutely fine.
However, sometimes, the MCU seems to stop after the Erase step and goes into a Hard Fault. It is quite hard to debug at this point, as the flash is already empty at this point. This issue may be related to communication on the I2C interface, though I am not 100% sure at this point.
I have a theory why this happens. I think it has to do with the fact that the NVIC table is gone after the flash is erased, and for some reason the MCU tries to execute a handler, and goes into a hard fault as the handler is not there anymore.
However, as you can see, I use '__disable_irq();' at the very beginning of the function. Is this not enough to prevent that from happening? Am I missing something?
Btw. I know that there might be better ways to update the firmware. I have considered them and unfortunately the way I've described seems to be the only option I have.
Any help would be much appreciated.
