Zephyr Project is a real-time operating systems for the Internet of Things (IoT) that was introduced in early 2016, and supported/hosted by the Linux Foundation.
It runs on a fairly large number of MCU boards from different architecture (x86, Arm, RISC-V, etc..), and Linaro even launched 96boards IoT compliant hardware like BLE Carbon board that are designed to run Zephyr Project. More recently, Linaro CEO revealed several commercial products are shipping with Zephyr Project OS, so I thought it might be a good time to give it a try.
Target Board – Wemos Lolin32
I only had STM32 Bluepill, and some ESP32 boards, so I went with the latter since it comes with WiFi. But instead of re-using some of my existing boards, I asked Banggood whether they could send Wemos Lolin32, which they did. They sell it for $7.99 shipped, but any other ESP32 board should do.
The board comes with two headers that you can solder if you wish. I did it with the pins facing upwards, but if you want to insert the board into a breadboard, they should obviously face downwards instead.
In the steps below, we’ll mostly use the micro USB port, the reset button, and on-board user LED connected to GPIO 5. I’ll follow the instructions on Zephyr website for Linux, and try a few samples. I’ll do so in Ubuntu 16.04, but they should be easy enough to adapt to Windows or Mac OS, as both OS are also supported.
Install ESP32 Toolchain and SDK
First let’s install xtensa-esp32 toolchain and dependencies in Ubuntu 16.04 64-bit:
1 2 3 4 5 |
sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-serial wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz mkdir -p ~/esp cd ~/esp tar -xzf ~/Downloads/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz |
We can now add the toolchain folder to the PATH in ~/.profile:
1 |
export PATH="$PATH:$HOME/esp/xtensa-esp32-elf/bin" |
Logout and login again, and you should see the ESP32 toolchain in the path, e.g.:
1 2 |
printenv PATH /home/jaufranc/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/jaufranc/.rvm/bin:/snap/bin:/var/lib/snapd/snap/bin:/home/jaufranc/.rvm/bin:/home/jaufranc/esp/xtensa-esp32-elf/bin |
Next up is the ESP-IDF SDK (Software Development Kit) which we can retrieve from github:
1 |
git clone --recursive https://github.com/espressif/esp-idf.git |
Once it’s done set up IDF_PATH by adding the following line to ~/.profile file:
1 |
export IDF_PATH=~/esp/esp-idf |
Zephyr Project RTOS and Samples
The setup part specific to ESP32 is now done, so we can get Zephyr Project OS…
1 2 |
cd ~ git clone https://github.com/zephyrproject-rtos/zephyr.git |
and install the dependencies:
1 2 3 4 5 6 |
sudo apt install --no-install-recommends git cmake ninja-build gperf \ ccache doxygen dfu-util device-tree-compiler \ python3-ply python3-pip python3-setuptools python3-wheel xz-utils file \ make gcc-multilib autoconf automake libtool cd ~/zephyr <span class="n">pip3</span> <span class="n">install</span> <span class="o">--</span><span class="n">user</span> <span class="o">-</span><span class="n">r</span> <span class="n">scripts</span><span class="o">/</span><span class="n">requirements</span><span class="o">.</span><span class="n">txt</span> |
CMake version 3.8.2 or higher is required, so let’s check our version:
1 2 |
cmake --version cmake version 3.5.1 |
Damn! The version in Ubuntu 16.04 is too old, so we need to upgrade it:
1 2 3 4 5 |
mkdir $HOME/cmake && cd $HOME/cmake wget https://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.sh yes | sh cmake-3.8.2-Linux-x86_64.sh | cat echo "export PATH=$PWD/cmake-3.8.2-Linux-x86_64/bin:\$PATH" >> $HOME/.zephyrrc source ~/zephyr/zephyr-env.sh |
and now we can check the version again:
1 2 |
cmake --version cmake version 3.8.2 |
All good.
Since Espressif is constantly working on ESP-IDF SDK, the API may change, so we’re being asked to checkout a specific tag:
1 2 |
cd ~/esp/esp-idf/ git checkout dc8c33892e0 |
We can now export variable for ESP32. If you want to make those permanent add the three lines below to ~/.profile:
1 2 3 |
<span class="go">export ZEPHYR_TOOLCHAIN_VARIANT="espressif" export ESP_IDF_PATH="${HOME}/esp/esp-idf" </span>export ESPRESSIF_TOOLCHAIN_PATH="${HOME}/esp/xtensa-esp32-elf/" |
The project has many samples on offer, let’s try out some starting with Hello World:
1 2 3 4 |
cd $ZEPHYR_BASE/samples/hello_world mkdir build && cd build cmake -GNinja -DBOARD=esp32 .. ninja run |
Before you run the last line make sure you have connected your ESP32 board to your computer using a micro USB to USB cable. If everything goes well the output the command should look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
ninja flash [1/57] Generating always_rebuild Building for board esp32 [2/2] Flashing esp32 Using runner: esp32 Converting ELF to BIN esptool.py v2.3.1 Flashing ESP32 on /dev/ttyUSB0 (921600bps) esptool.py v2.3.1 Connecting.... Chip is ESP32D0WDQ6 (revision 1) Features: WiFi, BT, Dual Core Uploading stub... Running stub... Stub running... Changing baud rate to 921600 Changed. Configuring flash size... Auto-detected Flash size: 4MB Flash params set to 0x0220 Wrote 16384 bytes at 0x00001000 in 0.2 seconds (601.2 kbit/s)... Hash of data verified. Leaving... Hard resetting via RTS pin... |
So it will built the sample, and upload it to the board in one go. Now connect minicom or another serial terminal origram to /dev/ttyUSB0 with 115200 8N1 settings, and press the reset button on the board to check the output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
ets Jun 8 2016 00:22:57 rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) flash read err, 1000 ets_main.c 371 ets Jun 8 2016 00:22:57 rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:2 load:0x3ffb0000,len:96 load:0x3ffb0060,len:360 load:0x3ffb01c8,len:1864 load:0x40080000,len:1024 load:0x40080400,len:96 load:0x40080460,len:9548 load:0x400c0000,len:0 entry 0x40080694 ***** Booting Zephyr OS v1.12.0-rc2-68-g158ea97 ***** Hello World! xtensa |
Success!
My next attempt was the Blinky “basic” sample. Should be easy enough, right? Nope. It does not build for ESP32 out of the box, and we are told to update board.h with:
- LED0_GPIO_NAME (or LED0_GPIO_CONTROLLER)
- LED0_GPIO_PIN
After a directory search, I found ~/zephyr/boards/xtensa/esp32/board.h
(basically empty) and I added two lines for the variables above, based on my guess using samples for other platforms, and knowing the LED is connected to pin 5:
1 2 3 4 5 6 7 8 9 10 11 12 |
/* * Copyright (c) 2017 Intel Corporation * SPDX-License-Identifier: Apache-2.0 */ #ifndef __INC_BOARD_H #define __INC_BOARD_H #define LED0_GPIO_PORT "gpio5" #define LED0_GPIO_PIN 5 #endif /* __INC_BOARD_H */ |
The way to build the app is the same as for all:
1 2 3 4 |
cd $ZEPHYR_BASE/samples/basic/blinky mkdir build && cd build cmake -GNinja -DBOARD=esp32 .. ninja flash |
The program will load to the flash. As mentioned in the documentation there’s no output in the serial console, but I did not get the user LED to blink either. So I must not have edited board.h properly, and was not able to find a solution in the amount of time I had.
Final test: networking. Our Wemos Lolin32 board has WiFi and Blutetooth, so let’s try at least WiFi with the WiFi Sample:
1 2 3 4 |
cd $ZEPHYR_BASE/samples/net/wifi mkdir build && cd build cmake -GNinja -DBOARD=esp32 .. ninja |
But sadly the build ends with an error:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/home/jaufranc/zephyr/subsys/net/ip/l2/wifi_mgmt.c:46:17: error: dereferencing pointer to incomplete type 'struct net_wifi_mgmt_offload' return off_api->connect(dev, params); ^ /home/jaufranc/zephyr/subsys/net/ip/l2/wifi_mgmt.c: In function 'wifi_scan': /home/jaufranc/zephyr/subsys/net/ip/l2/wifi_mgmt.c:84:17: error: dereferencing pointer to incomplete type 'struct net_wifi_mgmt_offload' return off_api->scan(dev, _scan_result_cb); ^ /home/jaufranc/zephyr/subsys/net/ip/l2/wifi_mgmt.c: In function 'wifi_disconnect': /home/jaufranc/zephyr/subsys/net/ip/l2/wifi_mgmt.c:101:17: error: dereferencing pointer to incomplete type 'struct net_wifi_mgmt_offload' return off_api->disconnect(dev); ^ [13/22] Building C object zephyr/kernel/CMakeFiles/kernel.dir/poll.c.obj ninja: build stopped: subcommand failed. |
The documentation reads
Verify the board and chip you are targeting provide Wi-Fi support.
For instance, Atmel’s Winc1500 chip is supported on top of quark_se_c1000_devboard board.
I had assumed ESP32 WiFi + bluetooth chip would be supported, but there’s a board directory in the sample:
1 2 |
ls boards/ quark_se_c1000_devboard.conf |
Oops, it looks like only that particular development board may support WiFi with Zephyr Project at this stage.
So Zephyr Project support for ESP32 does exist, but it seems basic/preliminary, and will not work without some serious work. It might be a better idea to get started with boards having their own specific samples like BBC micro:bit, Olimex STM32-E407, or Quark SE C1000 devboard mentioned above.
Jean-Luc started CNX Software in 2010 as a part-time endeavor, before quitting his job as a software engineering manager, and starting to write daily news, and reviews full time later in 2011.
Support CNX Software! Donate via cryptocurrencies, become a Patron on Patreon, or purchase goods on Amazon or Aliexpress
Perhaps you were just curious about Zephyr, but why not use FreeRTOS which is built specifically for the esp32 and runs on just as many boards as Zephyr. It becomes a simple case of using the Espressif instructions. Indeed, even simpler would be to use PlatformIO & FreeRTOS which work hand-in-hand by default.
You could also have saved some bother with Zephyr setup and used PlatformIO with that – it is a much neater, simpler and more robust way going forward.
Yes, my main plan was to test Zephyr. So I had to find hardware to test, and ended up using ESP32 since it was listed in supported hardware, and it’s the easiest platform to get (for free).
People in the UK who have a bbc microbit can run Zephyr on it. These boards are easy to get because they are given out in schools.
https://youtu.be/ZZRbIpVJGns
As someone who has used C for over 20 years now, I’d stick with Micropython on the ESP32. Not the IDF + FreeRTOS, Arduino, Zephyr, or anything else….MicroPython. It’s easier to use than C, fast enough and does almost everything (except Bluetooth). In fact, I’d choose the ESP32 as my platform of choice primarily because it has many relatively mature ports (Official, Loboris, WiPy) and because it does WiFi and Bluetooth (MicroPython support incoming)