cancel
Showing results for 
Search instead for 
Did you mean: 

Jump to the STM32H745 Bootloader from application/user code

EZamo.1
Associate III

Trying to debug why the StLinkv3/Cube isn't bootloading..

According to AN2606, the embedded dfu bootloader for the M7 is in: ITCM-RAM at 0x00000000 (Boot0=0 is FLASH 0x0800 0000)

However, once I jump, I don't see the UART TX line go high, which would indicate the boot loader is running. My guess is that I'm not initializing the addresses correctly... or.. there's a conflict with the M4 that is running. Unfortunately, the BCM4/BCM7 lines are tied high on the board, so I can't disable the M4 which doesn't have any code.

#define FW_ADDR 0
SysMemBootJump = (void(*)(void))(*((u32*)FW_ADDR+4);
static inline __attribute__((always_inline)) 
void jump ( void )
{
	__disable_irq();  
	HAL_DeInit();
	SysTick->CTRL=0;
	SysTick->LOAD=0;
	SysTick->VAL=0;
	__set_PRIMASK(1);	
	SCB->VTOR = FW_ADDR;
	__set_MSP(*(volatile uint32_t *)FW_ADDR);
	__set_CONTROL(0);
	SysMemBootJump();   
}

9 REPLIES 9
TDK
Guru

System memory is typically not mapped to address zero. You have to explicitly do that in SYSCFG. But jumping to the system memory address is easier. For the H7, it's at 0x1FF09800.

https://community.st.com/s/article/STM32H7-bootloader-jump-from-application

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

Thanks, I thought the 0 address was suspicious!

However, if I flash code that does nothing but jump to the bootloader (using the function from the faq), I don't see the DFU respond on any of the UARTs (0x7F->0x79).

Since the uarts can be mapped to a few different pins, which ones does the dfu expect them on by default (BOOT0=1)? The AN2606 table, for example, has entries for UART1 on PA9/10 AND PB14/15.. so at power-on, is it checking both sets? Or does the peripheral need to be initialized in code, then the jump to the bootloader?

TDK
Guru

It is checking all peripherals at once, including all the listed pins in those peripherals. Once a response is received on ANY of those periperhals, the others are disconnected and the bootloader begins with the one it got a response on. This is covered in AN2606 in some detail.

You should see all the relevant UART TX lines go high once you're in the bootloader.

Just a note: DFU is specifically the USB DFU protocol. There is not DFU UART, it's just the UART bootloader.

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

Before getting the bootloader to work via jumping, I guess I should first confirm it works with BOOT0=3.3v. And to eliminate the possibility that other core (M4) is fighting with the M7.. I switched to the Nucleo stm32h743 board.

Interestingly, with BOOT0=gnd, I can initialize PB14 (Uart1 Tx) as an output, and make it toggle (3.3v/gnd)... however, with Boot0=3.3v, it goes to 2V (open?), and doesn't show any activity when I send 0x7f to PB15 (Uart1 Rx), or with FLASHER-STM32.

I haven't tried running the above experiment on Discovery stm32h745.. but any how else to check if it's in the bootloader or why it's not responding? It's a stock board, and I havent changed the default option bytes.

MSipo
Senior II

I solved jump to bootloader like this (I store a known value to a memory location, then reset the MCU, and at startup I check for that value and do a vector reset into the bootloader):

__no_init uint32_t boot;
 
void BootloaderCheck(void)
{
  if (boot == 0x8BADF00D)
  {
    boot = 0;
    // Call bootloader (Remap system memory (the bootloader) to address 0 and do a vector reset)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    // Remap System Flash memory (bootloader) to 0x00000000. This is normally selected
    // by the BOOT pins after reset.
    SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SystemFlash);
    // Wait for all explicit memory accesses before this instruction complete
    __DSB();
    // Do a vector reset
    SCB->AIRCR = (0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_VECTRESET;
    while(1); // Wait until reset
  }
}
 
void GotoBootloader(void)
{
  __disable_irq();
  boot = 0x8BADF00D;
  NVIC_SystemReset();
}

And also modified startup_stm32l1xx_md.s:

EXTERN  __iar_program_start
        EXTERN  SystemInit
        EXTERN  BootloaderCheck
...
Reset_Handler
        LDR     R0, =BootloaderCheck
        BLX     R0
        LDR     R0, =SystemInit
        BLX     R0
        LDR     R0, =__iar_program_start
        BX      R0

Essentially it's the same principle, which I've described here:

https://community.st.com/s/question/0D50X0000AFpTmUSQV/using-nvicsystemreset-in-bootloaderapplication-jumps

Take a look at it. Maybe some additional ideas can be useful to you. 🙂

There is an error in this example. The line for (i=0;i<5;i++) should be for (i=0;i<8;i++)

Why? 5*32 bits covers relevant entries.
If you feel a post has answered your question, please click "Accept as Solution".

for my case (STM32H745) both ICER and ICPR are defined as being an array of size 8. I experienced the same problem that EZamo.1 and KSun.3 had.

https://community.st.com/s/question/0D53W00000BLufd/how-do-i-jump-from-application-code-to-bootloader-without-toggling-the-boot0-pin-on-stm32h745