2025-07-28 2:42 PM - edited 2025-07-28 2:43 PM
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.
Any idea what could cause this and how it should be fixed?
Solved! Go to Solution.
2025-07-29 7:07 AM - edited 2025-07-29 7:08 AM
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 */
}
}
2025-07-28 3:00 PM
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.
2025-07-28 3:41 PM
> 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?
2025-07-29 4:40 AM
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?
2025-07-29 6:34 AM
> 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.
2025-07-29 6:43 AM
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.
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.
2025-07-29 6:55 AM
When checking RCC_CSR for the reset reason, the only reset I was able to identify was the intended SFTRESET right before this interaction, the faulty reset either came out blank (all zeroes) or still SFTRESET. I have monitored the power lines and they don't drop in voltage, and our power supplies should be more than sufficient for the chip's current needs. I have found a solution to my problem through an alternative method which I will detail in another reply. Thanks for your help!
2025-07-29 6:58 AM
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!
2025-07-29 7:07 AM - edited 2025-07-29 7:08 AM
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 */
}
}