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

Turning on GCC optimizations prevents application from loading without debugger

Specs: SDK 14.1, nRF52832, S132

Env: Eclipse IDE, Linux

Hardware: Custom board

As the title explains, we've had no issues during development if the optimizations are set to -O0 -g. Once they are set to -O2, the program gets stuck somewhere during bootup. If I then use a nRF52 Development Kit and the JLink debugger, I am eventually able to get the program running. Without optimizations, the debugger immediately jumps to the beginning of main (as expected) and once I hit Start, everything runs as expected. With optimizations on, the debugger doesn't jump to main despite "running". Once I hit pause, I'm in a non-defined section of the program and I can only see disassembly as shown below.

I can consistently see that the program either halts at the ands.w or ldr.w instruction every time. If I then hit Continue, I'm brought to the beginning of main like nothing even happened. Starting the program from there allows everything to also work as expected. If I reset the device (using nrfjprog --reset) the program freezes again until I manually step through this first hiccup in the program using the debugger. For more detail, I'm using the secure BLE bootloader and the linker script shown below.

/* Linker script to configure memory regions. */

SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)

MEMORY
{
  FLASH (rx) : ORIGIN = 0x23000, LENGTH = 0x55000
  /* Original DFU ram configuration before modifying BLE sending rate */
  /* RAM (rwx) :  ORIGIN = 0x20002180, LENGTH = 0xde80 */
  
  RAM (rwx) : ORIGIN = 0x20004300, LENGTH = 0xBD00
}

SECTIONS
{
  . = ALIGN(4);
  .mem_section_dummy_ram :
  {
  }
  .log_dynamic_data :
  {
    PROVIDE(__start_log_dynamic_data = .);
    KEEP(*(.log_dynamic_data))
    PROVIDE(__stop_log_dynamic_data = .);
  } > RAM
  .fs_data :
  {
    PROVIDE(__start_fs_data = .);
    KEEP(*(.fs_data))
    PROVIDE(__stop_fs_data = .);
  } > RAM

} INSERT AFTER .data;

