nRF5x support within the Zephyr Project RTOS

image description

The Zephyr Project RTOS

The Zephyr Project RTOS is a recent effort by the Linux Foundation to provide the embedded world with a free, secure and fully-featured Real Time Operating System. It is designed from the ground up to be a modern, scalable, secure and responsive RTOS with a clear focus on IoT protocols and foundations. This open source RTOS is Apache 2.0 licensed and has a fully open development model

Recently Nordic contributed ports to all of our Cortex-M based ICs (nRF51, nRF52832 and nRF52840) as well as a fully featured, open source BLE Controller (Link Layer + HCI)that is highly optimized for the nRF5x family of ICs. This means that if you own any of the Nordic Development Kits for the nRF5x series you can clone, build and run Zephyr today and take advantage of all the features that it enables, including many standard BLE profiles, IPv6 over BLE, and a rich set of APIs and functionality that one would expect from a modern RTOS. On top of that every single line of code, including the BLE Host and Controller, are fully open source, allowing you to tweak and modify its behaviour or even extend it at will. You can even build your own controller and then use it to control it from an external Host stack or run the rest of the RTOS on your desktop computer using QEMU!

Here are some of the features that Zephyr supports:

Architectures:

  • ARM Cortex-Mx
  • Intel x86
  • ARC
  • Synopsys nios2
  • RISC-V
  • Tensilica Xtensa
  • MIPS (upcoming)

Real-time kernel:

Device Drivers:

Bluetooth Low Energy:

Networking:

Build and debug:

  • Flexible and powerful configuration system based on Kconfig
  • GCC and Clang support
  • GDB and Segger RTT support

Running Zephyr on nRF5x

Zephyr currently supports the following Nordic ICs:

  • nRF51822 (all variants)
  • nRF52832
  • nRF52840

Additionally, there's built-in support for the following nRF5x-based boards:

Important note on custom or additional boards: If your board is similar to one of the above supported ones but does not include a 32KHz external crystal, you may have to include the following lines in your prj.conf:

CONFIG_CLOCK_CONTROL_NRF5_K32SRC_RC=y
CONFIG_CLOCK_CONTROL_NRF5_K32SRC_250PPM=y

Since the internal RC would then need to be used as the low frequency source.

Using the nRF52832 and the nRF52 DK as an example, let's go through the steps of building, flashing and running Zephyr on it. If you want to use the official documentation instead of following this guide, please refer to:

NOTE: This instructions are valid for macOS and Linux. To build on Windows please refer to the official documentation

First we need to obtain and install a toolchain. The following toolchains are supported:

  • Linux: Zephyr SDK, GNU ARM Embedded
  • macOS: GNU ARM Embedded

Assuming we go with GNU ARM Embedded and that you have a working native compiler and basic toolset on your machine, you can then follow the steps below:

  1. Download and unpack GNU ARM Embedded to the folder of your choice. In this manual we will assume you've unpacked it in ~/gccarmemb/

  2. Export the following environment variables:

$ export GCCARMEMB_TOOLCHAIN_PATH="~/gccarmemb/"
$ export ZEPHYR_TOOLCHAIN_VARIANT=gccarmemb
  1. Clone the repository to obtain Zephyr's source code:
$ git clone https://github.com/zephyrproject-rtos/zephyr.git
  1. At the root folder of your freshly cloned repository, run:
$ source zephyr-env.sh
  1. Now you are ready to build. Let's start with a simple beacon example:
$ cd samples/bluetooth/beacon
$ mkdir build && cd build
$ cmake -DBOARD=nrf52_pca10040 ..
$ make
  1. To flash the image into the board you will need to download and install the JLink Software and Documentation Pack and the nRF5x command-line tools. Additional information about Segger J-Link in Nordic nRF5x boards can be found in the Nordic nRF5x Segger J-Link doc page

  2. Now you are ready to use nrfjprog to erase and program the board:

$ nrfjprog --eraseall -f nrf52
$ nrfjprog --program outdir/nrf52_pca10040/zephyr.hex -f nrf52
$ nrfjprog --reset -f nrf52

or simply

$ make flash
  1. When pluggin in the board, a serial communications port will have been detected by your operating system. Use your favourite terminal program to view the console output of the program you have just flashed (115k2, 8N1), for example:
$ minicom -D /dev/ttyACM0 -b 115200
  1. Use any device capable of scanning to make sure Zephyr's beacon is advertising correctly

Building a BLE Controller

Using Zephyr's built-in, Nordic-contributed, BLE Controller you can actually turn any of your nRF5x-based boards into a fully featured, standard BLE Controller than you can use with external protocol stacks. The Controller supports nRF51 and nRF52, and you can configure it to support any number of connections in any role.

To do so, you only need to compile the hci_uart sample:

$ cd samples/bluetooth/hci_uart
$ mkdir build && cd build
$ cmake -DBOARD=nrf52_pca10040 ..
$ make

After that, you can flash the .hex file to your board and you already have a fully-featured BLE Controller ready to accept HCI commands. The UART settings are as follows:

  • Baudrate: 1Mbit/s
  • 8 bits, no parity, 1 stop bit
  • Hardware Flow Control (RTS/CTS) enabled

Using the BLE Controller with Linux's BlueZ

Once you have built and flashed a BLE Controller to your Development Kit, you can even try it out with Linux's built-in Bluetooth stack, BlueZ!

Here's a short guide to achieving that, full instructions can be found in the Using BlueZ with Zephyr documentation page.

  1. First of all make sure you have a recent Linux kernel installed (at least 4.10) and a modern (5.45+) version of the BlueZ userspace tools. For some of the tools, and depending on what your distribution bundles, you might need to compile BlueZ from scratch. To do so issue the following commands:
