Skip to main content
MSard
Associate II
November 12, 2018
Solved

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

  • November 12, 2018
  • 5 replies
  • 2419 views

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

    This topic has been closed for replies.
    Best answer by Tesla DeLorean

    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.

    5 replies

    Tesla DeLorean
    Tesla DeLoreanBest answer
    Guru
    November 12, 2018

    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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Tesla DeLorean
    Guru
    November 12, 2018
    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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
    MSard
    MSardAuthor
    Associate II
    November 12, 2018

    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

    Tesla DeLorean
    Guru
    November 13, 2018

    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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
    MSard
    MSardAuthor
    Associate II
    November 13, 2018

    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.