I decided to have another look at Zephyr.
As per documentation about application development, there are three options: repository, workspace and freestanding. In the repository options, my application code is put directly within the zephyr repository. I don’t really like this option, as I like to keep my code separated from their code. That leaves the workspace and freestanding options. The workspace options puts the zephyr repository next to the repository containing my code. The freestanding options keeps my repository without a relation to a zephyr repository. For now, I will be looking at the workspace option. I will base my workspace on the reference workspace application.

As per instructions on the example application repository:

# initialize my-workspace for the example-application (main branch)
west init -m https://github.com/zephyrproject-rtos/example-application --mr main my-workspace

However, before I call west update , I will edit the my-workspace/example-application/west.yml file, such that it ends with

- cmsis # required by the ARM port
- hal_nordic # required by the custom_plank board (Nordic based)
- segger # RTT support (added this line)
- tinycrypt # BLE dependency

This name-allowlist makes it so it does not initialise submodules that are not needed by the project. I would like to have RTT support, thus I add “segger”, and since I intend to add Bluetooth Low Energy I also need “tinycrypt”. As the initial version of the project will run on a Nordic based board, I’ll keep the “hal_nordic” but I’ll remove the “hal_stm32”.

With these changes in place I will run “west update”. This will clone the required git repositories. After this is completed, I will attempt to build the example application. I will be using the compiler installed from the distro’s packages. How to do this is documented in the Other Cross Compilers section in the documentation.

However, this approach has a few caveats which I intend to investigate later. The major problem is the fact this option disabled the “newlib” support. It will default to “picolib” as C library. As my installation uses “newlib” rather then “picolib” as its C library, this will cause issues. Note that using the “gnuarmemb” as toolchain variant does not exhibit this problem. Anyhow, for the time being, I’ll configure the C library to “minimal C library” and I’ll be able to build. This can be done by addomg by adding CONFIG_MINIMAL_LIBC=y to the my-workspace/example-application/app/prj.conf file.

Now we should be able to build the application, by invoking west from the “example-application” directory, specifying the “app” directory as the target to build. I am using the example board, “custom_plank”, from the example repository, to verify custom boards are recognised by the build system.

[andre@mortar example-application]$ ZEPHYR_TOOLCHAIN_VARIANT=cross-compile CROSS_COMPILE=/usr/bin/arm-none-eabi- west build -b custom_plank app

Now all of this is set up, we can have a look at the goals for the project. I am intending to create a “Party Hat”. This will be a hat with a WS2812-based LED strip on it. I intend to use an nRF52832 microcontroller to control the LED strip, and communicate over BLE with a smart phone to configure what the LEDs are supposed to be doing.

I am using vanilla Zephyr, not Nordic’s fork, for this project. I wish to investigate how easy it is to create applications that can be targetted at multiple types (brands) of microcontrollers. But that’s all for much later. For now, I’ll focus on the nRF52832.

On a regular embedded project, all I specify is the target microcontroller, and handle the rest in code. I would put a “pinout.h” file specifying which pins are used for what. Zephyr takes a different approach. It defines the hardware in device trees. The thing I am used to see when booting a Linux kernel on a SBC. A single kernel binary, capable of running on many SBCs, given the device tree. On a MCU, this approach would obviously take way too much space. A specific target is created anyways, but the configuration is taken from a file using the same syntax as a typical Linux device tree would use. It defines the peripherals, assigns pins to them, and even what external hardware is connected to them.

This is a whole bunch of work that needs to be done, even before the first line of code is written. Zephyr has examples with drivers for WS2812 LED strips. From what I’ve seen, they’ll be using SPI. Which means, it’ll assign a full blown SPI bus even though just one pin is needed. And the example shows several layers of abstraction, as it is based on the device trees for the nrf52-dk. It maps nRF52 pins to Arduino pins, which are mapped to the SPI bus.

I’ll skip that for now. I will investigate that later. For now, I’ll try to use my existing WS2812 code for nRF52, using the PWM peripheral instead. It is possible to use the nrfx library directly inside Zephyr, so that is what I will be doing. Get the proof of concept running first, then see if we can do things differently. Perhaps I will try to get the PWM approach into a Zephyr driver, but that’s for later.

From here, if I were to publish the resulting project, I’ll have to do something about the repository I just cloned. I will squash all commits into one, and rename it to something like “Importing Example Application.” For this, I’ll use “git rebase –root -i”, put the first commit at “reword” and all the others as “squash”. Using vim, this can be achieved with “%s/pick/squash/g” to rename all the instances of “pick”, and then I’ll manually put “reword” at the first entry.

Then I’ll set the url to a new repo using “git remote origin set-url”, and there we go: my repo is at https://github.com/a-v-s/party_hat. It will still neat some cleaning up and stuff, but it is there.

I’ll have to explain some more issues I’ve ran into, but that’s for a later post.