Allowing debugger access to nRF5340

After an nRF5340 executes a power-on, brown-out, watchdog timer, or pin reset it is not automatically accessible to debug probes. This is true even if the nRF5340's memory is completely blank --i.e. no settings have been written to the device to disable the debugger-- because Access Port Protection APPROTECT requires firmware on the nRF5340 to explicitly enable debugger access every time the device starts up. This action must be performed independently on both cores.

A simple procedure is used to allow debugger access to a core in case a reset is executed before firmware has been programmed to keep the device "unlocked":

  1. Perform an ERASEALL via the CTRL-AP
  2. Program the required firmware before a reset is executed

The nrfjprog --recover operation handles both of these steps automatically. If nrfjprog isn't an option --or isn't practical for some reason-- then the steps can be done manually.

Performing an ERASEALL

The nRF5340 DK has an onboard J-Link so Segger's JLink utility is a convenient way to demonstrate how to interact with the CTRL-AP over SWD. Two Debug Port (DP) registers need to be introduced first:

CTRL/STATE DP

Setting the CSYSPWRUPREQ and CDBGPWRUPREQ bits in the CTRL/STAT DP powers up the device's debugger interface.

The APSEL field in the SELECT DP selects between the four possible Access Ports. The APBANKSEL is used to specify the most-significant four bits of the register address in the AP that you are accessing.

Only three JLink commands are required and they are all named intuitively:

  1. SWDWriteDP [ADDRESS] [VALUE]
  2. SWDReadAP [ADDRESS]
  3. SWDWriteAP [ADDRESS] [VALUE]

But there are two tricky things to remember:

  1. The ADDRESS parameter is automatically shifted left by two bits; Entering "SWDReadAP 1" is interpreted as "SWDReadAP 100b" or "SWDReadAP 4".
  2. The first invocation of SWDReadAP returns stale data so it is typically called at least twice.

The JLink utility is installed along with the Segger J-Link drivers (on Linux it is named JLinkExe). First plug an nRF5340 DK into the PC and launch the JLink utility. Then select the SWD interface:

Next the debug interface must be powered up:

The Identification Register (IDR) of one or more APs can be read as a sanity check. The first two APs should identify as Arm's AHB-AP (0x84770001) and the next two as Nordic's CTRL-AP (0x12880000). The SELECT DP's address is 8 (2<<2) and the IDR register's address is 0xFC (0xF<<4 | 3<<2). This is the application core's IDR:

Next, the application core's ERASEALL operation can be executed by writing 1 to register 4 (1<<2):

When ERASEALLSTATUS (2<<2) reads zero then the operation is complete:

The same procedure can be used on the network core by substituting the index of its AP for the application core's AP:

At this point the nRF5340 will remain accessible to the debugger until it is reset. Programming firmware to the cores can be done immediately without closing the JLink utility:

The firmware

Applications that are built using NCS tag v1.4.99-dev1 or newer include a function that takes care of setting up the APPROTECT registers. Currently this is done in system_nrf53_approtect.h and the device remains unlocked by default unless either ENABLE_APPROTECT or ENABLE_APPROTECT_USER_HANDLING was defined as a preprocesor symbol during compilation. This means that a simple application that contains only an infinite loop in main() can be programmed to a core to keep it unlocked. Note that the unlock firmware must be compiled separately for each core, however. An example project is attached to this post.

approtect.zip