2018-11-12 07:03 AM
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:
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
Solved! Go to Solution.
2018-11-12 08:45 AM
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.
2018-11-12 08:45 AM
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.
2018-11-12 08:50 AM
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
2018-11-12 01:49 PM
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
2018-11-12 04:25 PM
I'd wager the LDMIA SP! goes upward.
When 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.
2018-11-12 11:07 PM
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.