Skip to main content
Associate
July 28, 2025
Solved

STM32H743ZIT6 - Jump to bootloader from application not working for all bootloader versions

  • July 28, 2025
  • 5 replies
  • 553 views

We have been using some code to allow jumping into bootloader from the application that has been working well for many years, but has since failed on all our newest batches of PCBs. All PCBs have the same STM32H743ZIT6 processor, all revision V. The only difference is that the jump is working on processors with bootloader version 0x90, but not on boards with version 0x91. 

The code for the jump into bootloader is mostly taken from this post.

#define USB

void Bootloader_Jump(void)
{
 uint32_t i=0;
 void (*SysMemBootJump)(void);
 /* Set the address of the entry point to bootloader */
 volatile uint32_t BootAddr = 0x1FF09800;

 #ifdef USB
 __HAL_RCC_USB_OTG_FS_FORCE_RESET();
 HAL_Delay(1000);
 __HAL_RCC_USB_OTG_FS_RELEASE_RESET();
 #endif

 /* Disable all interrupts */
 __disable_irq();

 HAL_DeInit();

 /* Set the clock to the default state */
 HAL_RCC_DeInit();

 /* Disable Systick timer */
 SysTick->CTRL = 0;
 SysTick->LOAD = 0;
 SysTick->VAL = 0;


 /* Clear Interrupt Enable Register & Interrupt Pending Register */
 for (i=0;i<5;i++)
 {
 NVIC->ICER[i]=0xFFFFFFFF;
 NVIC->ICPR[i]=0xFFFFFFFF;
 }


 /* Re-enable all interrupts */
 __enable_irq();

 /* Set up the jump to booloader address + 4 */
 SysMemBootJump = (void (*)(void)) (*((uint32_t *) ((BootAddr + 4))));

 /* Set the main stack pointer to the bootloader stack */
 __set_MSP(*(uint32_t *)BootAddr);

 /* Call the function to jump to bootloader location */
 SysMemBootJump();

 /* Jump is done successfully */
 while (1)
 {
 /* Code should never reach this loop */
 }
}

The bootloader process is done via USART1. It fails at the Extended Erase Memory command, where instead of taking the time to erase memory then ACK, it resets.

Simon_L_1-1753738781554.png

Any idea what could cause this and how it should be fixed?

 

 

Best answer by Simon_L

I have found a slightly different way to approach the jump which works on my setup. The approach is detailed by m4l490n in the replies to this post.
The idea is to define a section of memory in RAM for a flag so the jump to bootloader can be detected and processed before anything else is initialized in the main function.

Here is the code :

In STM32H743ZITX_FLASH.ld, right after .bss section :

 /* Section defined for flag for jump into booloader */
 .uninit_data (NOLOAD) :
 {
 . = ALIGN(4);
 *(.uninit_data)
 . = ALIGN(4);
 } >DTCMRAM

 

In file where the request to jump into bootloader is received (in my case, main.c) :

#define JUMP_TO_BOOTLOADER 0x01234567	// Indicates request to jump to bootloader
uint32_t boot_reason __attribute__((section(".uninit_data"))); // Variable defined in uninitialized section of RAM
															 // Can be accessed before anything else is init
															 // See STM32H743ZITX_FLAS.ld

 

Where request to jump into bootloader is received and processed :

boot_reason = JUMP_TO_BOOTLOADER; // Indicate request to jump into bootlaoder
NVIC_SystemReset();

 

First lines of main function :

