cancel
Showing results for 
Search instead for 
Did you mean: 

Jump to internal Bootloader with STM32F7

Kevin Lehzen
Associate III
Posted on January 26, 2018 at 16:55

Hi there,

we are currently developing the firmware for our custom board with an STM32F746 MCU in LQFP-100 package. Our current version is working well and now we want to be able to download updates via USB DFU. I read many posts and the related documents from ST, so there might be some ways to realize this. Unfortunately, in either way we get stuck on  choosing the right addresses or verifying code with DfuSe. My favorite way is the following in which we jump to the internal bootloader:

&sharpdefine SYS_MEM_ADD                              0x1FF00000

 

//Disables the RCC (reset setting)

HAL_RCC_DeInit();

SysTick->CTRL = 0;

SysTick->LOAD = 0;

SysTick->VAL = 0;

// disables every IRQ

__disable_irq();

// remap system memory to 0x0000 0000

SYSCFG->MEMRMP = 0x01;

JumpToApplication = (void (*)(void)) (*((uint32_t *)(SYS_MEM_ADD + 4)));

__set_MSP(*(__IO uint32_t*) SYS_MEM_ADD);

JumpToApplication();

while(1);

 

 

The problem is that this way is just working in debug mode (toolchain SW4STM32 with Segger J-link). So my breakpoint is at JumpToApplication() and when I go one step further the device appears in DfuSe with the correct memory mapping (DFU update possible). In normal run mode the application is running and while switching to DFU/Bootloader mode the MCU just resets. I tried some different addresses but nothing would work. Maybe there is another way or something wrong in the IDE settings?

I appreciate every help. Thanks in advance!

Regards,

Kevin Lehzen

#stm32f7
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on January 27, 2018 at 02:51

This brought up 'STM32 BOOTLOADER' on the STM32F746G-DISCO for me

