by  Taras Kurnytskyi

Zephyr RTOS: Application Development

clock-icon-white  5 min read

In our previous blog, we discussed general issues related to Zephyr RTOS. Here, we will uncover more details about Zephyr and the application development process.

Zephyr RTOS social

The Best of Linux

As a Linux Foundation project, Zephyr naturally inherits the best development features and tools from Linux, including:

  • Developed infrastructure for existing platforms compilation with simple extension tools
  • Powerful driver development tool based on device tree structure approach
  • Flexible and orthogonal configuration
  • Easy IDE and Python integration, powerful command line tool (west)
  • POSIX compatible API

Getting started

To start application development, you need to:

  1. Install cmake version 3.13.1 or higher
  2. Install west
  3. Run west init [target directory] command
  4. Switch to [target directory], and then run west update

After running the last two commands, the latest Zephyr OS repository will reside in the target directory. To complete setup, Zephyr’s Software Development Kit (SDK) must be downloaded and installed. You will also need to set proper environmental scripts and run these scripts.

Application development. Standard boards

Zephyr’s base directory hosts Zephyr’s own source code, its kernel configuration options, and its build definitions. It can reside anywhere, but the location is controlled by west update command, where [target directory] for Zephyr’s own code is specified. For the application to know this location—as well as other setting parameters—you need to run the script residing in root Zephyr’s directory prior to application building.

At minimum, Zephyr’s application folder (app) needs to contain the following items (files):

  • CmakeLists.txt
  • prj.conf
  • Kconfig
  • src/*.c

As a result, the binary image is being built and placed in an automatically created build/zephyr folder.

Build control

The Zephyr build system is very flexible and uses many variables.

The most used are ZEPHYR_BASE, BOARD, and DTC_OVERLAY_FILE which can be supplied to the build system in different ways: either as parameters to west command, as an environmental variable, or as a proper statement in the CMakeLists.txt file.

Build stages

The Zephyr build process consists of two main stages: configuration and build.

Configuration stage

Driven by CMake, this stage is rather complicated with many files involved throughout the Zephyr hierarchy.

Source and more detail at

Build stages

Driven by Make (or Ninja), this stage can be subdivided into two sub-stages: first (pre-build) and second (final).

At the first (principal) stage, source files from various subsystems are included into build, depending on the configuration settings made at the previous stage. They are compiled into archives with a reference to header files in the tree. Header files generated during the configuration phase are included as well. Binary zephyr_prebuilt.elf is generated at this stage.

The final binary image zephyr.elf is generated at the second stage. This stage is needed because in some configurations, the binary from the previous stage is incomplete with empty placeholder sections that must be filled in. Dedicated Python script runs to gather missing information and eventually the final binary is built. More details can be found at

Application development. Custom boards

For known boards, a device tree structure describing board hardware is predefined and well described. The process becomes complicated in case of an application development for a custom board. Fortunately, the majority of custom boards are based on known MPUs—simplifying the development process. For this purpose, Zephyr introduced a notion of device tree overlays.

Let’s review how the process works for custom hardware with environmental sensors on board.

Enabling known sensor

Zephyr has implemented drivers for a vast majority of sensors. If the custom hardware has a sensor on board, then the Zephyr build system must be properly configured to include sensor functionality in the final binary image.

Adding new sensor

If a sensor driver is not implemented, the same work performed by Zephyr for a known sensor should be done manually by a developer.

Zephyr considers sensors to be a part of hardware. As a result, like all basic hardware, Zephyr manages sensor initialization as a preliminary step, or at least at some point prior to the start of an application’s main function. If properly set up and initialized, sensors will be ready for use at app start. (Developers need to obtain sensor handle by the unique sensor name, and then use sensor API functions to manipulate sensor data.)


At the first glance, it may seem that Zephyr is not easy to work with, and that using an SDK and toolchain developed for a particular SoC or MPU is more straightforward. But, moving to another board requires being familiar with the new SDK and toolchain and using Zephyr makes migration smoother and more flexible.

SoftServe’s R&D team keeps one finger on the pulse of technology to foresee and accelerate where breakthrough opportunities exist for solving specific business needs.

Let’s talk about your Zephyr experiences and where you are in your enterprise digital journey.