int main(void)
{
 // Checks software request to jump into bootloader
 // This needs to be the first thing in main()
 if (boot_reason == JUMP_TO_BOOTLOADER)
 {
	boot_reason = 0;
	Bootloader_Jump();
 }

 

The code for the Bootloader_Jump() function is simply :

// This function only works if it is called first in main.c, before anything else is initialized
void Bootloader_Jump(void)
{
 // Declaring function for memory jump
 void (*SysMemBootJump)(void);
 /* Set the address of the entry point to bootloader */
 volatile uint32_t BootAddr = 0x1FF09800;

 /* Set up the jump to booloader address + 4 */
 SysMemBootJump = (void (*)(void)) (*((uint32_t *) ((BootAddr + 4))));

 /* Set the main stack pointer to the bootloader stack */
 __set_MSP(*(uint32_t *)BootAddr);

 /* Call the function to jump to bootloader location */
 SysMemBootJump();

 /* Jump is done successfully */
 while (1)
 {
 /* Code should never reach this loop */
 }
}

5 replies

TDK
Super User
July 28, 2025

Looks like the bootloader is active and ACKing, no? I don't see anything to suggest the jump isn't working as intended.

Might want to monitor the NRST line to see if it's being reset.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Simon_LAuthor
Associate
July 29, 2025

At first yes, but then it resets after receiving the mass erase checksum (0xFF 0xFF 0x00). This reset is propagated and visible on the NRST line. After the faulty reset, the program boots back in the application.

On processors that work, there is a delay after receiving the checksum, followed by an ACK, no reset.

From looking at other posts concerning similar issues, the problem might be caused by a peripheral that is not being deinitialized properly, or a memory remapping issue. Is there anything else that could cause this behaviour?

TDK
Super User
July 29, 2025

> This reset is propagated and visible on the NRST line.

If NRST is going low, there's a reason. Perhaps a brown out condition occurs when the chip draws extra power for the erase procedure.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Pavel A.
Super User
July 28, 2025

 jump is working on processors with bootloader version 0x90, but not on boards with version 0x91. 

@STOne-32 ?  Another case of breaking change in the bootloader?

 

Khouloud GARSI
Technical Moderator
July 29, 2025

Hi @Simon_L ,

This limitation is seen on some STM32H743 samples where the erase takes more that 6 seconds.

This is due to the TIMOUT value used by the BL when waiting for the ongoing erase operation. The TIMEOUT value is set to 6 seconds, which is grater than the average erase timing (see below image) but less that the max value which is 10 seconds (see below image).

The erase operation seems to take more than 6 seconds on the sample that you have and this is why you see the reset. 

Please refer to the table below for more information about the flash Mass erase time.

KhouloudGARSI_0-1753796332042.png

To overcome this, either:
- Try with another sample with BL version V9.1 (if this is possible for you)
- Implement a code in RAM memory which erase the Flash and don't use the BL to do so (you can program that code in RAM using BL and then jump to it to perform the erase).
- Use a sample with BL version V9.2 ( the Erase timeout value was increased in BL V9.2).

 

Sorry for this inconvenience!

Khouloud.

Simon_LAuthor
Associate
July 29, 2025

Good to know, thank you. I have found this issue on all BL V9.1 tested (about 5 different chips of different batches). In this situation, wouldn't the reset occur after 6s instead of instantly after the request (less than 1ms)?
I have found an alternative solution to this problem which I will detail in another reply. Thanks for your help!

Simon_LAuthorBest answer
Associate
July 29, 2025

I have found a slightly different way to approach the jump which works on my setup. The approach is detailed by m4l490n in the replies to this post.
The idea is to define a section of memory in RAM for a flag so the jump to bootloader can be detected and processed before anything else is initialized in the main function.

Here is the code :

In STM32H743ZITX_FLASH.ld, right after .bss section :

 /* Section defined for flag for jump into booloader */
 .uninit_data (NOLOAD) :
 {
 . = ALIGN(4);
 *(.uninit_data)
 . = ALIGN(4);
 } >DTCMRAM

 

In file where the request to jump into bootloader is received (in my case, main.c) :

#define JUMP_TO_BOOTLOADER 0x01234567	// Indicates request to jump to bootloader
uint32_t boot_reason __attribute__((section(".uninit_data"))); // Variable defined in uninitialized section of RAM
															 // Can be accessed before anything else is init
															 // See STM32H743ZITX_FLAS.ld

 

Where request to jump into bootloader is received and processed :

boot_reason = JUMP_TO_BOOTLOADER; // Indicate request to jump into bootlaoder
NVIC_SystemReset();

 

First lines of main function :

int main(void)
{
 // Checks software request to jump into bootloader
 // This needs to be the first thing in main()
 if (boot_reason == JUMP_TO_BOOTLOADER)
 {
	boot_reason = 0;
	Bootloader_Jump();
 }

 

The code for the Bootloader_Jump() function is simply :

// This function only works if it is called first in main.c, before anything else is initialized
void Bootloader_Jump(void)
{
 // Declaring function for memory jump
 void (*SysMemBootJump)(void);
 /* Set the address of the entry point to bootloader */
 volatile uint32_t BootAddr = 0x1FF09800;

 /* Set up the jump to booloader address + 4 */
 SysMemBootJump = (void (*)(void)) (*((uint32_t *) ((BootAddr + 4))));

 /* Set the main stack pointer to the bootloader stack */
 __set_MSP(*(uint32_t *)BootAddr);

 /* Call the function to jump to bootloader location */
 SysMemBootJump();

 /* Jump is done successfully */
 while (1)
 {
 /* Code should never reach this loop */
 }
}
TDK
Super User
July 30, 2025

This is somewhat unsatisfying as a solution. As you state, why would the bootloader immediately reset here? Doesn't make any sense. It's not a timeout, it happens immediately on the mass reset command.

It works from a fresh reset state, so something on the chip is configured such that this problem occurs? What could that even be?

 

"If you feel a post has answered your question, please click ""Accept as Solution""."