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

NRF52 doesn't start without debugger (Jlink) on GCC toolchain

Okay this got us going around in circles and it looks stupidly simple. It seems there is a knowledge gap since we saw many posts similar to ours but without clarity as of what to do in practice.

-- Problem statement:

Boards with NRF52 do not start when a debugger is not plugged to it. This is impossible to see if one is using a DK board. It might be a blind spot in the setup/info that the Nordic Team has worked on or something that everyone creating software with NRF52 will have to deal with. At any rate it would be great to get a sensible answer for the community.

-- Hardware/software setup:

  • The debugger is a JLink from Segger with all latest drivers. Works a treat.
  • Our toolchain is ARM GCC
  • We work on Mac (we're not perfect)
  • SDK 14.0
  • SD 132 v5.0.0

-- What we did:

Tested on Dev kit board (10040), since JLink is always attached to it, it works. Tested on 4(!) different versions of our custom board with Jlink debugger attached, works but when removing the debugger and power cycling, the NRF52 doesn't start at all (no BT, no test LED turning on, no test GPIO turning on, nothing).

-- What we are aware of:

Something called semihosting, which prevents the nrf52 from starting if there is no debugger attached to it. Seems like the most likely issue here. The thing is, there is nowhere we could find a semihosting config. Is it in the sdk_config.h? We couldn't find that info.

Linker file. We have one like everyone else and it's unclear if that could play a role. Unlikely since the board works well when attached with the debugger. here is the linker file just in case:

/* Linker script to configure memory regions. */

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

MEMORY
{
  FLASH (rx) : ORIGIN = 0x23000, LENGTH = 0x55000
  RAM (rwx) :  ORIGIN = 0x200020F0, LENGTH = 0xDF10 /*is normally 0xDF10*/
}

SECTIONS
{
  . = ALIGN(4);
  .svc_data :
  {
    PROVIDE(__start_svc_data = .);
    KEEP(*(.svc_data))
    PROVIDE(__stop_svc_data = .);
  } > RAM
  
  .fs_data :
  {
    PROVIDE(__start_fs_data = .);
    KEEP(*(.fs_data))
    PROVIDE(__stop_fs_data = .);
  } > RAM
   .log_dynamic_data :
  {
    PROVIDE(__start_log_dynamic_data = .);
    KEEP(*(.log_dynamic_data))
    PROVIDE(__stop_log_dynamic_data = .);
  } > RAM
  .cli_sorted_cmd_ptrs :
  {
    PROVIDE(__start_cli_sorted_cmd_ptrs = .);
    KEEP(*(.cli_sorted_cmd_ptrs))
    PROVIDE(__stop_cli_sorted_cmd_ptrs = .);
  } > RAM
} INSERT AFTER .data;

SECTIONS
{
  .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
  
  
  .cli_command :
  {
    PROVIDE(__start_cli_command = .);
    KEEP(*(.cli_command))
    PROVIDE(__stop_cli_command = .);
  } > 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

  .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
} INSERT AFTER .text

INCLUDE "nrf5x_common.ld"

Also here are the flags we use:

#================================================================
# Libraries common to all targets
LIB_FILES += \
  $(SDK_ROOT)/components/nfc/t2t_lib/nfc_t2t_lib_gcc.a


# Optimization flags
OPT = -O3 -g3
# Uncomment the line below to enable link time optimization
#OPT += -flto


# C flags common to all targets

CFLAGS += $(OPT)
CFLAGS += -DBL_SETTINGS_ACCESS_ONLY
#CFLAGS += -DCONFIG_GPIO_AS_PINRESET
CFLAGS += -DNRF52
CFLAGS += -DNRF52832_XXAA
CFLAGS += -DNRF52_PAN_74
CFLAGS += -DNRF_SD_BLE_API_VERSION=5
CFLAGS += -DS132
CFLAGS += -DSOFTDEVICE_PRESENT
CFLAGS += -DSWI_DISABLE0
CFLAGS += -mcpu=cortex-m4
CFLAGS += -mthumb -mabi=aapcs
CFLAGS +=  -Wall -Werror
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
# keep every function in a separate section, this allows linker to discard unused ones
CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
CFLAGS += -fno-builtin -fshort-enums 

#----------------------- PROJECT SPECIFIC --------------
CFLAGS += $(PROJECT_BOARD)
CFLAGS += $(NFC_DISABLE)
CFLAGS += $(LOGGING_MESSAGES)
CFLAGS += $(WHICH_TEST_TO_RUN)
CFLAGS += -DNRF_DFU_HW_VERSION=$(NRF_DFU_HW_VERSION)


# C++ flags common to all targets
CXXFLAGS += $(OPT)

# Assembler flags common to all targets
ASMFLAGS += -g3
ASMFLAGS += -mcpu=cortex-m4
ASMFLAGS += -mthumb -mabi=aapcs
ASMFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
ASMFLAGS += -DBL_SETTINGS_ACCESS_ONLY
#ASMFLAGS += -DCONFIG_GPIO_AS_PINRESET
ASMFLAGS += -DNRF52
ASMFLAGS += -DNRF52832_XXAA
ASMFLAGS += -DNRF52_PAN_74
ASMFLAGS += -DNRF_SD_BLE_API_VERSION=5
ASMFLAGS += -DS132
ASMFLAGS += -DSOFTDEVICE_PRESENT
ASMFLAGS += -DSWI_DISABLE0

#----------------------- PROJECT SPECIFIC --------------
ASMFLAGS += $(PROJECT_BOARD)
ASMFLAGS += $(NFC_DISABLE)
ASMFLAGS += -DNRF_DFU_HW_VERSION=$(NRF_DFU_HW_VERSION)



# Linker flags
LDFLAGS += $(OPT)
LDFLAGS += -mthumb -mabi=aapcs -L $(TEMPLATE_PATH) -T$(LINKER_SCRIPT)
LDFLAGS += -mcpu=cortex-m4
LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
# let linker to dump unused sections
LDFLAGS += -Wl,--gc-sections

# use newlib in nano version
#SDK13 was like thatLDFLAGS += --specs=nano.specs -lc -lnosys
LDFLAGS += --specs=nano.specs 


# Add standard libraries at the very end of the linker input, after all objects
# that may need symbols provided by these libraries.
LIB_FILES += -lc -lnosys -lm

Anyone could articulate a reason and a solution for this behavior? We sorted all the shenanigans like size of RAM, hardware failure etc... We are completely stuck.

Related