cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 - Jump to Application from custom bootloader fails when compiling in release mode

MSard
Associate II

Hello,

I have developed a cusom bootloader for STM32H743; the bootloader gets an image file from serial port, writes it in FLASH at address 0x08020000 and then jump to it.

The function I have implemented for jumping is the usual one:

void runApplication(uint32_t app_address)
 
{
 
   McuDeInit();
 
 
   HAL_SuspendTick();
 
 
   /* Jump to user application */
 
   JumpAddress = *(__IO uint32_t*)(app_address + 4);
 
   JumpToApplication = (pFunction) JumpAddress;
 
   /* Initialize user application's Stack Pointer */
 
   __set_MSP(*(__IO uint32_t*) app_address);
 
   JumpToApplication();
 
}

First I do all uninitialization of peipherals and interrupts, then I set the SP and finally jump; app_address passed as parameter is equal to 0x08020000.

Everything works perfectly if i compile and run the program in Debug mode, but i get an Hard Fault when I compile in Release Mode.

I took a look at the disassemly which is obviously different:

In Debug Mode:

void runApplication(uint32_t app_address)
{
0x080020a4  push {r7, lr} 
0x080020a6  sub sp, #16 
0x080020a8  add r7, sp, #0 
0x080020aa  str r0, [r7, #4] 
	McuDeInit();
0x080020ac  bl 0x8002114 <McuDeInit> 
	
	HAL_SuspendTick();
0x080020b0  bl 0x8004ecc <HAL_SuspendTick> 
	
	/* Jump to user application */
	JumpAddress = *(__IO uint32_t*)(app_address + 4);
0x080020b4  ldr r3, [r7, #4] 
0x080020b6  adds r3, #4 
0x080020b8  ldr r3, [r3, #0] 
0x080020ba  ldr r2, [pc, #40]	; (0x80020e4 <runApplication+64>) 
0x080020bc  str r3, [r2, #0] 
	JumpToApplication = (pFunction) JumpAddress;
0x080020be  ldr r3, [pc, #36]	; (0x80020e4 <runApplication+64>) 
0x080020c0  ldr r3, [r3, #0] 
0x080020c2  mov r2, r3 
0x080020c4  ldr r3, [pc, #32]	; (0x80020e8 <runApplication+68>) 
0x080020c6  str r2, [r3, #0] 
	/* Initialize user application's Stack Pointer */
	__set_MSP(*(__IO uint32_t*) app_address);
0x080020c8  ldr r3, [r7, #4] 
0x080020ca  ldr r3, [r3, #0] 
0x080020cc  str r3, [r7, #12] 
0x080020ce  ldr r3, [r7, #12] 
0x080020d0  msr MSP, r3 
	JumpToApplication();
0x080020d4  ldr r3, [pc, #16]	; (0x80020e8 <runApplication+68>) 
0x080020d6  ldr r3, [r3, #0] 
0x080020d8  blx r3 
}

And the register status, just before the jump is the following one:

r0 = 0x00000000 r1 = 0x240013c4 r2 = 0x08024819 r3 = 0x08024819 r4 = 0x2400144c r5 = 0x0800c440 r6 = 0x00000000 r7 = 0x2407ffe0 r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 r11 = 0x00000000 r12 = 0x2407ffef sp = 0x20020000 lr = 0x080020b5 pc = 0x080020d8 fpscr = 0x00000010

In Release Mode:

void runApplication(uint32_t app_address)
{
0x08002090  push {r4, lr} 
0x08002092  mov r4, r0 
	McuDeInit();
0x08002094  bl 0x8002338 <McuDeInit> 
	
	HAL_SuspendTick();
0x08002098  bl 0x8003d94 <HAL_SuspendTick> 
	
	/* Jump to user application */
	JumpAddress = *(__IO uint32_t*)(app_address + 4);
0x0800209c  ldr r3, [r4, #4] 
	JumpToApplication = (pFunction) JumpAddress;
	/* Initialize user application's Stack Pointer */
	__set_MSP(*(__IO uint32_t*) app_address);
0x0800209e  ldr r2, [r4, #0] 
0x080020a0  msr MSP, r2 
}
0x080020a4  ldmia.w sp!, {r4, lr} 
	JumpToApplication();
0x080020a8  bx r3 
0x080020aa  nop

When program reaches the instruction ldmia.w sp!, {r4, lr} then jumps to HardFault handler and so it doesn't jump to application.

The register status before the Hard Fault is the following:

r0 = 0x00000000 r1 = 0x00000000 r2 = 0x20020000 r3 = 0x08024819 r4 = 0x08020000 r5 = 0x240013b0 r6 = 0x2400000c r7 = 0x240013bc r8 = 0x240013a8 r9 = 0x08020000 r10 = 0x240013a4 r11 = 0x240013b4 r12 = 0x00000021 sp = 0x20020000 lr = 0x0800209d pc = 0x080020a4 fpscr = 0x00000010

I can't see anything wrong at first glance; once in HardFault Handler I can see that:

  • Bit FORCED of HSFR is set, so this is a forced Hard Fault
  • Bit PRECISERR of BFSR is set, so this is a data bus error,
  • Bit BFARVALID is set and BFAR is equal to 0x20020000

I don't have any hints on where the problem lies and why it shows only in Release mode; please can anyone help me ?

Thanks

1 ACCEPTED SOLUTION

Accepted Solutions

What compiler are you using? Guess GNU/GCC

You're likely setting SP to 0x20020000, and then making that go UPWARD

Smarter solutions are to set the SP in Reset_Handler to __initial_sp, rather than let the compiler change it mid function, and unwind.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

5 REPLIES 5

What compiler are you using? Guess GNU/GCC

You're likely setting SP to 0x20020000, and then making that go UPWARD

Smarter solutions are to set the SP in Reset_Handler to __initial_sp, rather than let the compiler change it mid function, and unwind.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
AppJump         PROC
                EXPORT  AppJump   ; STM32L432
 
                LDR     R1, =0xE000ED00 ; SCB
                LDR     R0, =0x08002000 ; APP BASE
                STR     R0, [R1, #8]    ; VTOR
                LDR     SP, [R0, #0]    ; SP @ +0
                LDR     R0, [R0, #4]    ; PC @ +4
                BX      R0
                ENDP ; sourcer32@gmail.com

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
MSard
Associate II

Hi Clive,

thanks for the answer! Yes I am using GNU/GCC (visualGDB).

Sorry but I don't understand; how can i make the SP go upward ? Shouldn't the stack grow downward ?

Looking at the code you have posted the main difference I see compared to my code is that you set SCB->VTOR before jumping to application is that correct ?

Doesn't the instruction LDR SP, [R0, #0] already set SP to __initial_sp ? Do I have to do it also in application's Reset_Handler ?

Thanks again

I'd wager the LDMIA SP! goes upward.

W​hen I set SCB VTOR the system enters the Reset Handler with a system view more closely match boot conditions. You can set it and the SP again, as a defensive move. Easier to get the assembler to build what you need than the compiler.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
MSard
Associate II

I guess you are right since IA stands for increment after. Anyway I have changed my jumping code using assembly instructions as you suggested and now everything works perfectly.

Thank you very much.