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.
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.
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.
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.
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.
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.
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.
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.
- Run Segger Studio
- Create a new project/solution using the “An externally built executable for Nordic Semiconductor nRF” option.
- Set the load file to the compiled .elf file (usually in the build/zephyr folder)
- Add two dynamic folders. The zephyr folder is carefully scanned to ignore the other (non-ARM architectures). The soc folder is specifically only scanned in the Nordic_nrf folder.
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++