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

linker script and HardFault

Hi all!

I want to use the BLE stack by Nordic. I figured out that S132 is the appropriate HEX image for nRF52832. I can burn the softdevice into flash with nrjftool.

An application should also run and provide BLE features later. There are multiple linker scripts in the SDK:

  1. if SDK_DIR/components/softdevice/s132/toolchain/armgcc/armgcc_s132_nrf52832_xxaa.ld is selected for linking, my application begins running after burn, as expected;
  2. if SDK_DIR/config/nrf52832/armgcc/generic_gcc_nrf52.ld is selected, my application doesn't run, it's in an endless HardFault loop;

I'd be quite satisfied with 1), but BLE functions demand the compilation of many C files from the SDK, and some of them require section variables. Linker script #1 doesn't support section variables, so linker script #2 must be used instead. But the final application doesn't run. I've tried with other linker files from the examples directory, without any success.

SDK version is nRF5_SDK_15.2.0_9412b96. I'm using a custom build system.

What could go wrong?

Parents
  • If you're using a custom application with no SoftDevice (and no bootloader), then your application code is expected to be placed at address 0x0 in the flash.

    But when using the S132 SoftDevice, the MBR and SoftDevice take up a portion of the flash starting from address 0, and user application code is expected to start at a specific offset in flash _after_ the SoftDevice. The exact offset varies slightly depending on the SoftDevice release, but it's always documented in the SoftDevice release notes. It also has to be included in the linker script when linking your application code.

    In the first script file you mention, it says this:

    MEMORY
    {
    FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0x5a000
    RAM (rwx) : ORIGIN = 0x200014b8, LENGTH = 0xeb48
    }

    But in the second it says this:

    MEMORY
    {
    FLASH (rx) : ORIGIN = 0x2d000, LENGTH = 0x53000
    RAM (rwx) : ORIGIN = 0x20001f30, LENGTH = 0xe0d0
    }

    I happen to know that 0x26000 is the correct application offset address for the S132 SoftDevice (and coincidentally also for the S140 SoftDevice). The start-up code in the MBR, which is the first thing to run when you boot the CPU, expects the application code to be located at 0x26000, so after a little bit of set-up it will try to jump there. If you use the second script, your application won't be there: it will be at 0x2d000 instead. So when the CPU branches to 0x26000 there will be just 0xFF bytes there, and the CPU will interpret them as illegal instructions and you'll end up in the HardFault handler.

    The RAM definition is also important, because some of the RAM must also be reserved for use by the SoftDevice once it's been enabled. Exactly how much RAM has to be reserved depends a little bit on exactly what BLE features you use, and other things like how many simultaneous connections you want to support. Some of the SoftDevice APIs will return an error if you don't reserve enough RAM -- they also indicate how much RAM should be available which tells you how to adjust things.

    So if you want to use the second script with the SoftDevice, you have to adjust the FLASH and RAM definitions accordingly. You can try just copying the entries from the first script into the second one and see if that at least gets your application to start up.

  • Thanks for the answer, it's all clear to me. I've already figured out that the app start address is different in the mentioned linker files and created a new linker file with the correct start address (0x26000), but it again failed to execute correctly. Maybe I did something wrong, I'll give it a next try and share the results here.

  • Make sure you adjust the length too. (It should be 512KB - 0x26000, i.e. 0x5A000.)

    I would use the debugger to set a breakpoint at 0x26000 and then launch the target and see if it gets there. This will at least tell you if the start-up code is doing the right thing. If the breakpoint doesn't trigger, then something is going wrong before even reaching your application. If the breakpoint does trigger, then dump what's at 0x26000 to see if it looks like valid code and try single-stepping to see where it goes wrong.

  • Good idea. I'll try all your recommendations on the next week (I'm out of office at the moment) and reflect.

Reply Children
No Data
Related