Skip to content

Adding a Custom Board to Zephyr

When you are using Zephyr, you need to build your project for a specific “board”. Zephyr provides a number of boards out of the box, and you can also create your own custom boards. This tutorial shows you how to create a custom board.

Note that Zephyr’s terminology is a little confusing. A Zephyr “board” is not the same as a physical board (i.e. assembled PCB with components on it). A Zephyr board is a particular CPU instance. To quote directly from the Zephyr documentation:

Board: a particular CPU instance and its peripherals in a concrete hardware specification

Because a physical PCB may have a SoC with multiple CPUs, or even multiple SoCs which have multiple CPUs, the Zephyr definition is somewhat removed from intuition. It’s important to understand this distinction when building code.

This tutorial assumes your custom board has a nRF52840 SoC on it. However, the process is similar for other SoCs, just replace the nrf52840 with the appropriate SoC name.

Zephyr changes the way it defines boards in version ???.

Many MCU manufacturers provide example projects for their boards. These can be a great starting point for your own custom board. These boards are usually located in the Zephyr repo.

Folder Structure

There are a few different ways to structure a Zephyr project. I prefer to have the application code reside in a app/ directory, and all of the dependencies that are managed by west inside a directory called external/ (you could this whatever you want, e.g. deps/ or libs/). Before adding the custom board, this is what my folder structure looked like:

.west/
└── config
app/
├── CMakeLists.txt
├── Kconfig
├── Kconfig.zephyr
├── main.cpp
├── prj.conf
└── west.yml
external/
└── zephyr/

Having all the managed dependencies in a separate directory makes it easier to add a .gitignore for them, reduces the clutter in your root directory, and makes it easier to wipe the directory if you suspect there might be a cache issue.

Decide on a Board Name

The board name is used to identify the board in a number of places. I recommend picking a name that is in lowercase, and contains only alphanumeric characters and underscores. For this example, we will use the name my_board.

Add the Board Directory

Within our project root, create a boards/ directory. Inside that, create another directory called my_board/.

There are a few required files we need to add to the board directory for it to be a valid board:

Kconfig.my_board

Kconfig.my_board is a required file. As weird as this filename looks, yes, as per the Zephyr documentation, the extension has to be your board name! This file needs to select the correct SoC for the board.

boards/my_board/Kconfig.my_board
config BOARD_MY_BOARD
select SOC_NRF52840_QIAA

board.yml

board.yml is a required file that provides metadata about the board, such as the name, vendor and SoC.

boards/my_board/board.yml
board:
name: my_board
full_name: My Board
socs:
- name: nrf52840

Specifying a Board Root

In your .west/config file, specify the relative board root directory:

.west/config
[build]
cmake-args = -DBOARD_ROOT=../

This is the root directory of our project, which contains the boards directory. My complete .west/config file looked like this:

.west/config
[manifest]
path = app
file = west.yml
[build]
cmake-args = -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBOARD_ROOT=../
[zephyr]
base = external/zephyr

Build

Now you should be able to build your project:

Terminal window
cd app/
west build -b my_board/nrf52840

Note how the SoC you are building for is specified after a /. If the SoC had multiple CPUs, the particular CPU you are building for would also be specified here.