Skip to main content
Visitor II
September 5, 2024
Solved

Hard fault on blx instruction - STM32F091CBU6

  • September 5, 2024
  • 3 replies
  • 2064 views

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

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

    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.

    3 replies

    Visitor II
    September 5, 2024

    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.

    GCalinAuthor
    Visitor II
    September 5, 2024

    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?

    Super User
    September 5, 2024

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

    GCalinAuthor
    Visitor II
    September 5, 2024

    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.

    Graduate II
    September 5, 2024

    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

    GCalinAuthor
    Visitor II
    September 5, 2024

    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?

    Graduate II
    September 5, 2024

    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.