Skip to main content
Werner Mann
Associate
July 13, 2018
Solved

STM32H743: How to start the system boot loader via software

  • July 13, 2018
  • 5 replies
  • 8917 views
Posted on July 14, 2018 at 01:29

Hi,

what is the procedure to start the system bootloader in the STM32H743 via software. Even newest AN2606 is not clear on this, since none of the mentioned methods fit the STM32H7 registers etc.

What I mean:

For the F4 the system memory needs to be remapped to 0x00000000, load MSP from value in address 0x00000000 and then a jump to the address stored in address 0x0000004 is done. This works for an F4.

On the F7 (also a Cortex-M7) some option bytes have to be configured correctly and then it is basically MSP from 0x1ff0000 and jump to value of 0x1ff00004.

But what is the procedure on the H7? The system memory is located like on the F7 on 0x1ff00000 but it is not readable, and because of that no loading of MSP and reading the correct jump address. There is no system memory remapping bit in the SYSCFG register which is what AN2606 suggests to use, the only exception mentioned is for the F7. I think there is either no way to achieve this on the STM32H7 or another not yet documented way. In any case, AN2606 is lacking sufficient information, probably forgotten when adding the H7.

Just for reference: When booting with the BOOT pin high, DFU works, no problems here. It is a Rev. Y

Anyone any  idea what works?

Werner

This topic has been closed for replies.
Best answer by Tesla DeLorean
Posted on July 14, 2018 at 05:17

0x1FF09800

5 replies

Tesla DeLorean
Tesla DeLoreanBest answer
Guru
July 14, 2018
Posted on July 14, 2018 at 05:17

0x1FF09800

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Tesla DeLorean
Guru
July 14, 2018

Original Posted on July 14, 2018 at 07:33

Definitely gets into ROM

startup.s (Keil)
 
Reset_Handler PROC
 EXPORT Reset_Handler [WEAK]
 IMPORT SystemInit
 IMPORT __main
 
