Debugging nRF9160 Zephyr Applications with Ozone

Ozone is a free embedded software debugger from SEGGER. It is a powerful tool that allows you to gain deep insights into what is happening within embedded systems. It is particularly useful when debugging nRF9160 Zephyr applications. Organizing multiple threads and multi-image builds can be challenging, but this is the tool you want.

In our previous blog post “Taking the Next Step: Debugging with SEGGER Ozone and SystemView on Zephyr” (blog link: https://blog.golioth.io/taking-the-next-step-debugging-with-segger-ozone-and-systemview-on-zephyr/), Chris Gammell wrote about how to set up a SEGGER Ozone project to debug a Zephyr application running on the i.MX RT1060 evaluation kit. This is a great introduction to debugging Zephyr applications in Ozone and analyzing RTOS runtime behavior.

When I attempted to set up a similar Ozone project to debug the Nordic nRF9160 SIP development board, I encountered some difficulties along the way. Today, I will share what I learned.

In this article, I will cover how to:

• Configure the nRF9160 Zephyr application for thread-aware debugging.

• Create an Ozone project for the nRF9160 using the New Project Wizard.

• Modify the Ozone project to support debugging the nRF9160 multi-image build.

Hardware Configuration

Debugging nRF9160 Zephyr Applications with Ozone

In the example below, I will use the Nordic nRF9160 DK board. This development kit from Nordic has a built-in SEGGER J-Link OB debugger on the board, so no external J-Link debugger is needed to follow along with the example (SEGGER Ozone requires J-Link support).

Debugging nRF9160 Zephyr Applications with Ozone

Thread Awareness Support in Zephyr

Debugging nRF9160 Zephyr Applications with Ozone

In a typical Zephyr application built with the Golioth Zephyr SDK, there will be multiple threads. For example, one for the main loop of the application, one for the Golioth system client, and others for UART shell, logging subsystems, network management, etc.

SEGGER provides a Zephyr RTOS plugin for Ozone that displays the state of each thread, but it requires the Zephyr firmware to support thread-aware debugging at build time. Zephyr provides a CONFIG_DEBUG_THREAD_INFO Kconfig symbol that indicates the kernel maintains a list of all threads, making thread names visible in Ozone.

While you can simply add CONFIG_DEBUG_THREAD_INFO=y to the application’s prj.conf file, you may want to enable this additional debug information only at build time. We can create an additional debug.conf Kconfig file that will only be merged when we pass the -DEXTRA_CONF_FILE=debug.conf parameter to the build system.

Since this article is about using Ozone for thread-aware debugging, we will use the zephyr/samples/basic/threads/ application from the nRF Connect SDK Zephyr repository as the example application for this article.

If this is your first time building one of the Zephyr example applications, make sure to complete the nRF Connect SDK installation first and ensure your development environment is set up correctly.

How to Enable Thread Awareness?

Debugging nRF9160 Zephyr Applications with Ozone

First, create a zephyr/samples/basic/threads/debug.conf file and add the following command lines:

zephyr/samples/basic/threads/debug.conf

CONFIG_DEBUG_THREAD_INFO=y# CONFIG_DEBUG_THREAD_INFO needs the heap memory pool to# be defined for this appCONFIG_HEAP_MEM_POOL_SIZE=256

Next, build the firmware, specifying the required debug.conf file to be merged into the build configuration:

cd <your ncs workspace>/west build -p -b nrf9160dk_nrf9160_ns zephyr/samples/basic/threads/ -- -DEXTRA_CONF_FILE="debug.conf"

If the build completes successfully, you will see the build/zephyr/zephyr.elf file needed to start a debug session in Ozone.

Creating an Ozone Project

Debugging nRF9160 Zephyr Applications with Ozone

Now that we have built the firmware, we can launch Ozone and create an Ozone project using the New Project Wizard:

Debugging nRF9160 Zephyr Applications with Ozone

Select the nRF9160_xxAA chip.

Debugging nRF9160 Zephyr Applications with Ozone

Select to use the J-Link emulator.

Debugging nRF9160 Zephyr Applications with Ozone

Select the build/zephyr/zephyr.elf file that was generated in the previous discussion.

Debugging nRF9160 Zephyr Applications with Ozone

Leave the other selections as default.

Debugging nRF9160 Zephyr Applications with Ozone

After clicking “Finish”, you will see the Ozone project window appear. In the “Console” window, run the following command to load the Zephyr RTOS plugin:

Project.SetOSPlugin("ZephyrPlugin.js");

Debugging nRF9160 Zephyr Applications with Ozone

Now, you should see a new “Zephyr” window in the Ozone project (if not, click “View” → “Zephyr” to display the window):

Debugging nRF9160 Zephyr Applications with Ozone

Finally, save the project file by clicking “File” → “Save Project as…”:

Debugging nRF9160 Zephyr Applications with Ozone

Starting the Debug Session

Debugging nRF9160 Zephyr Applications with Ozone

Now that we have configured the Ozone project, we can start the debug session.

Click “Debug” → “Start Debug Session” → “Download & Reset Pro”

Debugging nRF9160 Zephyr Applications with Ozone

Strangely, when the firmware starts running, a pop-up window will indicate that the target has stopped in a HardFault exception state!

Debugging nRF9160 Zephyr Applications with Ozone

At this point, you may be wondering what is happening here…

Here’s a hint: the answer relates to the multi-image build.

https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/config_and_build/multi_image.html

Missing Steps:

Burn the Merged File Image

Debugging nRF9160 Zephyr Applications with Ozone

You may have noticed that we passed the board parameter (nrf9160dk_nrf9160_ns) to west build with a _ns suffix. This suffix indicates that the firmware will be built using Trusted Firmware-M (TF-M). This is the reference implementation of ARM’s IoT security framework known as the Platform Security Architecture (PSA).

TF-M uses the ARM TrustZone security features of the nRF9160’s Cortex-M33 MCU to partition the MCU into a Secure Processing Environment (SPE) and a Non-Secure Processing Environment (NSPE).

In short, the boot process works as follows:

1. When the MCU starts, it begins executing in the Secure Environment (SPE).

2. The boot process can optionally start from a secure bootloader chain using NSIB and/or MCUboot.

3. If used, the bootloader will start TF-M, which configures a portion of the MCU’s memory and peripherals as non-secure.

4. TF-M starts the Zephyr application running in the Non-Secure Environment (NSPE).

When we build for the _ns target, the TF-M image is automatically built and linked with the Zephyr application. If you look in the build/zephyr/output directory, you will see a file named merged.hex, which is a merged file containing the MCUboot bootloader (optional), the TF-M secure image, and the non-secure Zephyr application.

Fixing the Ozone Project File

Debugging nRF9160 Zephyr Applications with Ozone

We will make some changes directly in the Ozone project file, which can be opened in Ozone by clicking “File” → “Edit Project File”:

Debugging nRF9160 Zephyr Applications with Ozone

Burning the Merged Image

Debugging nRF9160 Zephyr Applications with Ozone

Navigate to the TargetDownload section of the Ozone project file and add the following to configure Ozone to flash the merged image (change the path to match the merged image file in your project):

/*********************************************************************** TargetDownload** Function description* Replaces the default program download routine. Optional.************************************************************************/void TargetDownload(void){Exec.Download("$(ProjectDir)/build/zephyr/merged.hex");}

Fix the vector table and PC address

Navigate to the _SetupTarget section of the Ozone project file and make the following changes:

1. Set the vector table address to 0

2. Read the entry point program counter address from the vector table

/*********************************************************************** _SetupTarget** Function description* Setup the target.* Called by AfterTargetReset() and AfterTargetDownload().** Auto-generated function. May be overridden by Ozone.************************************************************************/void _SetupTarget(void) {unsigned int SP;unsigned int PC;unsigned int VectorTableAddr;VectorTableAddr = 0;//// Set up initial stack pointer//SP = Target.ReadU32(VectorTableAddr);if (SP != 0xFFFFFFFF) {Target.SetReg("SP", SP);}//// Set up entry point PC//PC = Target.ReadU32(VectorTableAddr + 4);if (PC != 0xFFFFFFFF) {Target.SetReg("PC", PC);} else {Util.Error("Project script error: failed to set up entry point PC", 1);}}

When you save the project file, you should see a prompt asking if you want to reload the project.

Select “Yes”:

Debugging nRF9160 Zephyr Applications with Ozone

Starting the Debug Session

Debugging nRF9160 Zephyr Applications with Ozone

After the image file is flashed to the chip, you should see the debugger stop at the main location:

Debugging nRF9160 Zephyr Applications with Ozone

Click “Debug” → “Continue”:

Debugging nRF9160 Zephyr Applications with Ozone

This time, the firmware runs normally without exceptions.

Conclusion

Debugging nRF9160 Zephyr Applications with Ozone

I hope this helps you get started with using Ozone to debug the nRF9160. The nRF9160 has full support in Zephyr projects and the highest level of support in the Golioth IoT device management platform. With Golioth, you can connect and secure devices, send sensor data to the web, wirelessly update firmware, and expand your coverage using IoT cloud.

Debugging nRF9160 Zephyr Applications with Ozone

END

Source: Mike Tai TechnologyCopyright belongs to the original author, please contact for deletion if there is any infringementRecommended ReadingEmbedded Development Tool Version Selection StrategyOrganized STM32 related open-source projectsHaving trouble improving your C programming skills? Try these examples→ Follow for more updates ←

Leave a Comment