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.

  • No success. I've created a hybrid linker file with the correct flash and RAM addresses/sizes, but my app still doesn't work. If the very same app is linked with the linker file without extra sections, it's okay.

    Here's the correct linker file:

    /* Linker script to configure memory regions. */
    
    SEARCH_DIR(.)
    GROUP(-lgcc -lc -lnosys)
    
    MEMORY
    {
      FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0x5a000
      RAM (rwx) :  ORIGIN = 0x20001628, LENGTH = 0xe9d8
    }
    
    SECTIONS
    {
    }
    
    SECTIONS
    {
      . = ALIGN(4);
      .mem_section_dummy_ram :
      {
      }
    
    } INSERT AFTER .data;
    
    SECTIONS
    {
      .mem_section_dummy_rom :
      {
      }
    
    } INSERT AFTER .text
    
    INCLUDE "nrf_common.ld"

    And here's the wrong. As you can see, I've just added the extra sections, but it caused some troubles.

    /* Linker script to configure memory regions. */
    
    SEARCH_DIR(.)
    GROUP(-lgcc -lc -lnosys)
    
    MEMORY
    {
      FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0x5a000
      RAM (rwx) :  ORIGIN = 0x20001628, LENGTH = 0xe9d8
    }
    
    SECTIONS
    {
    }
    
    SECTIONS
    {
      . = ALIGN(4);
      .mem_section_dummy_ram :
      {
      }
      .cli_sorted_cmd_ptrs :
      {
        PROVIDE(__start_cli_sorted_cmd_ptrs = .);
        KEEP(*(.cli_sorted_cmd_ptrs))
        PROVIDE(__stop_cli_sorted_cmd_ptrs = .);
      } > RAM
      .fs_data :
      {
        PROVIDE(__start_fs_data = .);
        KEEP(*(.fs_data))
        PROVIDE(__stop_fs_data = .);
      } > RAM
      .log_dynamic_data :
      {
        PROVIDE(__start_log_dynamic_data = .);
        KEEP(*(SORT(.log_dynamic_data*)))
        PROVIDE(__stop_log_dynamic_data = .);
      } > RAM
      .log_filter_data :
      {
        PROVIDE(__start_log_filter_data = .);
        KEEP(*(SORT(.log_filter_data*)))
        PROVIDE(__stop_log_filter_data = .);
      } > RAM
    
    } INSERT AFTER .data;
    
    SECTIONS
    {
      .mem_section_dummy_rom :
      {
      }
      .sdh_ant_observers :
      {
        PROVIDE(__start_sdh_ant_observers = .);
        KEEP(*(SORT(.sdh_ant_observers*)))
        PROVIDE(__stop_sdh_ant_observers = .);
      } > FLASH
      .sdh_ble_observers :
      {
        PROVIDE(__start_sdh_ble_observers = .);
        KEEP(*(SORT(.sdh_ble_observers*)))
        PROVIDE(__stop_sdh_ble_observers = .);
      } > FLASH
      .sdh_soc_observers :
      {
        PROVIDE(__start_sdh_soc_observers = .);
        KEEP(*(SORT(.sdh_soc_observers*)))
        PROVIDE(__stop_sdh_soc_observers = .);
      } > FLASH
      .sdh_stack_observers :
      {
        PROVIDE(__start_sdh_stack_observers = .);
        KEEP(*(SORT(.sdh_stack_observers*)))
        PROVIDE(__stop_sdh_stack_observers = .);
      } > FLASH
      .sdh_req_observers :
      {
        PROVIDE(__start_sdh_req_observers = .);
        KEEP(*(SORT(.sdh_req_observers*)))
        PROVIDE(__stop_sdh_req_observers = .);
      } > FLASH
      .sdh_state_observers :
      {
        PROVIDE(__start_sdh_state_observers = .);
        KEEP(*(SORT(.sdh_state_observers*)))
        PROVIDE(__stop_sdh_state_observers = .);
      } > FLASH
        .nrf_queue :
      {
        PROVIDE(__start_nrf_queue = .);
        KEEP(*(.nrf_queue))
        PROVIDE(__stop_nrf_queue = .);
      } > FLASH
        .nrf_balloc :
      {
        PROVIDE(__start_nrf_balloc = .);
        KEEP(*(.nrf_balloc))
        PROVIDE(__stop_nrf_balloc = .);
      } > FLASH
        .cli_command :
      {
        PROVIDE(__start_cli_command = .);
        KEEP(*(.cli_command))
        PROVIDE(__stop_cli_command = .);
      } > FLASH
      .crypto_data :
      {
        PROVIDE(__start_crypto_data = .);
        KEEP(*(SORT(.crypto_data*)))
        PROVIDE(__stop_crypto_data = .);
      } > FLASH
      .pwr_mgmt_data :
      {
        PROVIDE(__start_pwr_mgmt_data = .);
        KEEP(*(SORT(.pwr_mgmt_data*)))
        PROVIDE(__stop_pwr_mgmt_data = .);
      } > FLASH
      .log_const_data :
      {
        PROVIDE(__start_log_const_data = .);
        KEEP(*(SORT(.log_const_data*)))
        PROVIDE(__stop_log_const_data = .);
      } > FLASH
      .log_backends :
      {
        PROVIDE(__start_log_backends = .);
        KEEP(*(SORT(.log_backends*)))
        PROVIDE(__stop_log_backends = .);
      } > FLASH
    
    } INSERT AFTER .text
    
    INCLUDE "nrf_common.ld"

    I'll check whether my compile flags are correct. Perhaps another SDK version would also suit...

  • I've got it. My compile flags are bit different than the flags in the SDK, but in general this doesn't cause any issue, except for a linker flag:

    -Wl,--start-group

    After uncommenting this (and using the proper linker file above) the app began working.

  • Hi.

    The flash address is correct for S132 V6.1.0. The ram address should not have any impact on the starting of the application. If it is wrong, then you might experience a memory corruption very quickly. Are you sure that the value you have set for the RAM start address is correct? It seems quite low (i.e. the lowest possible value), and it could be that you application is starting but gets a corrupted memory very quickly. If you are using a number of features in the SoftDevice, then the RAM start address should be higher.

    For example, take a look at the linker script for the ble_app_blinky example:

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

    The blinky example uses for example RTC0, TIMER0, Radio, ECB, and LF clock, which all requires the SoftDevice.

    Therefore the RAM start address is set much higher than the lowest value.

    Best regards,

    Andreas

Reply
  • Hi.

    The flash address is correct for S132 V6.1.0. The ram address should not have any impact on the starting of the application. If it is wrong, then you might experience a memory corruption very quickly. Are you sure that the value you have set for the RAM start address is correct? It seems quite low (i.e. the lowest possible value), and it could be that you application is starting but gets a corrupted memory very quickly. If you are using a number of features in the SoftDevice, then the RAM start address should be higher.

    For example, take a look at the linker script for the ble_app_blinky example:

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

    The blinky example uses for example RTC0, TIMER0, Radio, ECB, and LF clock, which all requires the SoftDevice.

    Therefore the RAM start address is set much higher than the lowest value.

    Best regards,

    Andreas

Children
Related