2025-09-18 5:23 AM
Hi,
Please help me sort this out.
I am trying to port a custom bootloader originally written for the SAMD21 Arm chip to the STM32U385VGT6. We are upgrading our current product with an STM32 Chip. I am having problems with switching from the bootloader to the application binary. My bootloader is loaded at address 0x08000000. The application binary is compiled to run from 0x08010000. I edited the linker script files to locate the binaries properly and tested opening the binary file with a hex editor. All seems situated correctly. Here is my function to jump to the application. APP_CODE_START is set to 0x08010000. I get "jumping to application" in my debug terminal. But the application code is not running.
Solved! Go to Solution.
2025-09-22 2:10 AM
<pre><code>
Thanks LCE and TDK,
I got the code working with the code snippet. Now the bootloader jumps to the application, and the application runs.
// Function pointer to the application's Reset Handler
typedef void (*pFunction)(void);
#define APP_CODE_START 0x08010000U
void jumpToApplication()
{
// 1. De-initialize (optional: if HAL was used before)
// Not needed since we only use CMSIS here
// 2. Get the main stack pointer (MSP) value of the application
uint32_t appStack = *((__IO uint32_t*)APP_CODE_START);
// 3. Get the reset handler address of the application
uint32_t appEntry = *(__IO uint32_t*)(APP_CODE_START + 4U);
pFunction jumpToApp = (pFunction)appEntry;
// 4. Reconfigure vector table offset register (VTOR)
SCB->VTOR = APP_CODE_START;
// 5. Set the MSP to the application's stack pointer
__set_MSP(appStack);
// 6. Jump to the application
jumpToApp();
// If something goes wrong, loop here
while (1) {}
}
</code></pre>
2025-09-18 5:33 AM
Do you ever re-enable interrupts?
You should disable interrupts individually so they do not immediately fire after the jump.
2025-09-18 8:02 AM
What TDK said.
And: __disable_irq(); does not actually disable any interrupts, it just prevents the MCU from entering any ISRs.
So better clear the Interrupt Enable and Pending registers. In H7 that's several NVIC->ICER[n] and NVIC->ICPR[n] .
2025-09-22 2:10 AM
<pre><code>
Thanks LCE and TDK,
I got the code working with the code snippet. Now the bootloader jumps to the application, and the application runs.
// Function pointer to the application's Reset Handler
typedef void (*pFunction)(void);
#define APP_CODE_START 0x08010000U
void jumpToApplication()
{
// 1. De-initialize (optional: if HAL was used before)
// Not needed since we only use CMSIS here
// 2. Get the main stack pointer (MSP) value of the application
uint32_t appStack = *((__IO uint32_t*)APP_CODE_START);
// 3. Get the reset handler address of the application
uint32_t appEntry = *(__IO uint32_t*)(APP_CODE_START + 4U);
pFunction jumpToApp = (pFunction)appEntry;
// 4. Reconfigure vector table offset register (VTOR)
SCB->VTOR = APP_CODE_START;
// 5. Set the MSP to the application's stack pointer
__set_MSP(appStack);
// 6. Jump to the application
jumpToApp();
// If something goes wrong, loop here
while (1) {}
}
</code></pre>
2025-09-30 11:52 AM
Once again, I encountered a situation where I found the SySTick_Handler interrupt is not firing when I relocate my application to 0x08010000 in my STM32U385VGT6 chip. After debugging, I found that the timer is running and the interrupt is not firing. I have a delay function that uses the uwTick variable to count the delays. It is not incremented. Once the delay is called, the code gets stuck there. The same code runs when located at 0x08000000 by changing the linker script. I need help to get the SysTick interrupt fired after jumping from the bootloader to the application image.
Here is my jump to the Application code.
<pre><code>
// Application base address
#define APP_CODE_START 0x08010000U
void jumpToApplication()
{
// 2. Get the main stack pointer (MSP) value of the application
uint32_t appStack = *((__IO uint32_t*)APP_CODE_START);
// 3. Get the reset handler address of the application
uint32_t appEntry = *(__IO uint32_t*)(APP_CODE_START + 4U);
pFunction jumpToApp = (pFunction)appEntry;
// 4. Reconfigure vector table offset register (VTOR)
SCB->VTOR = APP_CODE_START;
// 5. Set the MSP to the application's stack pointer
__set_MSP(appStack);
// 6. Jump to the application
jumpToApp();
// If something goes wrong, loop here
while (1) {}
}
Here is my application code located at 0x08010000
#define LED_PIN 15
static void gpio_init(void)
{
// Enable GPIOA clock (bit in AHB2ENR1)
RCC->AHB2ENR1 |= RCC_AHB2ENR1_GPIOAEN;
// Set PA15 as general-purpose output (MODER bits 30:31 = 01)
GPIOA->MODER &= ~(3U << (LED_PIN * 2)); // clear
GPIOA->MODER |= (1U << (LED_PIN * 2)); // set output
// Push-pull (default), no pull-up/down
GPIOA->OTYPER &= ~(1U << LED_PIN);
GPIOA->PUPDR &= ~(3U << (LED_PIN * 2));
// Set medium speed
GPIOA->OSPEEDR |= (1U << (LED_PIN * 2));
}
//SySTick-based delay function.
void Delay(uint32_t delay_ms)
{
uint32_t tickstart = uwTick;
while ((uwTick - tickstart) < delay_ms)
{
// busy wait
}
}
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
/* USER CODE BEGIN 2 */
gpio_init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
// Toggle PA15
GPIOA->ODR ^= (1U << LED_PIN);
// delay(500000);
Delay(2000);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
</pre></code>
2025-10-06 2:08 PM
Probably one of these two things: