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

Related