SECTIONS
{
  .mem_section_dummy_rom :
  {
  }
  .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
  .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(*(.log_const_data))
    PROVIDE(__stop_log_const_data = .);
  } > FLASH
    .svc_data :
  {
    PROVIDE(__start_svc_data = .);
    KEEP(*(.svc_data))
    PROVIDE(__stop_svc_data = .);
  } > FLASH
  .sdh_state_observers :
  {
    PROVIDE(__start_sdh_state_observers = .);
    KEEP(*(SORT(.sdh_state_observers*)))
    PROVIDE(__stop_sdh_state_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
  

} INSERT AFTER .text

INCLUDE "nrf5x_common.ld"

Because the program freezes before even getting into main, I feel like this program has something to do with the linker script/bootloader. Any help would be appreciated.

EDIT: Based on Turbo's comment, I wanted to step through the bootloader and see where exactly it was failing. I recompiled the bootloader with optimizations set to -O0 g3 and also needed to add -fomit-frame-pointer otherwise the linker would fail when compiling. I also modified the linker script for the bootloader as shown below:

  /*FLASH (rx) : ORIGIN = 0x78000, LENGTH = 0x6000*/
  FLASH (rx) : ORIGIN = 0x53000, LENGTH = 0x26000

After going through the same steps I described in the comment below, the program now runs as expected. I'm still really not sure what the problem is in this case because obviously changing these settings in the bootloader has fixed whatever was causing it to be stuck. But I've had to really reduce the space available for my application so this isn't really a solution.

EDIT2:

This problem seems to be linked to how the device is reset. If I reset the device using nrfjprog (i.e. nrfjprog -f nrf52 --reset), the device freezes in the manner described. If I completely disconnect power and then reconnect it, the device turns on immediately. And again, if I compile the bootloader with no optimizations, this problem also goes away. Still haven't figured out the root cause.

EDIT3:

The same program also occurs when trying to perform a buttonless DFU update. The device will hang initially and then after a power cycle it will run normally. As the device being worked on is in a case and is battery powered, power cycling every time isn't an option.

EDIT4:

I recompiled the project using the debug bootloader instead of the original bootloader with the optimizations turned off. This allowed me to view the debug messages of the bootloader. I don't know if this is part of the bug or not but I consistently get to a part of the code where the JLinkRTTClient just stops producing output and then if I hit enter, it says that there was a disconnection and it has reconnected. If I reset my device, I get no further output. I must power cycle the device in order to get output again. The output I see is as follows:

<info> nrf_sdh_soc: Inside main
<debug> nrf_sdh_soc: In nrf_bootloader_init
<debug> nrf_sdh_soc: in weak nrf_dfu_init_user
<debug> nrf_sdh_soc: In real nrf_dfu_init
<debug> mem_mngr: Running nrf_dfu_settings_init(sd_irq_initialized=false).
<debug> nrf_sdh_ble: Calling nrf_dfu_flash_init(sd_irq_initialized=false)...
<debug> nrf_sdh_ble: Initializing nrf_fstorage_nvmc backend.
<debug> nrf_sdh_soc: Initializing the clock.
<debug> nrf_sdh_soc: Enter nrf_dfu_continue
<debug> nrf_sdh_soc: Valid App
<debug> nrf_sdh_soc: Enter nrf_dfu_app_is_valid
<debug> nrf_sdh_soc: Return true. App was valid
<debug> nrf_sdh_soc: Enter nrf_dfu_app_is_valid
<debug> nrf_sdh_s

Parents
  • Hi Andrew,

    needed to add -fomit-frame-pointer otherwise the linker

    I did not realize that a compiler will force you to set the omit-frame-pointer option. In my head, it was the other way around, that you can set it, but the compiler will still decide to use and not use frame pointer allocations for functions necessary. I am not able to understand why a linker will force you to set this.

    FLASH (rx) : ORIGIN = 0x53000, LENGTH = 0x26000

    So the problem is not with the set of instructions produced but the data fetched. So there is high chance that your earlier flash settings were in conflict with some other module using the flash address between 0x78000 and (0x78000+LENGTH). 

    If it was a code overlap due to two linker script conflicts  (having memory segments too close to each other) then you should have seen problem when not using optimization, which would result in code size being a bit larger and possibly overflowing into next memory segment. 

    I would recommend to check all your memory segments in various linker scripts and also see if any part of your code has hardcoded memory address to the flash size in 0X78000 to 0x78000+LENGTH.

  • I'm not sure either honestly. I received the following error without that flag:

    ../../../../../components/libraries/bootloader/nrf_bootloader_app_start_asm.c: In function 'nrf_bootloader_app_start_impl':
    ../../../../../components/libraries/bootloader/nrf_bootloader_app_start_asm.c:129:1: error: r7 cannot be used in asm here
     }

    But that's neither here nor there at this point. I read that the memory locations for the bootloader needed to be modified slightly because the bootloader binary would be too big to fit in it's originally allocated memory space so I just arbitrarily made it bigger based on another post I saw. Here are the current memory configurations (that don't work):

    Bootloader:

      FLASH (rx) : ORIGIN = 0x78000, LENGTH = 0x6000
      RAM (rwx) :  ORIGIN = 0x20002830, LENGTH = 0xd7d0
      
      bootloader_settings_page (r) : ORIGIN = 0x0007F000, LENGTH = 0x1000
      uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4
      mbr_params_page (r) : ORIGIN = 0x0007E000, LENGTH = 0x1000
      uicr_mbr_params_page (r) : ORIGIN = 0x10001018, LENGTH = 0x4

    Application:

      FLASH (rx) : ORIGIN = 0x23000, LENGTH = 0x55000
      RAM (rwx) : ORIGIN = 0x20004300, LENGTH = 0xBD00

    The softdevice is S132. According to the documentation I could find, the S132 softdevice should occupy 0x01000 - 0x20000. This seems to contradict what the linker script sets for the secure ble bootloader example sets (0x23000 as shown above). I tried setting this back to 0x20000 but I get a merge conflict with mergehex so clearly they are overlapping.

Reply
  • I'm not sure either honestly. I received the following error without that flag:

    ../../../../../components/libraries/bootloader/nrf_bootloader_app_start_asm.c: In function 'nrf_bootloader_app_start_impl':
    ../../../../../components/libraries/bootloader/nrf_bootloader_app_start_asm.c:129:1: error: r7 cannot be used in asm here
     }

    But that's neither here nor there at this point. I read that the memory locations for the bootloader needed to be modified slightly because the bootloader binary would be too big to fit in it's originally allocated memory space so I just arbitrarily made it bigger based on another post I saw. Here are the current memory configurations (that don't work):

    Bootloader:

      FLASH (rx) : ORIGIN = 0x78000, LENGTH = 0x6000
      RAM (rwx) :  ORIGIN = 0x20002830, LENGTH = 0xd7d0
      
      bootloader_settings_page (r) : ORIGIN = 0x0007F000, LENGTH = 0x1000
      uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4
      mbr_params_page (r) : ORIGIN = 0x0007E000, LENGTH = 0x1000
      uicr_mbr_params_page (r) : ORIGIN = 0x10001018, LENGTH = 0x4

    Application:

      FLASH (rx) : ORIGIN = 0x23000, LENGTH = 0x55000
      RAM (rwx) : ORIGIN = 0x20004300, LENGTH = 0xBD00

    The softdevice is S132. According to the documentation I could find, the S132 softdevice should occupy 0x01000 - 0x20000. This seems to contradict what the linker script sets for the secure ble bootloader example sets (0x23000 as shown above). I tried setting this back to 0x20000 but I get a merge conflict with mergehex so clearly they are overlapping.

Children
Related