Need for invalidating cache when executing from flash that has been erased and written to
Hi!
I am writing a bootloader for an STM32H7S3L8, that received the application binary over UART and places it into flash, specifically on address 0x08008000, and I am getting hard faults when jumping to the address.
If I "install" the application AND bootloader through STM32CubeIDE with SWD, I can successfully jump from the bootloader to the application at runtime. Even if I copy all the application bytes from flash to a RAM section, I can successfully jump to the application and execute it there (from RAM).
But as soon as I am trying to execute from flash that during that runtime session has been erased and then written to, I get hard faults. I even tried just copying the application bytes to ram, erase the flash and copy the application bytes back to the same memory location, and execution from there doesn't work.
From googling around, I suspect that the D and/or I cache might be the problem. I can disable I cache, but I can't disable D cache, then I'm not able to write and read from flash properly (i.e. I don't even reach the line where I am trying to jump to the application).
I have also tried various combinations of invalidating D cache (using SCB_CleanInvalidateDCache_by_Addr/SCB_InvalidateDCache_by_Addr) after erasing and writing, but to no avail.
So to put it simply, how do I robustly execute from flash that I have erased and then written to? What do you need to do/set up before you try to execute from flash memory that you have once erased and written to?
Code is something along the lines of this
typedef void (*pFunction)(void);
#define FLASH_APP_START_ADDRESS ((uint32_t)0x8008000U)
void JumpToApp(void)
{
const uint32_t jump_address = *(__IO uint32_t*) (FLASH_APP_START_ADDRESS + 4U);
const pFunction jump_to_application = (pFunction) jump_address;
SCB->VTOR = FLASH_APP_START_ADDRESS;
uint32_t sp_addr = *(__IO uint32_t*)FLASH_APP_START_ADDRESS;
__set_MSP(sp_addr);
__enable_irq();
jump_to_application();
}
int main()
{
SCB_EnableDCache();
EraseFlash();
uint8_t* application_data = (uint8_t*)malloc(...);
ReceiveApplication(application_data);
// 'application_data' now contains application bytes
const flash_status status = FlashWriteBytes(FLASH_APP_START_ADDRESS, application_data, application_size);
JumpToApp();
}
