This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF bootloader runs into HardFault

I'd like to run a softdevice application with OTA support on a RIGADO BMD-200 Evaluation board. I've successfully flashed the softdevice, the app, and the rigado bootloader, with rigado's program.py from the rigado bootloader-tools.

Now I want to switch to the open source nrf bootloader, so I've taken the example from nrf SDK (nRF51_SDK_9.0.0/examples/dfu/bootloader), and succesfully compiled it in eclipse, with rigado's costum_board.h. Then I start to use a linux implementation of nrfjprog to erease, flash softdevice and flash the bootloader example. This program is recommeded in the example. During debugging in eclipse I saw, that the program always stucks in the hardfault handler. I've already checked the bootloader starting address in the UICR, it's OK (10001014 = 0003C000).

After that I tried to flash the nrf bootloader with jlink, but the result HardFault again. Then I left out the debugger from the test, so I wrote 3 led switcher functions (red, blue, green), and call them in the startup.s file. For example red led switcher in the HardFault handler in the gcc_startup_nrf51.S file looks like this :

...    
HardFault_Handler:
        LDR     R0, =ledRed
        BX      R0
        B      .
...

The led enabling c function in main.c:

void ledRed(void){
    	LEDS_CONFIGURE(LEDS_MASK);
    	LEDS_ON(1 << LED_RED);
}

These led switcher functions only work when Os optimisation is set. (Why?)

With this kind of led debug I find out that that the program runs till

LDR     R0, =SystemInit
BLX     R0

lines in the gcc_startup_nrf51.S. When the program counter reaches this call, it causes a HardFault.

When I use -O0 optimisation I get the following message from the c compiler:

In function 'bootloader_util_reset':
../src_nordic/bootloader_util.c:106:1: error: r7 cannot be used in asm here

With -fomit-frame-pointer switch I can compile, but I don't know the proper meaning of the switch. However the led-s do not lights up with -O0, -O1, -O2, or -O3 optimisation setup, only with -Os. An other interesting thing: when I call the led functions in the asm code with BX insead of BLX I always get a HardFault after the led switch on.

I'm using the next setups in the project:

Project defines (for c com and assembler): SWI_DISABLE0 BOARD_PCA10028 SOFTDEVICE_PRESENT NRF51 S110 __HEAP_SIZE=0 BLE_STACK_SUPPORT_REQD.
Assembler options:-x assembler-with-cpp (and upper defines and include paths). C compiler options: -std=gnu99 -Wall -Werror (and upper defines and include paths).
Linker options: --specs=nano.specs -lc -lnosys -Xlinker --gc-sections (and linker script include path from the example)What does nosys option do?
Target options: cortex-m0, armv6-m.
Thumb Debug level: none (I'm debugging with leds now.)

I'm using Eclipse Kepler SR2, nRF51_SDK_9.0.0, with softdevice 8.0.0, SEGGER J-Link Commander V5.02c, arm-none-eabi-gcc v4.8.3, on kubuntu 14.04.

So after this long description, my main question is: why the program can't get in the main function? Have anyone seen similar problem before? Thank you for the help in advance.

  • It seems like a older version of the BMD-200 board was delivered with a older nRF51 revision, and with only 16 kB of RAM. Can you check which variant you have? If you have a revision 3 silicon with 32 kB of RAM I would expect the bootloader example from the SDK to work without any issues.

  • Thank you for the comment. Yes, I have an older (Rev A) version of BMD-200 on the eval kit, with 16 kB of RAM. And yes, I've made this mistake, I didn't modify the RAM setup in the linker file. One of my friends helps me to solve this problem. I going to write the solution in the answer section.

  • Hi, I have a answer to my question, thanks to one of my friend:

    I've a Rev A version of BMD-200 on my eval board with 16K RAM (as Einar Thorsrud assumed). I forgot to modify the RAM size and origin in the linker script. The new RAM setup is:

    RAM (rwx) :  ORIGIN = 0x20003000, LENGTH = 0x0fff.
    

    Also there was a problem with the stack pointer. It was not initialised in the startup file, so now I do it in the begining of the Reset_Handler:

    ldr   r0, =__StackTop
    mov   sp, r0
    

    The __StackTop variable is calculated in the gcc_nrf51_common.ld file:

     __StackTop = ORIGIN(RAM) + LENGTH(RAM);
    

    I also reduced the Stack_Size from 2048 to 800.

    My friend have solved the problem of BX and BLX instructions too. BX has no link, so the the PC is lost during the function call. We only need the BL instruction, because it saves the PC before the call, and it can restrore the PC after the function returns. BLX something similar to BL, but we don't need that. The new main call in the startup file:

    .LC0:
        BL     SystemInit
        BL      _start
    

    Now the bootloader starts. (But I have new problems to debug:)

  • Thank you for taking the time and sharing the answer, liszi.

  • I was having identical symptoms to liszi, but a different fix.

    My setup:

    • PCA10036 devkit with a 2015.40 stamp on it.
    • Used ARM GCC toolchain to compile the blinky app from the 12.0 SDK (it was originally for PCA10040, but I changed all references to PCA10036)
    • When I used keil to flash the devkit with the exact same blinky code, it worked. When I used make flash to do it, the thing would never boot
    • So I debugged with jlink, stepping one instruction at a time, and found that the bl SystemInit in gcc_startup_nrf52.s seemed to cause it to go to hardfault.

    My fix:

    • Stop using my ancient devkit. I have a bunch of BMD-300s, so I programmed one of those and the exact same .hex that had been hardfaulting on the devkit worked.

    Implied root causes:

    1. Devkit was ancient
    2. .hex was being compiled for the wrong CPU revision (seems unlikely to me, because Keil was still able to make a working .hex)
Related