cancel
Showing results for 
Search instead for 
Did you mean: 

Unable to Jump Between Bootloader and Application using stm32u575

_stm32u575
Associate

I am currently working on a project using the STM32U575ZI-Q microcontroller. I have successfully developed a bootloader for my application. However, I am encountering a critical issue where the program fails to jump from the bootloader to the main application.

Issue Details:

  1. Problem Statement:
  • The bootloader does not transition to the application despite the address being correctly set.
    • Instead of jumping to the application, the program hangs indefinitely.
  1. Steps Taken:
  • Verified the application start address in the bootloader code.
    • Ensured that the vector table is correctly pointed to the application start address.
    • Checked for any potential interrupts that might interfere with the jump process.
  1. Observations:
  • The bootloader code executes correctly up to the point where it should jump to the application.
    • Upon attempting to jump, the program execution halts, and no further operations occur.
  1. Environment:
  • IDE/Toolchain: STM32CubeIDE
    • Microcontroller: STM32U575ZI-Q
    • Bootloader and Application: Custom code developed using STM32CubeIDE.

Request:

I would greatly appreciate your assistance in diagnosing and resolving this issue. Specifically, I am looking for guidance on:

  • Verifying the correct setup for transitioning control from the bootloader to the application.
  • Identifying any potential pitfalls or common issues that might cause the program to hang during this transition.
  • Recommended debugging steps or tools that could help in pinpointing the root cause of this problem.

 

Attachment:

I have inseeted the relevant sections of my bootloader and application code for your reference and analysis.

Thank you for your support.

 

void JumpToApplication(uint32_t address) {

SendStatusMessage("Gonna Jump to Application\r\n");

printAddress(address);

 

// If the function returns false, return to the bootloader loop

if (!WaitForInputAndReturnToBootloader()) {

return;

}

 

// Get application's stack pointer (first word of the application start address)

uint32_t appStack = *(volatile uint32_t*)address;

// Get application's reset handler address (second word of the application start address)

void (*app_reset_handler)(void) = (void(*)(void)) (*(volatile uint32_t*)(address + 4));

 

printAddress((uint32_t)app_reset_handler);

 

// Validate appStack and app_reset_handler addresses

if ((appStack & 0xFF000000) != 0x20000000 || ((uint32_t)app_reset_handler & 1) == 0) {

SendStatusMessage("Invalid stack pointer or reset handler address.\r\n");

return;

}

 

// Set main stack pointer to the value at the start of the application address

__set_MSP(appStack);

 

SendStatusMessage("App Stack\r\n");

printAddress((uint32_t)appStack);

 

SendStatusMessage("App Reset Handler\r\n");

printAddress((uint32_t)app_reset_handler);

 

// Clear the terminal screen

ClearTerminalScreen();

 

// Set Vector Table Offset Register to the application's vector table address

SCB->VTOR = address;

 

// SendStatusMessage("SCB->VTOR\r\n");

// printAddress((uint32_t)SCB->VTOR);

 

// Enable all interrupts

__enable_irq();

 

// Jump to application's reset handler

app_reset_handler(); // Call the app reset handler

 

// If the app_reset_handler returns, there's an issue

SendStatusMessage("Failed to jump to application.\r\n");

}

 

Best regards,

 

Cristopher Bohol 

3 REPLIES 3
haresh05
Associate

I am also facing the same issue. Have you found any solution for this?

Why do you develop a bootloader when it is already there?

OK, when it comes to your own bootloader, here my thoughts what to check:

  1. Assuming your bootloader has enough memory, also stack - OK, you receive new sectors in order to flash into MCU flash memory.
    Are you sure not NOT to flash an overwrite the code with user program when you are still running on bootloader in flash memory? (you cannot overwrite code when you execute code form the the same memory location at the same time)
  2. When jumping without a reset from bootloader to user code: is your ICache (and also DCache) on when running bootloader code?
    Even flashing the ROM was OK - you have to invalidate the caches (updated content now) before you jump to updated code (and data).
  3. When you jump just straight from your bootloader code to your user code (flashed), do you set Vector Table and also SP register?
    If not: the user code will still use the vector table of the bootloader, as well as the stack (SP register) as set for the bootloader (and not your application code).

When it comes to the question like "jumping to bootloaded code as user code" you might consider how the vector table is set (used by your user code) and what the stack (and SP register) is. Also to bear in mind the caches (used during bootloading and jumping to user code) might be invalidated.

Why not using the BOOT pin and the STM bootloader in the chip? Having your own bootloader, maybe for OTA firmware updates (see Arduino bootloader used often on STM boards) and make sure that jumping to user code works like after core reset (at least to set vector table, stack, esp. SP register).

BTW: how do you jump after bootloading to user code? The correct way would be this: read the vector table provided by the application (user) code. Read the second word (first is SP register init, second is Reset_Handler entry). Read this second word in vector table as entry address for your user code (Reset_Handler). Jump to it, via jumping with register value, the address read first from vector table.

Don't forget to think about the stack (which one?) and to set SP register. If you keep going with stack defined for bootloader - you are maybe "out of stack".

And, if you do not relocate the vector table - you will use still the bootloader vector table (but not the one provided with your user code).

BTW: do you know, when using a NUCLEO board - it comes with an ARM mbed bootloader?
When you have a NUCLEO board with onboard STM debugger chip - it provides usually also an USB memory device (an external USB memory device pops up on host PC).

When you drag and draw now a new FW bin file onto this "USB memory device": it should flash this new user application and boot it (if this USB memory device is not disabled via updating the ST-Link SW and selecting the other option).

So, any STM32 have already a bootloader integrated (see BOOT pin options), a NUCLEO board comes with a very convenient way to flash a new FW (see USB memory device) and when you write your own bootloader: check Arduino bootloaders for a STM chip and make sure to set all set properly before you jump to the new user/application code: SP and stack base/size, vector table, caches invalidated...