; STM32H7 Boot-to-ROM sourcer32@gmail.com 13-July-2018
 
 LDR R0, =0x2001FFFC ; Safe End-of-RAM location (for demonstration)
 LDR R1, =0xBEEFBEEF ; Special Key
 LDR R2, [R0, #0]
 CMP R1, R2
 BNE NotDFuse
 
 STR R0, [R0, #0] ; Invalidate Key
 LDR R1, =0xE000ED00 ; SCB
 LDR R0, =0x1FF09800 ; ROM BASE
 STR R0, [R1, #8] ; VTOR
 LDR SP,[R0, #0] ; ROM Stack Pointer
 LDR R0,[R0, #4] ; ROM Program Counter
 BX R0
 
NotDFuse
 
 LDR R0, =SystemInit
 BLX R0
 
 LDR R0, =__main
 BX R0
 
 ENDP Reset_Handler
 
main.c
 
void DFUBoot(void)
{
 *((uint32_t *)0x2001FFFC) = 0xBEEFBEEF; // Special Key to End-of-RAM
 
 SCB_CleanDCache();
 NVIC_SystemReset();
}

Formatting broken in forum transition, edited to try and fix that

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Khouloud GARSI
Technical Moderator
January 21, 2019

Hello,

In STM32H7, the base address of the system memory is different from the entry point of the bootloader.

Thus, in order to jump to the bootloader, address "0x1FF09800" should be used instead of "0x1FFF0000".

You may have a look on FAQ "Jump to Bootloader from application on STM32H7 devices".

Link:

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

Khouloud.

Werner Mann
Associate
January 21, 2019

Thanks for pointing the FAQ page out to me. While the first answer was already good enough for my purpose, it is good to see some sample code which includes the proper deactivation procedure.

Werner

Werner Mann
Associate
January 21, 2019

Indeed the caches and MPU should be considered. In my bootloader I simply do not activate any of these (for exactly the above reason) but in general you're right. You may be right about the interrupt context and protected mode (at least for the later I hope you are!).

Beni1
Associate II
March 10, 2020

Hi!

I have basically two questions:

1. How can I jump to user code after exiting DFU on a dual core chip?

I am using NUCLEO-H745ZI-Q board and I can reset to the CM7 core by setting address 0x8000000 and than initiate a 0 download or to CM4 core if I set address 0x81000000. But cannot really start up both cores? Or is there a way to start from one core the other?

So basically my aim is to connect BOOT0 pin to high and the controller always comes up as a DFU device when board starts up and when the USB host is up it can update the firmware if neccessary and than run the user code on both cores?

2. If I am using CM7 core with USB stuffs than I need to disable USB interrupts and reset them to work properly(regarding to the DFU manual):

"When performing a jump from the bootloader to a loaded application code using the USB IP,

the application has to disable all pending USB interrupts and reset the core before enabling

interrupts. Otherwise, a pending interrupt (issued from the bootloader code) may interfere

with the user code and cause a functional failure. This procedure is not needed after exiting

the system memory boot mode"

I am doing this in the beginning of USB_OTG_FS_PCD_Init ()

 hpcd_USB_OTG_FS.Instance = USB_OTG_FS;

 USB_DisableGlobalInt(hpcd_USB_OTG_FS.Instance); //disable USB global interrupt

 USB_CoreReset_User(hpcd_USB_OTG_FS.Instance); //copy of restet USB core code fom LL libraries

but it only works sometimes only once but generally doesnt work. Either my user code USB deivce comes up or the USB bootloader and than I try to reset to bootloader and the USB doesnt come up at all.. and after that I need to power cycle the whole demo board to get any USB back, reset pin doesnt work.. quite odd, probaly USB is getting in a messy state somehow..

Thanks,

Beni

Zed
Associate III
August 6, 2022

For those whom other solutions didn't help there's clear instructions from Arm which, by the way, helped me a lot.

Direct link to the article: https://developer.arm.com/documentation/ka002218/latest

...When the flash content was updated or is already up-to-date, the bootloader jumps to the user application. This requires a number of steps before the user application can be executed. This is usually done by calling a function such as the example below, BootJump(), which has the aim to basically restore reset conditions for the user application:

static void BootJump( uint32_t *Address )
{

Make sure, the CPU is in privileged mode.

 if( CONTROL_nPRIV_Msk & __get_CONTROL( ) )
 { /* not in privileged mode */
 EnablePrivilegedMode( ) ;
 }

The function EnablePrivilegedMode( ) triggers a SVC, and enters handler mode (which can only run in privileged mode). The nPRIV bit in the CONTROL register is cleared which can only be done in privileged mode. See ARM: How to write an SVC function about implementing SVC functions.

Disable all enabled interrupts in NVIC.

NVIC->ICER[ 0 ] = 0xFFFFFFFF ;
NVIC->ICER[ 1 ] = 0xFFFFFFFF ;
NVIC->ICER[ 2 ] = 0xFFFFFFFF ;
NVIC->ICER[ 3 ] = 0xFFFFFFFF ;
NVIC->ICER[ 4 ] = 0xFFFFFFFF ;
NVIC->ICER[ 5 ] = 0xFFFFFFFF ;
NVIC->ICER[ 6 ] = 0xFFFFFFFF ;
NVIC->ICER[ 7 ] = 0xFFFFFFFF ;

Disable all enabled peripherals which might generate interrupt requests, and clear all pending interrupt flags in those peripherals. Because this is device-specific, refer to the device datasheet for the proper way to clear these peripheral interrupts.

Clear all pending interrupt requests in NVIC.

NVIC->ICPR[ 0 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 1 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 2 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 3 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 4 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 5 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 6 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 7 ] = 0xFFFFFFFF ;

Disable SysTick and clear its exception pending bit, if it is used in the bootloader, e. g. by the RTX.

SysTick->CTRL = 0 ;
SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk ;

Disable individual fault handlers if the bootloader used them.

SCB->SHCSR &= ~( SCB_SHCSR_USGFAULTENA_Msk | \ 
 SCB_SHCSR_BUSFAULTENA_Msk | \ 
 SCB_SHCSR_MEMFAULTENA_Msk ) ;

Activate the MSP, if the core is found to currently run with the PSP. As the compiler might still use the stack, the PSP needs to be copied to the MSP before this.

if( CONTROL_SPSEL_Msk & __get_CONTROL( ) )
{ /* MSP is not active */
 __set_MSP( __get_PSP( ) ) ;
 __set_CONTROL( __get_CONTROL( ) & ~CONTROL_SPSEL_Msk ) ;
}

Load the vector table address of the user application into SCB->VTOR register. Make sure the address meets the alignment requirements.

SCB->VTOR = ( uint32_t )Address ;

A few device families, like the NXP 4300 series, will also have a shadow pointer to the VTOR, which also needs to be updated with the new address. Review the device datasheet to see if one exists.

The final part is to set the MSP to the value found in the user application vector table and then load the PC with the reset vector value of the user application. This can't be done in C, as it is always possible, that the compiler uses the current SP. But that would be gone after setting the new MSP. So, a call to a small assembler function is done.

BootJumpASM( Address[ 0 ], Address[ 1 ] ) ;

The program flow will never return to this point.

This is the end of the function BootJump( ).

}

The BootJumpASM( ) helper function can also be implemented with the compiler. However, writing assembler is something compiler-specific. So the implementation for the BootJumpASM( ) function looks different for each compiler.

Arm Compiler 5

__asm __attribute__( ( noreturn ) ) void BootJumpASM( uint32_t SP, uint32_t RH )
{
 MSR MSP,r0
 BX r1
}

Arm Compiler 6

__attribute__( ( naked, noreturn ) ) void BootJumpASM( uint32_t SP, uint32_t RH )
{
 __asm("MSR MSP,r0");
 __asm("BX r1");
}

Define the starting address for the main application, and call the jump function with the address as a parameter:

#define USER_APPLICATION_BASE_ADDRESS 0x00008000 /* as example */
 
BootJump( ( uint32_t * )USER_APPLICATION_BASE_ADDRESS ) ;

Now, flash the device with both applications, to debug the jump. Use the Disassembly dialog to confirm the memory address of the instructions.