$ git clone git://git.kernel.org/pub/scm/bluetooth/bluez.git
$ ./bootstrap-configure --disable-android --disable-midi
$ make

You can then find btattach, btmgt and btproxy in the tools/ folder and btmon in the monitor/ folder.

  1. Compile and flash the hci_uart example as shown above

  2. On a separate terminal, open btmon to be able to observe all HCI traffic between BlueZ and the controller:

$ sudo btmon
  1. Open another terminal, attach the controller to the system:
$ sudo btattach -B /dev/ttyACM0 -S 1000000 -P h4
  1. Open a third terminal and open btmgt:
$ sudo btmgmt --index 0

NOTE: the "--index" option is the controller index. Depending on whether you already had one or more controllers connected this could be a number from 0 to N.

  1. From the btmgmt console assign any random static address to the controller (only required for BlueZ < 5.45):
[hci0]# static-addr FF:02:03:04:05:FF
  1. Power on the controller:
[hci0]# auto-power
  1. Now you are ready to do whatever you want with it, you could for example scan for devices:
[hci0]# find -l

image description

Additional documentation can be found in the btmon, btattach and btmgmt man pages.

Note: We recommend enabling the experimental features in BlueZ in order to access all of the BLE functionality. To do that edit:

/lib/systemd/system/bluetooth.service

And make sure that you include the -E option in bluetoothd's ExecStart:

ExecStart=/usr/libexec/bluetooth/bluetoothd -E

After that reload and restart the daemon:

$ sudo systemctl daemon-reload 
$ sudo systemctl restart bluetooth

Using the BLE Controller build to run the RTOS from QEMU

Another useful feature of Zephyr is the possibility to run all or part of its codebase from QEMU, allowing you to develop and debug directly on your computer, no flashing or remote debugger required.

To enable BLE development with QEMU, first follow the instructions on the section above to build and flash a BLE Controller build onto your Development Kit. Additionally you will need to install the Zephyr SDK to compile for QEMU, since you cannot use GCC ARM Embedded at this point for it. To install the SDK (Linux only) follow the steps detailed here.

  1. Make sure you have a recent Linux kernel installed (at least 4.6) and a modern (5.42+) version of the BlueZ userspace tools.

  2. Compile and flash the hci_uart example as shown above

  3. On a separate terminal, open btmon to be able to observe all HCI traffic between BlueZ and the controller:

$ sudo btmon
  1. Open another terminal, attach the controller to the system in raw mode (note the -R):
$ sudo btattach -B /dev/ttyACM0 -S 1000000 -R
  1. In yet another terminal, open an instance of btproxy, which will expose the controller to QEMU:
$ sudo btproxy -i 0 -u

NOTE: Replace -i 0 with the index corresponding to your Zephyr-based BLE Controller

  1. Open a fourth terminal and choose any of the bluetooth samples available, in this case we'll try the peripheral_hr one:
$ cd samples/bluetooth/peripheral_hr
  1. Finally you are ready to compile for QEMU and run:
$ make qemu

At this point you are running the application, RTOS and the Bluetooth Host on QEMU locally on your development computer, but the controller on the nRF5x on the Development Kit. They interface using standard HCI, and you will see all traffic being sent between the two in your btmon window.

image description

Happy coding! If you try Zephyr out on the nRF5x and have feedback for us, please feel free to leave a comment in the blog post or tweet to us at @NordicTweets.

Also if you want to get involved with Zephyr, or simply need help as a user, you can join the Zephyr mailing list or join the #zephyrproject IRC channel.

  • @Nilasstohr. This is not quite the right forum to ask those questions, since Zephyr is not officially supported by Nordic yet. Please use the Zephyr mailing list or join us at #zephrproject or #zephyr-bt and we'll be happy to help you out there.

  • Hello again, I have a question about the configuration of the zephyr bluetooth stack. I need to do a proof of concept for the company were I work, where a nordic device should be both a central and a peripheral, I successfully did this with nordic sdk following one of the example.

    The question is how to do this with zephyr?, looking through the source code in ex. central_hr and peripheral_hr it is not obvious were they are configured as central and peripheral (apart from seeing a start a scan and adv etc, is started)

    thanks much in advance.

  • solution for my compile error (thanks to Carles) is shared here:

    Following the guide www.zephyrproject.org/.../installation_win.html

    where the zephyr SDK is fetched with: git clone github.com/.../zephyr.git

    But in my case I got a compile error (see above). The reason for this was likely that an old zephyr version was fetched or a cleanup in the fetched version was needed for some reason. To fix the problem following three git commands are executed in the msys2 shell.

    git fetch origin

    git reset --hard origin/master (making sure local copy is identical to master repo version)

    git clean -ffdx (clean up of output directories)

  • @Nilasstohr. I've tried repeatedly to reproduce this by building the central_hr example for nrf52840 on both Windows and Linux and I cannot reproduce. Could you please join IRC again and we can talk about it? Yesterday I didn't see your messages on IRC, was a bit late here.

  • Thank you for your fast answer, I have fetched the master and recompiled, the problem persist. I think I came closer to a reason which is seem below, I have also written this in the IRC.

    For some reason the central samples (ex. central_hr) is depended on ll_adv.h and ll_adv.c but the library is never compiled.

    This is seen by looking at the compile output for central_hr when running "make BOARD=nrf52840_pca10056". Comparing this to compiling the peripheral_hr, the compile output will have the line “CC subsys/bluetooth/controller/ll_sw/ll_adv.o”.

    The ll_adv_set_get function are a part of ll_adv (which is not compiled in the central examples) this might be the reason for the compile error. The question is why my central examples compile like this way and how to change it?

    I have not done anything beside following the guide below with a window 10 OS. www.zephyrproject.org/.../installation_win.html