2025-06-02 5:08 AM - edited 2025-06-02 5:15 AM
Hello everyone,
MCU in use: STM32H745XI (dual-core, Bootloader v9.1, CubeIDE 1.16.1, HAL v1.11.3, CubeProgrammer v2.17.0)
Hardware status: BOOT0 HIGH works perfectly, I can access the system bootloader over USART1 (PA9/PA10), and program via UART. Hardware is validated and all connections are good. PB15/PB14 pins are floating, not connected anywhere.
My need:
I want to jump from user application (C code only, no BOOT0 pin) to the internal ROM system bootloader for firmware update purposes, so that I can upload new firmware over UART (using CubeProgrammer or similar), and then return to normal application on the next reset.
Here are the methods I have tried (none worked):
Set MSP to 0x1FF09800, jump to 0x1FF09804 (function pointer), disable all interrupts (NVIC->ICER), set PRIMASK/FAULTMASK, disable and invalidate caches (SCB), disable SysTick, deinit all peripherals (HAL_DeInit, RCC_DeInit, etc.).
Disable MPU/SAU regions (including secure/privileged regions).
Put all GPIOs (including used UART pins) in analog input (to avoid interference).
Set all memory barriers (DSB/ISB) and do multiple dummy memory accesses before jump.
Used both CM7 and CM4 cores for jump (with CM4 in low power/stop or held in reset).
Verified that all Option Bytes are in default state except BOOT_CM7_ADD1 = 0x1FF0 (0x1FF00000).
Result:
MCU freezes (hard fault or lockup) and system bootloader never responds on UART.
BUT, if I use BOOT0 HIGH and reset the MCU, bootloader always works (handshakes over UART as expected).
My questions:
Has anyone successfully jumped to the system bootloader on STM32H745XI purely by C code (no BOOT0/OB change), and if so, how?
Is there any undocumented, low-level trick (register hack, RAM/stack/clock/secure config, etc.) to force bootloader entry, or is it silicon-level blocked?
Why exactly does the function pointer jump method (as used in STM32F4/F7/L4, and sometimes H747) fail on H745XI? Is there an internal hardware barrier at reset/boot?
Are there any real-world solutions beyond changing Option Bytes (which I can do, but would like to avoid for safety reasons)?
Notes:
PB15/PB14 pins are floating and not connected, so no TX damage risk.
If I brick the MCU, I can recover via SWD/JTAG or CubeProgrammer, so I am open to any risky/experimental ideas.
Any direct practical experience from someone who actually achieved this on STM32H745XI (not just theory or F4/F7 tricks) would be extremely valuable.
References:
Reference Manual Table 123 and Table 124 (bootloader address 0x1FF00000, entry 0x1FF09800, V9.1 limitations).
Datasheet: "Jump issue" and "boot mode is only checked at reset."
Thank you in advance!
Solved! Go to Solution.
2025-06-08 5:21 AM - edited 2025-06-12 4:52 AM
Dear @Ahmet Yasin CİVAN ,
Thank you very much for the detailed post and also valuable contribution to our STCommunity on how to jump in safe mode to system memory.
Thank you again
STOne-32
2025-06-10 6:21 AM - edited 2025-06-10 6:21 AM
Thank you so much for the kind words! I'm glad I could share some insights and help out in the STCommunity. If there’s ever any other tricky STM32H7 issue you’d like to chat about or if you’d like more details on my approach, just let me know — always happy to discuss!
2025-09-11 2:52 PM
This thread has been great to follow. Has anyone been able to use these methods on the STM32C011 MCUs to connect via UART? I've attempted to implement the software-only jump to the bootloader and it locks-up in a similar manor. I've pulled in the relevant suggestions from the thread but the issue persists. Looking at the PC in the debugger, it jumps to the bootloader address but the chip doesn't respond to the UART connection from STM32CubeProgramer. The error being:
Error: Activating device: KO. Please, verify the boot mode configuration and check the serial port configuration. Reset your device then try again...
This is the simplified version of the code which, I believe, pulls in all the suggested fixes:
volatile uint32_t BootAddr_STM32C0 = 0x1FFF0000;
_Pragma("GCC push_options") \
_Pragma("GCC optimize (\"O0\")")
void JumpToBootloader(void)
{
uint32_t i=0;
void (*SysMemBootJump)(void);
/* Disable all interrupts */
__disable_irq();
//De-init all peripherals
HAL_DMA_DeInit(&hdma_tim3_ch4);
HAL_DMA_DeInit(&hdma_tim17_ch1);
HAL_TIM_PWM_DeInit(&htim3);
HAL_TIM_Base_DeInit(&htim3);
HAL_TIM_PWM_DeInit(&htim14);
HAL_TIM_Base_DeInit(&htim14);
HAL_TIM_PWM_DeInit(&htim17);
HAL_TIM_Base_DeInit(&htim17);
HAL_UART_DeInit(&huart1);
HAL_UART_DeInit(&huart2);
/* 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<(sizeof(NVIC->ICER)/sizeof(NVIC->ICER[0]));i++)
{
NVIC->ICER[i]=0xFFFFFFFF;
NVIC->ICPR[i]=0xFFFFFFFF;
}
/* Re-enable all interrupts */
__enable_irq();
/* Set up the jump to boot loader address + 4 */
SysMemBootJump = (void (*)(void)) (*((uint32_t *) ((BootAddr_STM32C0 + 4))));
/* Set the main stack pointer to the boot loader stack */
__set_MSP(*(uint32_t *)BootAddr_STM32C0);
// Set the Memory Mode
SYSCFG->CFGR1 = 0x01;
/* Call the function to jump to boot loader location */
SysMemBootJump();
/* Jump is done successfully */
/* Code should never reach this loop */
while (1){}
}
_Pragma("GCC pop_options")
The only lead I'm still checking into is the possibility of some USART interrupts needing to be reenabled after clearing all the ICER and ICPR registers.
If anyone has been able to get this working on the STM32CO11, I'd love to hear about it.
Thanks in advance.
.
2025-09-12 8:32 AM
Does it work with the BOOT0 pin method?
How about very early in Reset_Handler code in startup.s? This might be the simplest as the MCU is close to reset conditions without all your peripherals, clocks and interrupts.
Check the SYSCFG clock is enabled, and that you're actually mapping the ROM at zero. Inspect the vector table and confirm the entry point