cancel
Showing results for 
Search instead for 
Did you mean: 

Hard fault on blx instruction - STM32F091CBU6

GCalin
Associate II

Hello everyone,

 

I am developing a simple bootloader application where I have the bootloader code located at 0x8000000 and the main firmware at 0x8008000.

To jump from the bootloader to the firmware code I am using this code:

 

typedef void (*pFunction)(void);

pFunction JumpToFirmware = (pFunction)(*(__IO uint32_t*)(0x8008000 + 4));

__disable_irq();

JumpToFirmware();

 

For some reason the jump is generating a hard fault, catch by the hardfault event handler. Since there is no fault registers in the Cortex-M0, it is being difficult to track the problem down.

 

The generated assembly code looks good at JumpToFirmware():

JumpToFirmware();
08002da4: blx r2

 

I checked and the r2 is correctly loaded with value 0x8008225 (read from the firmware vector table stored at 0x8008000), however blx causes the hard fault. I even tried to straight test with a asm(" blx 0x8008225"), which I believe would be a valid branch, but it still causes the fault.

I also check the target address 0x8008225 and it contains the correct startup code of the main firmware.

 

Is there something else that must be set before using the blx in this particular scenario?

 

Gabriel

1 ACCEPTED SOLUTION

Accepted Solutions

Not exactly, but the PC being in the HardFault Handler is not helpful, it's not the thing that actually faulted.

What you want to see is the PC in the stacked context. So dump stack at SP too

https://github.com/cturvey/RandomNinjaChef/blob/main/KeilHardFault.c

I don't have a CM0(+) GNU/GAS version of the handler to hand.

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

8 REPLIES 8
liaifat85
Senior II

The firmware at 0x8008000 should be correctly compiled, linked, and flashed. The firmware must be fully functional and must have been built to be relocated to 0x8008000.

That was exactly what I did. The bootloader and firmware are separated projects, fully functional. The bootloader just flashes the MCU from 0x8008000, replacing the firmware code when needed. Only jumping from the bootloader to the firmware are causing problem, although the jump code appears to be correct. Any idea?

Pavel A.
Evangelist III

Add __isb() between __disable_irq() and  JumpToFirmware() ?

No change.

I even tried to blx 0x8008225 on the very first instruction of startup_stm32f091cbux.s, but it still causes the hard fault. Shouldn't it work? I could not find a detailed documentation that lists all possible hard fault on the Cortex M0 associated with the bl/blx instructions. Apparently only the use of even address should cause a hard fault with a blx instruction.

Get an effective HardFault_Handler()

Look at what's specifically being reported, and what instruction it's trying to jump too.

Want help here, show a dump of the registers, and a disassembly of the point of the fault, and where it was trying to jump

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

The fault is triggered at blx r3:

...
203 pFunction JumpToFirmware = (pFunction)(*(__IO uint32_t*)(0x8008000 + 4));
08002d98: ldr r3, [pc, #72] @ (0x8002de4 <main+256>)
08002d9a: ldr r3, [r3, #0]
142 __ASM volatile ("cpsid i" : : : "memory");
08002d9c: cpsid i
219 JumpToFirmware();
08002d9e: blx r3
223 for(;;);

 

Just before the blx call the registers are:

r0 1 
r1 128
r2 0x400 (Hex)
r3 0x8008225 (Hex)
r4 0x20002b78 (Hex)
r5 -1
r6 -1
r7 -1
r8 -1
r9 -1
r10 -1
r11 -1
r12 -134250496
sp 0x20007ff8
lr 134225065
pc 0x8002d9e <main+186>
xpsr -2130706432
msp 0x20007ff8
psp 0xfffffffc
primask 1
basepri 0
faultmask 0
control 0

After the blx call, the HardFault_Handler() is called. The internal registers are:

 

r0 536871108 
r1 536871112
r2 0x20002b78 (Hex)
r3 0x0 (Hex)
r4 0x20002b78 (Hex)
r5 -1
r6 -1
r7 -1
r8 -1
r9 -1
r10 -1
r11 -1
r12 -134250496
sp 0x20007fe0
lr -7
pc 0x80025c8 <HardFault_Handler>
xpsr 1627389955
msp 0x20007fe0
psp 0xfffffffc
primask 1
basepri 0
faultmask 0
control 0

 

At 0x8008225 there is the startup code:

08008225: ldr r0, [pc, #52] @ (0x800825c)
08008227: mov sp, r0
08008229: b.n 0x800822c
0800822b: nop
0800822d: ldr r0, [pc, #48] @ (0x8008260)
0800822f: ldr r1, [pc, #52] @ (0x8008264)
08008231: ldr r2, [pc, #52] @ (0x8008268)
08008233: movs r3, #0
08008235: b.n 0x800823c
08008237: ldr r4, [r2, r3]
08008239: str r4, [r0, r3]
0800823b: adds r3, #4
0800823d: adds r4, r0, r3
0800823f: cmp r4, r1
08008241: bcc.n 0x8008236
08008243: ldr r2, [pc, #40] @ (0x800826c)
08008245: ldr r4, [pc, #40] @ (0x8008270)
08008247: movs r3, #0
08008249: b.n 0x800824e
0800824b: str r3, [r2, #0]
0800824d: adds r2, #4
0800824f: cmp r2, r4
08008251: bcc.n 0x800824a

...

 

Anything out of place?

Not exactly, but the PC being in the HardFault Handler is not helpful, it's not the thing that actually faulted.

What you want to see is the PC in the stacked context. So dump stack at SP too

https://github.com/cturvey/RandomNinjaChef/blob/main/KeilHardFault.c

I don't have a CM0(+) GNU/GAS version of the handler to hand.

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

Dumping the stack helped to pin point a initialization error in the firmware code, not related to the actual bootloader -> firmware jump. It was some work, but it was a nice opportunity to learn the ins and outs of the STM32.

Thank you all for the invaluable help.

Gabriel