2026-02-09 9:35 PM - edited 2026-02-09 9:43 PM
I referred to this article: “Bootloader jump to Application HardFault - STM32H563.”
I am also using the STM32H563, and used the following function to jump to the application, but the jump does not succeed. My test program is very simple. After creating an STM32H563 project, I only configured the UART to print messages so I can identify which program is currently running.
/* Bootloader */
typedef void (*pFunction)(void);
void relocate_exe(uint32_t app_addr)
{
uint32_t appStack;
uint32_t appResetHandler;
pFunction appEntry;
appStack = *(volatile uint32_t *)app_addr;
appResetHandler = *(volatile uint32_t *)(app_addr + 4);
appEntry = (pFunction) appResetHandler;
__disable_irq();
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
SCB->VTOR = (uint32_t) app_addr;
__set_MSP(appStack);
//__enable_irq();
appEntry();
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART3_UART_Init();
char msg[128];
sprintf(msg, "Bootloader!!!(%x)\r\n", SCB->VTOR);
HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
relocate_exe(0x8020000); // Jump to application
while (1);
}
/* Application */
int main(void)
{
HAL_Init();
SystemClock_Config();
__enable_irq();
SCB->VTOR = (uint32_t) 0x8020000;
MX_GPIO_Init();
MX_USART3_UART_Init();
char msg[128];
sprintf(msg, "Application!!!(%x)\r\n", SCB->VTOR);
HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
while (1);
}
I also modified the STM32H563ZITX_FLASH.ld linker script accordingly.
/* Bootloader */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 640K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}/* Application */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 640K
FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 128K
}
Below is the console output for reference.
Solved! Go to Solution.
2026-02-09 10:16 PM
The subject comes back every week, so please read few dozens of past posts.
First, you should jump to the app or the bootloader before initializing ANYTHING in main(). There are many good reasons for that.
Second, the code invoking the app will usually fail if compiled with no optimization.
See this file for more details (cone and the comments):
https://github.com/gbm-ii/STM32_Inc/blob/main/cm_boot.h
2026-02-09 10:16 PM
The subject comes back every week, so please read few dozens of past posts.
First, you should jump to the app or the bootloader before initializing ANYTHING in main(). There are many good reasons for that.
Second, the code invoking the app will usually fail if compiled with no optimization.
See this file for more details (cone and the comments):
https://github.com/gbm-ii/STM32_Inc/blob/main/cm_boot.h
2026-02-10 2:44 AM
Hi gbm,
Thank you for your help—it really did solve my problem. Since this code was able to jump successfully on the STM32F103, I couldn’t figure out where the issue was coming from.
There are indeed many articles about this topic, and I should have searched more carefully. I truly appreciate your help. Thanks again!
2026-02-10 2:44 AM - edited 2026-02-10 2:52 AM
There is no need to set VTOR address again in the application code
/* Bootloader */
typedef void (*pFunction)(void);
void relocate_exe(uint32_t app_addr)
{
uint32_t appStack;
uint32_t appResetHandler;
pFunction appEntry;
appStack = *(volatile uint32_t *)app_addr;
appResetHandler = *(volatile uint32_t *)(app_addr + 4);
appEntry = (pFunction) appResetHandler;
__disable_irq();
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
SCB->VTOR = (uint32_t) app_addr;
__set_MSP(appStack);
//__enable_irq();
appEntry();
}before disable_irq .. denationalize every things using HAL_RCC_DeInit();
HAL_DeInit();