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

IAR to GCC porting issue with debugging the code

I ported an existing application(modified from SDK 15.2.0) from IAR compiler to GCC compiler in windows environment. I used the SEGGER SES for final linking using the default flash_placement.xml file. During the linking I provided the entry point as 'Reset_Handler'. The compiling and linking was successful, but when I flashed the program to controller, its stuck in Soft device Flash address range.(I have pre-loaded the S132 soft device hex file). 

I can see that the Reset handler function is getting called and then nRFInitialize, followed by SystemInit() in system_nrf52.c file. In this function while executing errata_12() function, it jumps soft device address range and then stays there. Before and after screenshots below:

Before:

After: 

And stuck in this line:

Need assistance for the startup sequence to jump to application main.

Also Need further information as to

1. How the startup sequence works in nRF52832 device? Whats the reset address?
2. How the Soft device software handles the startup sequence and how it jumps to address of 'Reset_handler' function when this address value can be dynamic?
3. As I am compiling my code in GCC does this affect the precompiled soft device software? How do I compile soft device in GCC too? Can I get its symbol file(.elf/.out) so that I can debug my code?

Parents
  • Here is an example on how a flash_placement.xml file in SDK 15.2 looks like (from ble_app_beacon example):

    <!DOCTYPE Linker_Placement_File>
    <Root name="Flash Section Placement">
      <MemorySegment name="FLASH" start="$(FLASH_PH_START)" size="$(FLASH_PH_SIZE)">
        <ProgramSection load="no" name=".reserved_flash" start="$(FLASH_PH_START)" size="$(FLASH_START)-$(FLASH_PH_START)" />
        <ProgramSection alignment="0x100" load="Yes" name=".vectors" start="$(FLASH_START)" />
        <ProgramSection alignment="4" load="Yes" name=".init" />
        <ProgramSection alignment="4" load="Yes" name=".init_rodata" />
        <ProgramSection alignment="4" load="Yes" name=".text" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_soc_observers" inputsections="*(SORT(.sdh_soc_observers*))" address_symbol="__start_sdh_soc_observers" end_symbol="__stop_sdh_soc_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_ble_observers" inputsections="*(SORT(.sdh_ble_observers*))" address_symbol="__start_sdh_ble_observers" end_symbol="__stop_sdh_ble_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".pwr_mgmt_data" inputsections="*(SORT(.pwr_mgmt_data*))" address_symbol="__start_pwr_mgmt_data" end_symbol="__stop_pwr_mgmt_data" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_stack_observers" inputsections="*(SORT(.sdh_stack_observers*))" address_symbol="__start_sdh_stack_observers" end_symbol="__stop_sdh_stack_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_req_observers" inputsections="*(SORT(.sdh_req_observers*))" address_symbol="__start_sdh_req_observers" end_symbol="__stop_sdh_req_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_state_observers" inputsections="*(SORT(.sdh_state_observers*))" address_symbol="__start_sdh_state_observers" end_symbol="__stop_sdh_state_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".nrf_queue" inputsections="*(.nrf_queue*)" address_symbol="__start_nrf_queue" end_symbol="__stop_nrf_queue" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".nrf_balloc" inputsections="*(.nrf_balloc*)" address_symbol="__start_nrf_balloc" end_symbol="__stop_nrf_balloc" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".cli_command" inputsections="*(.cli_command*)" address_symbol="__start_cli_command" end_symbol="__stop_cli_command" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".crypto_data" inputsections="*(SORT(.crypto_data*))" address_symbol="__start_crypto_data" end_symbol="__stop_crypto_data" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_const_data" inputsections="*(SORT(.log_const_data*))" address_symbol="__start_log_const_data" end_symbol="__stop_log_const_data" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_backends" inputsections="*(SORT(.log_backends*))" address_symbol="__start_log_backends" end_symbol="__stop_log_backends" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections" address_symbol="__start_nrf_sections" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".cli_sorted_cmd_ptrs"  inputsections="*(.cli_sorted_cmd_ptrs*)" runin=".cli_sorted_cmd_ptrs_run"/>
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".fs_data"  inputsections="*(.fs_data*)" runin=".fs_data_run"/>
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_dynamic_data"  inputsections="*(SORT(.log_dynamic_data*))" runin=".log_dynamic_data_run"/>
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_filter_data"  inputsections="*(SORT(.log_filter_data*))" runin=".log_filter_data_run"/>
        <ProgramSection alignment="4" load="Yes" name=".dtors" />
        <ProgramSection alignment="4" load="Yes" name=".ctors" />
        <ProgramSection alignment="4" load="Yes" name=".rodata" />
        <ProgramSection alignment="4" load="Yes" name=".ARM.exidx" address_symbol="__exidx_start" end_symbol="__exidx_end" />
        <ProgramSection alignment="4" load="Yes" runin=".fast_run" name=".fast" />
        <ProgramSection alignment="4" load="Yes" runin=".data_run" name=".data" />
        <ProgramSection alignment="4" load="Yes" runin=".tdata_run" name=".tdata" />
      </MemorySegment>
      <MemorySegment name="RAM" start="$(RAM_PH_START)" size="$(RAM_PH_SIZE)">
        <ProgramSection load="no" name=".reserved_ram" start="$(RAM_PH_START)" size="$(RAM_START)-$(RAM_PH_START)" />
        <ProgramSection alignment="0x100" load="No" name=".vectors_ram" start="$(RAM_START)" address_symbol="__app_ram_start__"/>
        <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections_run" address_symbol="__start_nrf_sections_run" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".cli_sorted_cmd_ptrs_run" address_symbol="__start_cli_sorted_cmd_ptrs" end_symbol="__stop_cli_sorted_cmd_ptrs" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".fs_data_run" address_symbol="__start_fs_data" end_symbol="__stop_fs_data" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".log_dynamic_data_run" address_symbol="__start_log_dynamic_data" end_symbol="__stop_log_dynamic_data" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".log_filter_data_run" address_symbol="__start_log_filter_data" end_symbol="__stop_log_filter_data" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections_run_end" address_symbol="__end_nrf_sections_run" />
        <ProgramSection alignment="4" load="No" name=".fast_run" />
        <ProgramSection alignment="4" load="No" name=".data_run" />
        <ProgramSection alignment="4" load="No" name=".tdata_run" />
        <ProgramSection alignment="4" load="No" name=".bss" />
        <ProgramSection alignment="4" load="No" name=".tbss" />
        <ProgramSection alignment="4" load="No" name=".non_init" />
        <ProgramSection alignment="4" size="__HEAPSIZE__" load="No" name=".heap" />
        <ProgramSection alignment="8" size="__STACKSIZE__" load="No" place_from_segment_end="Yes" name=".stack"  address_symbol="__StackLimit" end_symbol="__StackTop"/>
        <ProgramSection alignment="8" size="__STACKSIZE_PROCESS__" load="No" name=".stack_process" />
      </MemorySegment>
    </Root>
    

    and in the SES project file(.emProject) we have the following,

    snippet:

          linker_section_placement_file="flash_placement.xml"
          linker_section_placement_macros="FLASH_PH_START=0x0;FLASH_PH_SIZE=0x80000;RAM_PH_START=0x20000000;RAM_PH_SIZE=0x10000;FLASH_START=0x26000;FLASH_SIZE=0x5a000;RAM_START=0x200018a8;RAM_SIZE=0xe758"
          linker_section_placements_segments="FLASH RX 0x0 0x80000;RAM RWX 0x20000000 0x10000"

  • Thank you. This worked but now during BLE stack initialization, it goes into svc handler. Screenshot below. Can you help me?

  • Yes its flashed. I use the soft device to flash the s132 soft device hex file. 

    Note: When I flash the IAR compiled hex, it works but when I flash the GCC/SES compiled it doesn't. Stuck now as per screenshot above. 

  • Have you added the necessary preprocessor defines ?

    (Click on image to make it bigger)

  • Below is the config based on our application. 

  • Looks like you are missing the NO_VTOR_CONFIG (This definition tells SES to expect a SoftDevice to be present that will forward exceptions and interrupts to the application.)

  • How this is handled in IAR? Do I have any Macros that is set for IAR to inform about the soft device?

