Getting started with Zephyr
This article will explain how to setup a local Zephyr development environment. I will do this for development on de NXP FRDM-MCXA156, but you can use this tutorial for any board supported on Zephyr. I will mention every platform specific setup I do, so you can alter it for your usecase.
Setting up a west workspace
First we need to create a workspace. In this tutorial I chose to go for topology 2, where our application is the manifest repository. For more information about the supported toplogies refer to this.
Creating the workspace folder
To start setting up a workspace we make a new folder in a suitable location, for example the home directory.
1mkdir zephyr-ws
The name of this folder does not matter. In Zephyr development this folder is called the topdir. Next we go into this folder
1cd zephyr-ws
Adding a basic application
Inside this folder we create a new directory where our application will live. I named it app, but this name also doesn’t matter.
A folder alone isn’t an application so we will need some files.
zephyr-ws
└── app
├── CMakeLists.txt
├── prj.conf
├── src
│ └── main.c
└── west.yml
This is the tree structure of a minimal Zephyr application. For this tutorial I went with a basic blink program.
west.yml
1manifest:
2 version: 1.0
3
4 projects:
5 - name: zephyr
6 url: https://github.com/zephyrproject-rtos/zephyr
7 revision: v4.4.0
8 import:
9 name-allowlist:
10 - hal_nxp
11 - cmsis_6
This is the manifest file. I used version 1.0 and included Zephyr v4.4.0. You can of course choose whatever version you want.
I also import the necessary projects from the Zephyr west.yml file which, in my case, are hal_nxp and cmsis_6. This will be different depending on what boards you are using. I’m using a NXP board, so this is what I need for my basic project.
main.c
1#include <zephyr/drivers/gpio.h>
2#include <zephyr/kernel.h>
3
4#define LED_NODE DT_ALIAS(led0)
5#define BLINK_MS 1000
6
7static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED_NODE, gpios);
8
9int main(void)
10{
11 bool led_state = true;
12
13 if (!gpio_is_ready_dt(&led)) {
14 return 0;
15 }
16
17 if (gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE) < 0) {
18 return 0;
19 }
20
21 while (true) {
22 if (gpio_pin_toggle_dt(&led) < 0) {
23 return 0;
24 }
25
26 led_state = !led_state;
27 k_msleep(BLINK_MS);
28 }
29
30 return 0;
31}
This blink code should work on any board with led0 defined.
prj.conf
CONFIG_GPIO=y
We only need to enable the GPIO for this basic example.
CMakeLists.txt
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(blink)
target_sources(app PRIVATE src/main.c)
With all these files you now have a minimal blink application.
If you use git, the content of this folder is the thing you manage. Anything outside this folder does not need to be tracked by git.
Installing and initializing west
west is installed via pip, so we will need to create a virtual environment (or venv).
Run this in the topdir, in my case zephyr-ws:
1python3 -m venv .venv
2source .venv/bin/activate
3pip install west
This will install the west application in the virtual environment. Everytime you want to work with west, you will have to activate the venv.
Next we actually initialize our workspace:
1west init -l app/
This command will create a workspace around our application in the manifest repository; app in my case.
The output of this command will tell you to run west update, so we will do this next.
1west update
This will update the projects defined in the manifest file.
In my case it will download Zephyr V4.4.0 and the imports I’ve allowed: hal_nxp and cmsis_6.
Next we will run:
1west zephyr-export
This will register the Zephyr installation with CMake, so we can succesfully build it.
Installing the Zephyr SDK
Now we will finally install the SDK. This only takes one command to do:
1west sdk install
Building and flashing
To build the application we use the west build command:
1west build -b frdm_mcxa156 app --pristine
Here I choose to build app for my NXP board. If you use another board, choose that one instead of course.
The pristine flag tells west to build everything, everytime. That way I can be sure the build file always represents the current code.
Next comes flashing. For this you will need a runner that can flash your specific board. In my case I can use pyocd, so I will need to install it.
1pip install pyocd
I will also install the pack for my specific chip:
1pyocd pack install MCXA156
If everything works well, and you connect your board to your computer and run
1pyocd list
you should see your board in the list.
If this does not happen you might not be part of the dialout group or you don’t have the correct udev rules installed.
To fix this run
1sudo usermod -aG dialout $USER
to add your user to the dialout group. You might need to restart your computer for this to take effect.
If you use a NXP board, to set the correct udev rules you can download the rules from the pyocd github and add them to /etc/udev/rules.d/.
After you’ve done this run
1sudo udevadm control --reload-rules
2sudo udevadm trigger
to register these rules.
To flash your board just run:
1west flash --runner pyocd
Result
If everything went well you should have a board with a blinking LED running Zephyr.