//***************************************************************************
void BootDFU(void)
{
 printf('Entering Boot Loader..

');
 SCB_DisableDCache();
 *((unsigned long *)0x2004FFF0) = 0xDEADBEEF; // 320KB STM32F7xx
 __DSB();
 NVIC_SystemReset(); 
}
//***************************************************************************

; Reset handler
Reset_Handler PROC
 EXPORT Reset_Handler [WEAK]
 IMPORT SystemInit
 IMPORT __main
 LDR R0, =0x2004FFF0 ; Address for RAM signature
 LDR R1, =0xDEADBEEF
 LDR R2, [R0, #0]
 STR R0, [R0, #0] ; Invalidate
 CMP R2, R1
 BEQ Reboot_Loader
 LDR R0, =SystemInit
 BLX R0
 LDR R0, =__main
 BX R0
 ENDP
Reboot_Loader PROC
 EXPORT Reboot_Loader ; STM32F7xx
 LDR R0, =0x1FF00000 ; ROM BASE
 LDR SP, [R0, #0] ; SP @ +0
 LDR R0, [R0, #4] ; PC @ +4
 BX R0
 ENDP ; sourcer32@gmail.com
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

View solution in original post

17 REPLIES 17
Clive1 (HNL)
Senior II
Posted on January 26, 2018 at 18:50

A blanket disabling of IRQs is unhelpful, where would that get enabled again? Does this reflect the state at reset? Turn off your interrupt sources at the peripheral.

Don't call the loader from an interrupt context.

Would have to see if the system loader is testing for the dual bank boot.

Posted on January 27, 2018 at 02:51

This brought up 'STM32 BOOTLOADER' on the STM32F746G-DISCO for me

//***************************************************************************
void BootDFU(void)
{
 printf('Entering Boot Loader..

');
 SCB_DisableDCache();
 *((unsigned long *)0x2004FFF0) = 0xDEADBEEF; // 320KB STM32F7xx
 __DSB();
 NVIC_SystemReset(); 
}
//***************************************************************************

; Reset handler
Reset_Handler PROC
 EXPORT Reset_Handler [WEAK]
 IMPORT SystemInit
 IMPORT __main
 LDR R0, =0x2004FFF0 ; Address for RAM signature
 LDR R1, =0xDEADBEEF
 LDR R2, [R0, #0]
 STR R0, [R0, #0] ; Invalidate
 CMP R2, R1
 BEQ Reboot_Loader
 LDR R0, =SystemInit
 BLX R0
 LDR R0, =__main
 BX R0
 ENDP
Reboot_Loader PROC
 EXPORT Reboot_Loader ; STM32F7xx
 LDR R0, =0x1FF00000 ; ROM BASE
 LDR SP, [R0, #0] ; SP @ +0
 LDR R0, [R0, #4] ; PC @ +4
 BX R0
 ENDP ; sourcer32@gmail.com
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Posted on January 29, 2018 at 20:30

Thanks Clive,

I am sorry but I am a bit confused where to put the assembler code. Looks like its something for the startup...s?

Kind regards,

Kevin

Posted on January 29, 2018 at 22:25

Yes startup_stm32f7xx.s augmenting the reset vector permitting transfer into ROM at 'reset' conditions. Here using Keil syntax.

Kevin Lehzen
Associate III
Posted on February 01, 2018 at 10:02

Thanks for your help, Clive. Now it works!

Cheers

Posted on February 19, 2018 at 21:01

Hi Clive

I too am struggling to get this boot loader thing going. I have read AN2606 and 3155 from STM and have seen your replies to many others like me in this forum. I am using an STM32L496 and will use USART1 as my boot load device. Could you explain a couple of things about the overall system to me:

1) I see that you are writing a flag into RAM and then testing this flag out of reset to determine if the CPU will branch to the main code or the boot loader. Why would you do this rather than just jump to the boot loader?

2) The STM docs tell me that the boot loader in the L496 will use the Systick timer for USART1. Figure 67 in AN2606 seems to indicate that the boot loader code will take care of setting this up. Do I need to disable the existing systick timer before jumping to the boot loader?

3) The same figure doesn't show that the USARTs are enabled by the boot loader. Do I need to set up  USART1 before I jump there or did they just forget to include this in the figure?

4) In your system that writes 'DEADBEEF' to a RAM location, would there not be a risk of making the famous 'brick' if the boot load was interrupted? If the 'DEADBEEF' was written to an area of flash instead, and then only cleared by the PC updating program once it is sure the new code has been completely transferred, would that be any better? I think this should be possible with the L496 hardware.

Many thanks in advance for your advice (and patience)!

Posted on February 19, 2018 at 22:53

1) Because you're a lot closer to 'reset conditions' than you are in your main code with interrupts, PLLs etc.

2) The system loader runs from ROM with no user intervention normally, you're goal is to enter with the least amount of meddling. You enabling and having a bunch of interrupts firing isn't what the system loader expects.

3) see 2

4) If you foolishly delete the boot loader in FLASH so the board has nothing to execute you can certainly brick things. The goal would be to have a boot loader in front that you *don't* delete, and it checks and validates the application image placed later in FLASH before calling it. That way you always have something functioning, and a system that is recoverable. Not exactly sure how having a RAM tag that says run ROM vs FLASH will brick the system during a single reset cycle, or how that would be different, or less safe, to writing something more permanently in FLASH

If you want a recoverable board you'd expose the BOOT0 pins so you can get the device into the ROM's system loader.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on February 20, 2018 at 00:05

Using Clive Oness guidance from above, I have it working now for the L496. To answer one of my questions above, the boot loader code does look after everything wrt to the USART and Systick set up. In the startup_stm32l496xx.s file, I inserted this just before the STM generated branch to main ( 'bl main') :

/* Look for boot loader signature. */

LDR R0, =0x20002000         

// note different location for my system compared to example above

LDR R1, =0xDEADBEEF

LDR R2, [R0, &sharp0]

/* Invalidate */

STR R0, [R0, &sharp0]

CMP R2, R1

BEQ Reboot_Loader

LDR R0, =SystemInit

BLX R0

bl main

Reboot_Loader:

/* Boot Loader BASE */

LDR R0, =0x1FFF0000  

 // note different boot loader location for L496 compared to above

LDR SP, [R0, &sharp0]

// SP @ +0

LDR R0, [R0, &sharp4]

// PC @ +4

BX R0

// jump to bootloader

/* Call the application's entry point.*/

<-this generated by STM

 bl main

<-this is generated by STM and could be removed now

LoopForever:

<-this is generated by STM 

b LoopForever

<-this is generated by STM 

And the function that starts it all:

void

bootload(

void

)

{

*((

unsigned

long

*)0x20002000) = 0xDEADBEEF;

NVIC_SystemReset();

while

(1);

// this should never happen!

}

For the L496, I will try placing the DEADBEEF signature into an area of flash that will be off limits to my update program. I will also not overwrite the code in the startupxxx.s file during an update. Once the new code has been completely written and verified, then I will clear the DEADBEEF flash location with the update program. I believe that this will keep the system in the boot load mode even if power or coms are interrupted during an update.

6 Mar 2018: Update for conversion to STM32L4R5: The stm32lr5 has a couple of changes compared to the stm32l496 that require an addition to the assembler startup file. The Syscfg register must be modified to map the bootloader to address 0x00000000:

/* Look for boot loader signature. */

LDR R0, =0x20040000

LDR R1, =0xDEADBEEF

LDR R2, [R0, &sharp0]

/* Invalidate */

STR R0, [R0, &sharp0]

CMP R2, R1

BEQ Reboot_Loader

LDR R0, =SystemInit

BLX R0

bl main

Reboot_Loader:

/* Remap bootloader code to address 0x00000000 */

LDR R0, =0x40021060

// address of the clock enable register for access to syscfg

LDR R1, =0x00000001

// only need to set bit one to 1. All others will be 0 out of reset

STR R1, [R0, &sharp0]

LDR R0, =0x40010000

// location of SYSCFG_MEMRMP

LDR R1, =0x00000001

STR R1, [R0, &sharp0]

/* Boot Loader BASE */

LDR R0, =0x00000000

LDR SP, [R0, &sharp0]

// SP @ +0

LDR R0, [R0, &sharp4]

// PC @ +4

BX R0

// jump to bootloader

/* Call the application's entry point.*/

bl main

LoopForever:

b LoopForever

Posted on February 20, 2018 at 01:18

Makes sense and much appreciated! Thanks for your help J

Paul