Reply Children
  • Well, in IAR you have this __ICFEDIT_intvec_start__ define in the .icf file, and we also have this --drv_vector_table_base=0x0 under debugger option.

  • Okay. Thank you. The solution is working now.

    Few questions as mentioned initially.
    1. How the startup sequence works in nRF52832 device? Whats the reset address?
    2. How the Soft device software handles the startup sequence and how it jumps to address of 'Reset_handler' function?

  • The start-up behavior is defined by the ARM Cortex-M4 CPU design. I recommend having this manual in addition to the Nordic nRF52832 product spec handy:

    http://infocenter.arm.com/help/topic/com.arm.doc.dui0553b/DUI0553.pdf

    Refer to the vector table description in section 2.3.4. You'll see that the first few words are the initial stack pointer value and the reset vector.

    The default vector table location at CPU power-up or reset is at address 0x0, which is in the flash. At power-on or reset, the CPU will load the SP register with the "Initial SP value" (offset 0x00000000) and load the program counter (PC) register with the "Reset" value (offset 0x00000004). The CPU will jump to that address and begin execution.

    Subsequent fields are used for other exception vectors. The first 16 slots in the vector table are reserved for exceptions that are related to the ARM CPU itself. This includes NMI, faults, system call handler and the systick timer interrupt. (All ARM CPUs have one built in systick timer.) All vectors after that are vendor-specific. For the Nordic chip, this means the radio, UARTs, SPI, I2C, RTC and all other peripheral devices. (This is how it works in the ARM SoC works: ARM designs the CPU core, the SoC vendor designs everything else and puts everything together.)

    You'll notice that the vector addresses (not including the SP value) are all odd numbers (i.e. the LSB is set) even though the actual handler is at an even numbered address. With ARM, all instructions are either 2 bytes (thumb mode) or 4 bytes (ARM mode). This means that the LSB is never used for address decoding. Instead it's used to indicate if the target address contains thumb mode code or ARM mode code. Setting the LSB means thumb mode.

    So if the reset vector address is 0xA81, that means the actual code starts at addres 0xA80, and it's thumb mode code.

    If you create an application which does not use the SoftDevice, then you can store your code starting at address 0x0 in the flash and the vector table in your code will control everything.

    When you use the SoftDevice, then it goes at offset 0x0 instead. Your application goes somewhere else. With the latest S140 SoftDevice, that somewhere else is 0x26000. So your vector table ends up at 0x26000 instead of 0x0. The SoftDevice actually captures all exception events. Some it handles itself (like the radio interrupt), while others it will forward to the application. The idea is that the application code doesn't really know that any of this is happening. The only thing that changes between these two cases is that the linker script puts your application's vector table at 0x26000 instead of 0x0.

    This adds a little latency to interrupt processing because a bit of SoftDevice code is executed before it jumps to your own handler, but this is kept as small as possible.

    The Cortex-M4 processor also has a Vector Table Offset Register (VTOR). You can actually use this to move the vector table to another location, i.e. make the CPU use a base address other than 0x0 when jumping to an exception handler. This has to be set by software though: you always have to have the initial vector table with (at bare minimum) the reset vector and stack pointer at address 0x0 in order for the CPU to boot correctly, and then you can have your code move it later.

    With the SoftDevice in place, the CPU reaches the SoftDevice's reset handler first. Actually, it reaches the boot block -- the SoftDevice .hex file actually has the boot block at address 0x0 and the SoftDevice starting at 0x1000. The boot block will get control of the CPU first, and then eventually it will branch to the reset vector at 0x26004, which passes control to your application's reset vector. (Nordic doesn't distribute the source code for this, so there's no way to know exactly what it does.)

    -Bill

Related