Run Zephyr on nrf52840 (Particle Xenon)

Mark Zachmann
Oct 17, 2019 · 6 min read

I’ve been experimenting with Nordic Semiconductor nrf52840 boards, first using Arduino, then naked NordicSemi SDK/C++ and now I’m looking into Zephyr. The (imho) best of the module/boards is the Particle Xenon.


Why Zephyr?

Zephyr is a free open-source multi-threaded OS by the Linux Foundation. It’s a small-footprint operating system designed for smallish embedded systems with a specialization in Bluetooth. The nrf52840 with 1MB of flash and 1/4MB of ram and a fast ARM cpu is almost a perfect match.

I’m considering it mainly because of the Bluetooth support. Nordic (and others) have helped with the Zephyr Bluetooth implementation and it’s much nicer to use than Nordic’s internal Bluetooth stack for the simple reason that the code is open-source and compiled-in so it’s much easier to debug (and fix if necessary). It’s possible that Nordic’s SoftDevice (the SDK closed implementation of Bluetooth) is as reliable, or even more-so, but debugging it is agony if not impossible. It also requires somewhat indeterminate space in the flash/ram map and must be sideloaded with apps. This makes the upgrade process complex.

Quick Summary

Before getting into how to build/use Zephyr, just a summary of my thoughts after a few days of implementation.

Zephyr is very easy to implement and get running. I can even use it with the Nrf5 bootstrapper. It took just a couple of days to get it running on my custom Xenon implementation and powering an OLED the way I wanted it. The Zephyr API is simple but very powerful.

The documentation could be better. In typical open-source fashion a fair amount of understanding requires going through the code. The overview documentation is reasonable and the setup documentation is very good.

The API reference (one page is shown on the left here) as you can see is very bad. Note the entire lack of an overview and configuration options is a list of CONFIG defines with no info. Arguments are declared but not explained. It’s poorly done autodoc. I’m not entirely sure what a ‘static’ C function is in this context.

The sample applications are also poorly documented and usually trivial but still quite useful.

The toolset is very good but slightly complex. It runs under Windows, Mac, and Linux. Under Linux& MAC you can even debug in a simulated environment (QEMU).

I have been able to get Segger Studio with a JLink to debug Zephyr very adequately on the Particle Xenon. It’s not documented (so I’ll discuss in detail) and not supported (yet) so… but it seems to work very well and you get full visual debugging — and the Bluetooth code is visible.

Debugging a Zephyr App with Segger Studio

Getting Started

The Getting Started at the Zephyr site is very good. I won’t duplicate it. If you are using a stock Particle Xenon then there is even bundled support for it. I started with those Xenon files but modified them for my usage (I remap the I2c, SPI, … pins and add some peripherals). Modification was easy and discussed in the porting guide, but I just read through the files and some samples.

The .DTS file specifies the board-specific device tree. This defines what pieces of the nrf52840 the board makes available in the hardware implementation and what pins correspond to those pieces (such as I2C or SPI).

The config/KConfig files define which pieces of the subsystem are being actively used by the software and how — similar to the Nordic SDK .conf file.

A good way to think about it is that the Device Tree shows what’s available (such as partitions) and the prj.conf (for the project) or board_defconfig (for the board) says whether or not it’s being used.

I didn’t bother trying to figure out how to flash the Xenon the Zephyr way because i’m using the Nrf5 bootloader and Bluetooth DFU (device firmware updater). Flashing via the JLink is painless, however. I just set the project load file to the built .elf application and when I debug/go it downloads the binary .elf file to the module at the right offset.

Configuration Editing via GUI

Zephyr comes with a configuration (prj.conf) editor that’s pretty good. To invoke it use west as in:

west build -t guiconfig -b board-name project-name


west build -t menuconfig -b board-name project-name

for a terminal-based gui.

Unfortunately these apps change the .config file in your build folder, so they get wiped away by a new prj.conf. Copy any changes to your prj.conf or Kconfig files to have them persist.

Setting Flash Offset

Setting the flash offset and size was a struggle. I used the partition definitions from the Xenon (see mesh_feather.dtsi) and they did nothing until I worked out to add


to the prj.conf file. I think CONFIG_BOOTLOADER_MCUBOOT would be similar.
Note that this used to be: CONFIG_USE_CODE_PARTITION.

Workspace Design

The default Zephyr installation is to place a copy of zephyr into your source tree and then build into a folder in the source tree. This is clumsy/bad since you end up with the entire Zephyr tree needing to get backed up.

So, instead I did the following:

Zephyr Code Source Tree for BlueLora project

3. Set ZEPHYR_BASE to point to the zephyr source tree.

4. Insert a symbolic link in the zephyr source tree to the driver folder via (in the {zephyr-source}/boards/arm folder)

mklink /d {driver-folder-name} {folder-source-name}

which will create a symbolic link between the folder in my source in OneDrive and where it needs to live in the zephyr tree.

Now it’s possible to build in this source folder using west build…


There are some issues with building. The cache sometimes seems to get corrupted and it compiles but doesn’t even run to main() — you just get a vector trap. Delete the entire build folder and try again if that seems to be happening.

Using Segger Studio with Zephyr

I’ve gotten to like Segger Studio so I wanted to hook it up to Zephyr but the doc is self-contradictory and scant. There is a special version of Segger specific for the Nrf Connect SDK (which uses Zephyr) but I found it to be buggy and not useful.

Instead I used standard Segger Studio. The big trick is avoiding the many files with the same names for different architectures.

This ensures that most of the non-app source is included so that you can step through stuff. When debugging, SES will ask for a few extra .c or .h files but not many.

The other thing to do is allow building for debug. A few prj.conf entries:


And one last conf entry to allow C++


Once this is all set up you can debug with Segger Studio (building still uses the zephyr west application).

Home Wireless

Home automation in the wireless IOT era

Mark Zachmann

Written by

Entrepreneur, software architect, electrical engineer. Ex-academic.

Home Wireless

Home automation in the wireless IOT era

More From Medium

More on Nrf52840 from Home Wireless

More on Nrf52840 from Home Wireless

BlueLora Node on Kickstarter

More on Zephyr from Home Wireless

More on Zephyr from Home Wireless

More on Zephyr from Home Wireless

Using a PWM Device in Zephyr

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade