Skip to main content
Associate II
February 10, 2026
Solved

How to jump to application from bootloader in STM32H563

  • February 10, 2026
  • 3 replies
  • 159 views

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
}

 

Hueiyi_2-1770701377800.png

Hueiyi_1-1770701358780.png

 

Below is the console output for reference.

Hueiyi_3-1770701651749.png

 

 

Best answer by gbm

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

 

3 replies

gbm
gbmBest answer
Principal
February 10, 2026

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

 

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
HueiyiAuthor
Associate II
February 10, 2026

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!

jumman_JHINGA
Senior III
February 10, 2026

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();