2025-06-04 4:35 AM
Hi everyone,
I'm currently working on a custom board featuring an STM32H747, and my goal is to implement a firmware update mechanism via the I2C interface. Since I'm a beginner when it comes to bootloaders (especially with dual-core microcontrollers), I'm reaching out for some help.
I don't have physical access or the ability to control the BOOT0/BOOT1 pins of the MCU. This means I must rely exclusively on a custom bootloader residing in the internal Flash. This bootloader will need to handle receiving the new firmware via I2C and subsequently programming the Flash.
Can anyone help me out? I'm not sure where to start.
Thanks a lot for your time and support!
2025-06-04 5:14 AM
Look at AN2606 for which pins are supported by the internal bootloader. Use one of those.
STM32 microcontroller system memory boot mode - Application note
I2C protocol used in the STM32 bootloader - Application note
Internally, jump to the bootloader when you want to flash the device and communicate with it over I2C.
How to jump to system bootloader from application ... - STMicroelectronics Community
2025-06-04 8:55 AM
Hi TDK, and thank you for your response.
I followed the guide you linked and built my JumpToBootloader function as follows:
#define BOOT_ADDR 0x1FF09800 // my MCU boot code base address
struct boot_vectable_ {
uint32_t Initial_SP;
void (*Reset_Handler)(void);
};
#define BOOTVTAB ((struct boot_vectable_ *)BOOT_ADDR)
void JumpToBootloader(void)
{
/* Disable all interrupts */
__disable_irq();
/* Disable Systick timer */
SysTick->CTRL = 0;
/* Set the clock to the default state */
HAL_RCC_DeInit();
/* Clear Interrupt Enable Register & Interrupt Pending Register */
for (uint8_t i = 0; i < 8; i++)
{
NVIC->ICER[i]=0xFFFFFFFF;
NVIC->ICPR[i]=0xFFFFFFFF;
}
/* Re-enable all interrupts */
__enable_irq();
// Set the MSP
__set_MSP(BOOTVTAB->Initial_SP);
// Jump to app firmware
BOOTVTAB->Reset_Handler();
}
I executed my function on the CM4 core and noticed that it doesn't work because it calls the HardFault_Handler function. Then, I executed the function on the CM7 core instead, and it works.
So, my first question is: Can I only call the bootloader from the CM7 core?
If the answer is yes, since my application code runs on the CM4 core, how do I call the function that's on the CM7 core from the application running on the CM4 core?
Once the bootloader is started, can I update both the CM7 core firmware and the CM4 core firmware?
I read Application Note AN4221, which explains the commands to use for operations on the microcontroller via I2C. Is there an example of how to upload a .hex or .bin file using these commands?
Finally, if something goes wrong and the new firmware isn't loaded correctly (e.g., the battery drains), I'll lose the ability to restart the bootloader because I've corrupted the firmware, right? In that case, I absolutely need to have access to the BOOT pin to put the microcontroller back into bootloader mode, right?
Thank you for your time.
2025-06-04 2:34 PM - edited 2025-06-04 2:34 PM
> So, my first question is: Can I only call the bootloader from the CM7 core?
I don't see anything saying this one way or the other. But in any case, you will need to ensure the other core does NOTHING while the bootloader is active and that the chip is in an as-reset state, meaning clocks are disabled, peripherals are disabled, etc. It would be better to do it on the CM7 core just after reset to ensure this state.
> Once the bootloader is started, can I update both the CM7 core firmware and the CM4 core firmware?
Yes.
> Finally, if something goes wrong and the new firmware isn't loaded correctly (e.g., the battery drains), I'll lose the ability to restart the bootloader because I've corrupted the firmware, right? In that case, I absolutely need to have access to the BOOT pin to put the microcontroller back into bootloader mode, right?
You can change option bytes to always boot into the bootloader, then change them back once the flash operation is successful. This also solves the above potential problem: set option bytes and reset to boot into the bootloader.