Debugging nRF52 series devices using Trace

#Why use trace

"Embedded Trace Macrocell (ETM) allows to capture information on the processor’s state without affecting the processor’s performance. Microcontrollers that include an ETM allow detailed program execution to be recorded and saved in real time. This information can be used to analyze program flow and execution time, perform profiling and locate software bugs that are otherwise very hard to locate. A typical situation in which code trace is extremely valuable, is to find out how and why a "program crash" occurred in case of a runaway program count." J-Link/J-Trace User Guide.


Debugging features can be classified into two groups.

  1. Invasive debugging (i.e. program halt and stepping, HW breakpoints, etc...)
  2. Noninvasive debugging (i.e. memory access, trace, profiling)

Tracing is a form of Noninvasive debugging, and on nRF52 series devices there are three types of trace sources:

  • Instruction trace: Generated by the Embedded Trace Macrocell (ETM).
  • Data trace: Generated by the Data Watchpoint and Trace (DWT) unit.
  • Debug message: Generated by ITM, provides message output such as printf in the debugger GUI.

The trace information is connected to the Trace Port Interface Unit (TPIU) and exported to external trace hardware (i.e. SEGGER's j-Trace external debugger).

IMPORTANT: To use trace you need to have an external debugger that supports trace (trace won't work using the on-board debugger on our development kits). (see debug probes with built-in trace memory). IAR and ULink also offer debuggers that support trace and work with our devices.

#Embedded Trace Macrocell (ETM)

ETM allows you to observe how your software executes on the target device. ETM will be useful when debugging and optimizing your embedded system. When using conventional debug techniques there are some disadvantages: intrusive (behavior of the system is changed), non real-time, and no performance visibility. With trace, instruction and/or data transfer is collected and delivered off-chip in real-time (or stored on-chip for post processing).

Main benefits of ETM:

  • Trace and debug your system executing in real-time.
  • Collect vital timing on program execution for performance optimizations and ‘always-in-time’ code verification.
  • Capture program activity around the event you want to look at.

#Setting up and using ETM

  1. Connect debugger (with trace functionality) to target device, making sure trace pins are connected (see which GPIOs are trace pins here: Note that we have a custom board to make this easy but you will have to figure something else out.

The connector board schematic.

image description

  1. Make sure you have up-to-date startup files and define ENABLE_TRACE in your project's preprocessor definitions. When this is defined trace functionality will be enabled in system_nrf52.c as seen in the screen shot below.

image description

  1. Configure ETM in your Debug Settings as in the screen shot below. More info here:

image description

  1. Start the debugging session and open the Instruction Trace Window or the trace window of your choice.

image description

From here just play around, see what trace is all about, and post what you find/any questions/concerns you may have in the comments!

#Conclusion I'm no expert here, so please share your experiences with trace. How has it been useful? What else could be said about trace? Feel free to offer suggestions about how I can improve this post either in the comments or a PM.

  • Marten Kristiansen were you able to find out why Ozone fails?

  • jev were you able to resolve the issue of Ozone stopping on Bluetooth Connect? I am trying to set-up trace with JTrace Pro, Ozone and the nRF52840. If you have a fix for this, I would appreciate it if you posted it here. 

  • "

    • I've observed a difference between running the same code from GDB and Ozone. Code works fine from GDB, however, when run from Ozone it fails on Bluetooth connect. Can't really say what the problem is yet. "

    Sorry to kick this topic, but did you ever found out why oZone stopped in bluetooth connect? I see something similar where the SD fetches from a non-existing table that it expects at 0x20000000. That address is RAM, but it is uninitialized (never written to) before it is accessed.

  • I just purchased the J-Trace Pro Cortex from Segger. It has a 19-pin interface so you won't need the adapter. 

    I've made a few observations with Ozone (Their trace-capable debugger) I can give you here:
    • When you reset, the IDE sets PC to the entry point of the ELF file and executes from there. It can make some sense; but this means that after reset the MBR doesn't get invoked. Also, if you are relying on a bootloader to do something before your application code, it won't get invoked. I haven't found an option to change that behavior; but you can change it by editing the Ozone project file.
    • I've observed a difference between running the same code from GDB and Ozone. Code works fine from GDB, however, when run from Ozone it fails on Bluetooth connect. Can't really say what the problem is yet. 
  • Hi,

    Thank you so much for your blog post. It just so happens that I am currently investigating ways to access TRACE on a nRF52832 DK.

    Thus, I am currently choosing what debugger to buy. From my understanding of your article, I could achieve what I am trying to do with the following:

    1: J-Trace Pro Cortex- M -

    2: J-Link 19 Pin Cortex-M adapter -

    3- Some custom wiring to reproduce the scheme you have detailed in your post.

    Is that it ? I just want to make sure that I am not missing anything before going for it.

    Thank you very much in advance !