官方英文原文 · 站内阅读
以下完整保留 Zephyr v4.2.0 的 8 份英文 RST 原文,展开即可阅读。RST 中的 Sphinx 指令保持原样,未改写为可执行命令。中文操作步骤请从左侧学习路线进入。
来源:Zephyr Project contributors。许可证:Apache-2.0。本站仅添加阅读容器,原文件内容不变;详细来源见资料索引。
Getting Started Guide
展开英文原文(RST)
.. _getting_started:
Getting Started Guide
#####################
Follow this guide to:
- Set up a command-line Zephyr development environment on Ubuntu, macOS, or
Windows (instructions for other Linux distributions are discussed in
:ref:`installation_linux`)
- Get the source code
- Build, flash, and run a sample application
.. _host_setup:
Select and Update OS
********************
Click the operating system you are using.
.. tabs::
.. group-tab:: Ubuntu
This guide covers Ubuntu version 22.04 LTS and later.
If you are using a different Linux distribution see :ref:`installation_linux`.
.. code-block:: bash
sudo apt update
sudo apt upgrade
.. group-tab:: macOS
On macOS Mojave or later, select *System Preferences* >
*Software Update*. Click *Update Now* if necessary.
On other versions, see `this Apple support topic
<https://support.apple.com/en-us/HT201541>`_.
.. group-tab:: Windows
Select *Start* > *Settings* > *Update & Security* > *Windows Update*.
Click *Check for updates* and install any that are available.
.. _install-required-tools:
Install dependencies
********************
Next, you'll install some host dependencies using your package manager.
The current minimum required version for the main dependencies are:
.. list-table::
:header-rows: 1
* - Tool
- Min. Version
* - `CMake <https://cmake.org/>`_
- 3.20.5
* - `Python <https://www.python.org/>`_
- 3.10
* - `Devicetree compiler <https://www.devicetree.org/>`_
- 1.4.6
.. tabs::
.. group-tab:: Ubuntu
.. _install_dependencies_ubuntu:
#. Use ``apt`` to install the required dependencies:
.. code-block:: bash
sudo apt install --no-install-recommends git cmake ninja-build gperf \
ccache dfu-util device-tree-compiler wget python3-dev python3-venv python3-tk \
xz-utils file make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1
.. note::
Due to the unavailability of ``gcc-multilib`` and ``g++-multilib`` on AArch64
(ARM64) systems, you may need to remove them from the list of packages to install.
#. Verify the versions of the main dependencies installed on your system by entering:
.. code-block:: bash
cmake --version
python3 --version
dtc --version
Check those against the versions in the table in the beginning of this section.
Refer to the :ref:`installation_linux` page for additional information on updating
the dependencies manually.
.. group-tab:: macOS
.. _install_dependencies_macos:
#. Install `Homebrew <https://brew.sh/>`_:
.. code-block:: bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
#. After the Homebrew installation script completes, follow the on-screen
instructions to add the Homebrew installation to the path.
* On macOS running on Apple Silicon, this is achieved with:
.. code-block:: bash
(echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> ~/.zprofile
source ~/.zprofile
* On macOS running on Intel, use the command for Apple Silicon, but replace ``/opt/homebrew/`` with ``/usr/local/``.
#. Use ``brew`` to install the required dependencies:
.. code-block:: bash
brew install cmake ninja gperf python3 python-tk ccache qemu dtc libmagic wget openocd
#. Add the Homebrew Python folder to the path, in order to be able to
execute ``python`` and ``pip`` as well ``python3`` and ``pip3``.
.. code-block:: bash
(echo; echo 'export PATH="'$(brew --prefix)'/opt/python/libexec/bin:$PATH"') >> ~/.zprofile
source ~/.zprofile
.. group-tab:: Windows
.. note::
Due to issues finding executables, the Zephyr Project doesn't
currently support application flashing using the `Windows Subsystem
for Linux (WSL)
<https://msdn.microsoft.com/en-us/commandline/wsl/install_guide>`_
(WSL).
Therefore, we don't recommend using WSL when getting started.
In modern version of Windows (10 and later) it is recommended to install the Windows Terminal
application from the Microsoft Store. Instructions are provided for a ``cmd.exe`` or
PowerShell command prompts.
These instructions rely on Windows' official package manager, `winget`_.
If using winget isn't an option, you can install dependencies from their
respective websites and ensure the command line tools are on your
:envvar:`PATH` :ref:`environment variable <env_vars>`.
|p|
.. _install_dependencies_windows:
#. In modern Windows versions, winget is already pre-installed by default.
You can verify that this is the case by typing ``winget`` in a terminal
window. If that fails, you can then `install winget`_.
#. Open a Command Prompt (``cmd.exe``) or PowerShell terminal window.
To do so, press the Windows key, type ``cmd.exe`` or PowerShell and
click on the result.
#. Use ``winget`` to install the required dependencies:
.. code-block:: bat
winget install Kitware.CMake Ninja-build.Ninja oss-winget.gperf python Git.Git oss-winget.dtc wget 7zip.7zip
#. Close the terminal window.
.. note::
You may need to add the 7zip installation folder to your ``PATH``.
.. _winget: https://learn.microsoft.com/en-us/windows/package-manager/
.. _install winget: https://aka.ms/getwinget
.. _get_the_code:
.. _clone-zephyr:
.. _install_py_requirements:
.. _gs_python_deps:
Get Zephyr and install Python dependencies
******************************************
Next, clone Zephyr and its :ref:`modules <modules>` into a new :ref:`west
<west>` workspace. In the following instructions the name :file:`zephyrproject`
is used for the workspace, however in practice its name and location can be freely
chosen. You'll also install Zephyr's additional Python dependencies in a
`Python virtual environment`_.
.. _Python virtual environment: https://docs.python.org/3/library/venv.html
.. tabs::
.. group-tab:: Ubuntu
#. Create a new virtual environment:
.. code-block:: bash
python3 -m venv ~/zephyrproject/.venv
#. Activate the virtual environment:
.. code-block:: bash
source ~/zephyrproject/.venv/bin/activate
Once activated your shell will be prefixed with ``(.venv)``. The
virtual environment can be deactivated at any time by running
``deactivate``.
.. note::
Remember to activate the virtual environment every time you
start working.
#. Install west:
.. code-block:: bash
pip install west
#. Get the Zephyr source code:
.. only:: not release
.. code-block:: bash
west init ~/zephyrproject
cd ~/zephyrproject
west update
.. only:: release
.. We need to use a parsed-literal here because substitutions do not work in code
blocks. This means users can't copy-paste these lines as easily as other blocks but
should be good enough still :)
.. parsed-literal::
west init ~/zephyrproject --mr v |zephyr-version-ltrim|
cd ~/zephyrproject
west update
#. Export a :ref:`Zephyr CMake package <cmake_pkg>`. This allows CMake to
automatically load boilerplate code required for building Zephyr
applications.
.. code-block:: bash
west zephyr-export
#. The Zephyr west extension command, ``west packages`` can be used to install Python
dependencies.
.. code-block:: bash
west packages pip --install
.. group-tab:: macOS
#. Create a new virtual environment:
.. code-block:: bash
python3 -m venv ~/zephyrproject/.venv
#. Activate the virtual environment:
.. code-block:: bash
source ~/zephyrproject/.venv/bin/activate
Once activated your shell will be prefixed with ``(.venv)``. The
virtual environment can be deactivated at any time by running
``deactivate``.
.. note::
Remember to activate the virtual environment every time you
start working.
#. Install west:
.. code-block:: bash
pip install west
#. Get the Zephyr source code:
.. code-block:: bash
west init ~/zephyrproject
cd ~/zephyrproject
west update
#. Export a :ref:`Zephyr CMake package <cmake_pkg>`. This allows CMake to
automatically load boilerplate code required for building Zephyr
applications.
.. code-block:: bash
west zephyr-export
#. The Zephyr west extension command, ``west packages`` can be used to install Python
dependencies.
.. code-block:: bash
west packages pip --install
.. group-tab:: Windows
#. Open a ``cmd.exe`` or PowerShell terminal window **as a regular user**
#. Create a new virtual environment:
.. tabs::
.. code-tab:: bat
cd %HOMEPATH%
python -m venv zephyrproject\.venv
.. code-tab:: powershell
cd $Env:HOMEPATH
python -m venv zephyrproject\.venv
#. Activate the virtual environment:
.. tabs::
.. code-tab:: bat
zephyrproject\.venv\Scripts\activate.bat
.. code-tab:: powershell
zephyrproject\.venv\Scripts\Activate.ps1
Once activated your shell will be prefixed with ``(.venv)``. The
virtual environment can be deactivated at any time by running
``deactivate``.
.. note::
Remember to activate the virtual environment every time you
start working.
#. Install west:
.. code-block:: bat
pip install west
#. Get the Zephyr source code:
.. code-block:: bat
west init zephyrproject
cd zephyrproject
west update
#. Export a :ref:`Zephyr CMake package <cmake_pkg>`. This allows CMake to
automatically load boilerplate code required for building Zephyr
applications.
.. code-block:: bat
west zephyr-export
#. The Zephyr west extension command, ``west packages`` can be used to install Python
dependencies.
.. code-block:: bat
west packages pip --install
Install the Zephyr SDK
**********************
The :ref:`Zephyr Software Development Kit (SDK) <toolchain_zephyr_sdk>`
contains toolchains for each of Zephyr's supported architectures, which
include a compiler, assembler, linker and other programs required to build
Zephyr applications.
For Linux, it also contains additional host tools, such as custom QEMU and OpenOCD builds
that are used to emulate, flash and debug Zephyr applications.
.. tabs::
.. group-tab:: Ubuntu
Install the Zephyr SDK using the ``west sdk install``.
.. code-block:: bash
cd ~/zephyrproject/zephyr
west sdk install
.. tip::
Using the command options, you can specify the SDK installation destination
and which architecture of toolchains to install.
See ``west sdk install --help`` for details.
.. group-tab:: macOS
Install the Zephyr SDK using the ``west sdk install``.
.. code-block:: bash
cd ~/zephyrproject/zephyr
west sdk install
.. tip::
Using the command options, you can specify the SDK installation destination
and which architecture of toolchains to install.
See ``west sdk install --help`` for details.
.. group-tab:: Windows
Install the Zephyr SDK using the ``west sdk install``.
.. tabs::
.. code-tab:: bat
cd %HOMEPATH%\zephyrproject\zephyr
west sdk install
.. code-tab:: powershell
cd $Env:HOMEPATH\zephyrproject\zephyr
west sdk install
.. tip::
Using the command options, you can specify the SDK installation destination
and which architecture of toolchains to install.
See ``west sdk install --help`` for details.
.. note::
If you want to install Zephyr SDK without using the ``west sdk`` command,
please see :ref:`toolchain_zephyr_sdk_install`.
.. _getting_started_run_sample:
Build the Blinky Sample
***********************
.. note::
:zephyr:code-sample:`blinky` is compatible with most, but not all, :ref:`boards`. If your board
does not meet Blinky's :ref:`blinky-sample-requirements`, then
:zephyr:code-sample:`hello_world` is a good alternative.
If you are unsure what name west uses for your board, ``west boards``
can be used to obtain a list of all boards Zephyr supports.
Build the :zephyr:code-sample:`blinky` with :ref:`west build <west-building>`, changing
``<your-board-name>`` appropriately for your board:
.. tabs::
.. group-tab:: Ubuntu
.. code-block:: bash
cd ~/zephyrproject/zephyr
west build -p always -b <your-board-name> samples/basic/blinky
.. group-tab:: macOS
.. code-block:: bash
cd ~/zephyrproject/zephyr
west build -p always -b <your-board-name> samples/basic/blinky
.. group-tab:: Windows
.. tabs::
.. code-tab:: bat
cd %HOMEPATH%\zephyrproject\zephyr
west build -p always -b <your-board-name> samples\basic\blinky
.. code-tab:: powershell
cd $Env:HOMEPATH\zephyrproject\zephyr
west build -p always -b <your-board-name> samples\basic\blinky
The ``-p always`` option forces a pristine build, and is recommended for new
users. Users may also use the ``-p auto`` option, which will use
heuristics to determine if a pristine build is required, such as when building
another sample.
.. note::
A board may contain one or multiple SoCs, Also, each SoC may contain one or
more CPU clusters.
When building for such boards it is necessary to specify the SoC or CPU
cluster for which the sample must be built.
For example to build :zephyr:code-sample:`blinky` for the ``cpuapp`` core on
the :zephyr:board:`nrf5340dk` the board must be provided as:
``nrf5340dk/nrf5340/cpuapp``. See also :ref:`board_terminology` for more
details.
Flash the Sample
****************
Connect your board, usually via USB, and turn it on if there's a power switch.
If in doubt about what to do, check your board's page in :ref:`boards`.
Then flash the sample using :ref:`west flash <west-flashing>`:
.. code-block:: shell
west flash
.. note::
You may need to install additional :ref:`host tools <flash-debug-host-tools>`
required by your board. The ``west flash`` command will print an error if any
required dependencies are missing.
.. note::
When using Linux, you may need to configure udev rules the first time
of using a debug probe.
Please also see :ref:`setting-udev-rules`.
If you're using blinky, the LED will start to blink as shown in this figure:
.. figure:: img/ReelBoard-Blinky.png
:width: 400px
:name: reelboard-blinky
Phytec :ref:`reel_board <reel_board>` running blinky
Next Steps
**********
Here are some next steps for exploring Zephyr:
* Try other :zephyr:code-sample-category:`samples`
* Learn about :ref:`application` and the :ref:`west <west>` tool
* Find out about west's :ref:`flashing and debugging <west-build-flash-debug>`
features, or more about :ref:`flashing_and_debugging` in general
* Check out :ref:`beyond-GSG` for additional setup alternatives and ideas
* Discover :ref:`project-resources` for getting help from the Zephyr
community
.. _troubleshooting_installation:
Troubleshooting Installation
****************************
Here are some tips for fixing some issues related to the installation process.
.. _toolchain_zephyr_sdk_update:
Double Check the Zephyr SDK Variables When Updating
===================================================
When updating Zephyr SDK, check whether the :envvar:`ZEPHYR_TOOLCHAIN_VARIANT`
or :envvar:`ZEPHYR_SDK_INSTALL_DIR` environment variables are already set.
See :ref:`gs_toolchain_update` for more information.
For more information about these environment variables in Zephyr, see :ref:`env_vars_important`.
.. _help:
Asking for Help
***************
You can ask for help on a mailing list or on Discord. Please send bug reports and
feature requests to GitHub.
* **Mailing Lists**: users@lists.zephyrproject.org is usually the right list to
ask for help. `Search archives and sign up here`_.
* **Discord**: You can join with this `Discord invite`_.
* **GitHub**: Use `GitHub issues`_ for bugs and feature requests.
How to Ask
==========
.. important::
Please search this documentation and the mailing list archives first. Your
question may have an answer there.
Don't just say "this isn't working" or ask "is this working?". Include as much
detail as you can about:
#. What you want to do
#. What you tried (commands you typed, etc.)
#. What happened (output of each command, etc.)
Use Copy/Paste
==============
Please **copy/paste text** instead of taking a picture or a screenshot of it.
Text includes source code, terminal commands, and their output.
Doing this makes it easier for people to help you, and also helps other users
search the archives. Unnecessary screenshots exclude vision impaired
developers; some are major Zephyr contributors. `Accessibility`_ has been
recognized as a basic human right by the United Nations.
When copy/pasting more than 5 lines of computer text into Discord or Github,
create a snippet using three backticks to delimit the snippet.
.. _Search archives and sign up here: https://lists.zephyrproject.org/g/users
.. _Discord invite: https://chat.zephyrproject.org
.. _GitHub issues: https://github.com/zephyrproject-rtos/zephyr/issues
.. _Accessibility: https://www.w3.org/standards/webdesign/accessibility
Install Linux Host Dependencies
展开英文原文(RST)
.. _installation_linux:
Install Linux Host Dependencies
###############################
Documentation is available for these Linux distributions:
* Ubuntu
* Fedora
* Clear Linux
* Arch Linux
For distributions that are not based on rolling releases, some of the
requirements and dependencies may not be met by your package manager. In that
case please follow the additional instructions that are provided to find
software from sources other than the package manager.
.. note:: If you're working behind a corporate firewall, you'll likely
need to configure a proxy for accessing the internet, if you haven't
done so already. While some tools use the environment variables
``http_proxy`` and ``https_proxy`` to get their proxy settings, some
use their own configuration files, most notably ``apt`` and
``git``.
Update Your Operating System
****************************
Ensure your host system is up to date.
.. tabs::
.. group-tab:: Ubuntu
.. code-block:: console
sudo apt-get update
sudo apt-get upgrade
.. group-tab:: Fedora
.. code-block:: console
sudo dnf upgrade
.. group-tab:: Clear Linux
.. code-block:: console
sudo swupd update
.. group-tab:: Arch Linux
.. code-block:: console
sudo pacman -Syu
.. _linux_requirements:
Install Requirements and Dependencies
*************************************
.. NOTE FOR DOCS AUTHORS: DO NOT PUT DOCUMENTATION BUILD DEPENDENCIES HERE.
This section is for dependencies to build Zephyr binaries, *NOT* this
documentation. If you need to add a dependency only required for building
the docs, add it to doc/README.rst. (This change was made following the
introduction of LaTeX->PDF support for the docs, as the texlive footprint is
massive and not needed by users not building PDF documentation.)
Note that both Ninja and Make are installed with these instructions; you only
need one.
.. tabs::
.. group-tab:: Ubuntu
.. code-block:: console
sudo apt-get install --no-install-recommends git cmake ninja-build gperf \
ccache dfu-util device-tree-compiler wget \
python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \
make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1
.. group-tab:: Fedora
.. code-block:: console
sudo dnf group install "Development Tools" "C Development Tools and Libraries"
sudo dnf install cmake ninja-build gperf dfu-util dtc wget which \
python3-pip python3-tkinter xz file python3-devel SDL2-devel
.. group-tab:: Clear Linux
.. code-block:: console
sudo swupd bundle-add c-basic dev-utils dfu-util dtc \
os-core-dev python-basic python3-basic python3-tcl
The Clear Linux focus is on *native* performance and security and not
cross-compilation. For that reason it uniquely exports by default to the
:ref:`environment <env_vars>` of all users a list of compiler and linker
flags. Zephyr's CMake build system will either warn or fail because of
these. To clear the C/C++ flags among these and fix the Zephyr build, run
the following command as root then log out and back in:
.. code-block:: console
echo 'unset CFLAGS CXXFLAGS' >> /etc/profile.d/unset_cflags.sh
Note this command unsets the C/C++ flags for *all users on the
system*. Each Linux distribution has a unique, relatively complex and
potentially evolving sequence of bash initialization files sourcing each
other and Clear Linux is no exception. If you need a more flexible
solution, start by looking at the logic in
``/usr/share/defaults/etc/profile``.
.. group-tab:: Arch Linux
.. code-block:: console
sudo pacman -S git cmake ninja gperf ccache dfu-util dtc wget \
python-pip python-setuptools python-wheel tk xz file make
CMake
=====
A :ref:`recent CMake version <install-required-tools>` is required. Check what
version you have by using ``cmake --version``. If you have an older version,
there are several ways of obtaining a more recent one:
* On Ubuntu, you can follow the instructions for adding the
`kitware third-party apt repository <https://apt.kitware.com/>`_
to get an updated version of cmake using apt.
* Download and install a packaged cmake from the CMake project site.
(Note this won't uninstall the previous version of cmake.)
.. code-block:: console
cd ~
wget https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1-Linux-x86_64.sh
chmod +x cmake-3.21.1-Linux-x86_64.sh
sudo ./cmake-3.21.1-Linux-x86_64.sh --skip-license --prefix=/usr/local
hash -r
The ``hash -r`` command may be necessary if the installation script
put cmake into a new location on your PATH.
* Download and install from the pre-built binaries provided by the CMake
project itself in the `CMake Downloads`_ page.
For example, to install version 3.21.1 in :file:`~/bin/cmake`:
.. code-block:: console
mkdir $HOME/bin/cmake && cd $HOME/bin/cmake
wget https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1-Linux-x86_64.sh
yes | sh cmake-3.21.1-Linux-x86_64.sh | cat
echo "export PATH=$PWD/cmake-3.21.1-Linux-x86_64/bin:\$PATH" >> $HOME/.zephyrrc
* Use ``pip3``:
.. code-block:: console
pip3 install --user cmake
Note this won't uninstall the previous version of cmake and will
install the new cmake into your ~/.local/bin folder so
you'll need to add ~/.local/bin to your PATH. (See :ref:`python-pip`
for details.)
* Check your distribution's beta or unstable release package library for an
update.
* On Ubuntu you can also use snap to get the latest version available:
.. code-block:: console
sudo snap install cmake
After updating cmake, verify that the newly installed cmake is found
using ``cmake --version``.
You might also want to uninstall the CMake provided by your package manager to
avoid conflicts. (Use ``whereis cmake`` to find other installed
versions.)
DTC (Device Tree Compiler)
==========================
A :ref:`recent DTC version <install-required-tools>` is required. Check what
version you have by using ``dtc --version``. If you have an older version,
either install a more recent one by building from source, or use the one that is
bundled in the :ref:`Zephyr SDK <toolchain_zephyr_sdk>` by installing it.
Python
======
A :ref:`modern Python 3 version <install-required-tools>` is required. Check
what version you have by using ``python3 --version``.
If you have an older version, you will need to install a more recent Python 3.
You can build from source, or use a backport from your distribution's package
manager channels if one is available. Isolating this Python in a virtual
environment is recommended to avoid interfering with your system Python.
.. _pyenv: https://github.com/pyenv/pyenv
Install the Zephyr Software Development Kit (SDK)
*************************************************
The Zephyr Software Development Kit (SDK) contains toolchains for each of
Zephyr's supported architectures. It also includes additional host tools, such
as custom QEMU and OpenOCD.
Use of the Zephyr SDK is highly recommended and may even be required under
certain conditions (for example, running tests in QEMU for some architectures).
The Zephyr SDK supports the following target architectures:
* ARC (32-bit and 64-bit; ARCv1, ARCv2, ARCv3)
* ARM (32-bit and 64-bit; ARMv6, ARMv7, ARMv8; A/R/M Profiles)
* MIPS (32-bit and 64-bit)
* RISC-V (32-bit and 64-bit; RV32I, RV32E, RV64I)
* x86 (32-bit and 64-bit)
* Xtensa
Follow these steps to install the Zephyr SDK:
#. Download and verify the `Zephyr SDK bundle`_:
.. parsed-literal::
wget |sdk-url-linux|
wget -O - |sdk-url-linux-sha| | shasum --check --ignore-missing
You can change |sdk-version-literal| to another version if needed; the
`Zephyr SDK Releases`_ page contains all available SDK releases.
If your host architecture is 64-bit ARM (for example, Raspberry Pi), replace
``x86_64`` with ``aarch64`` in order to download the 64-bit ARM Linux SDK.
#. Extract the Zephyr SDK bundle archive:
.. parsed-literal::
cd <sdk download directory>
tar xvf zephyr-sdk- |sdk-version-trim| _linux-x86_64.tar.xz
#. Run the Zephyr SDK bundle setup script:
.. parsed-literal::
cd zephyr-sdk- |sdk-version-ltrim|
./setup.sh
If this fails, make sure Zephyr's dependencies were installed as described
in `Install Requirements and Dependencies`_.
If you want to uninstall the SDK, remove the directory where you installed it.
If you relocate the SDK directory, you need to re-run the setup script.
.. note::
It is recommended to extract the Zephyr SDK bundle at one of the following locations:
* ``$HOME``
* ``$HOME/.local``
* ``$HOME/.local/opt``
* ``$HOME/bin``
* ``/opt``
* ``/usr/local``
The Zephyr SDK bundle archive contains the ``zephyr-sdk-<version>``
directory and, when extracted under ``$HOME``, the resulting installation
path will be ``$HOME/zephyr-sdk-<version>``.
If you install the Zephyr SDK outside any of these locations, you must
register the Zephyr SDK in the CMake package registry by running the setup
script, or set :envvar:`ZEPHYR_SDK_INSTALL_DIR` to point to the Zephyr SDK
installation directory.
You can also use :envvar:`ZEPHYR_SDK_INSTALL_DIR` for pointing to a
directory containing multiple Zephyr SDKs, allowing for automatic toolchain
selection. For example, ``ZEPHYR_SDK_INSTALL_DIR=/company/tools``, where
the ``company/tools`` folder contains the following subfolders:
* ``/company/tools/zephyr-sdk-0.13.2``
* ``/company/tools/zephyr-sdk-a.b.c``
* ``/company/tools/zephyr-sdk-x.y.z``
This allows the Zephyr build system to choose the correct version of the
SDK, while allowing multiple Zephyr SDKs to be grouped together at a
specific path.
.. _sdkless_builds:
Building on Linux without the Zephyr SDK
****************************************
The Zephyr SDK is provided for convenience and ease of use. It provides
toolchains for all Zephyr target architectures, and does not require any extra
flags when building applications or running tests. In addition to
cross-compilers, the Zephyr SDK also provides prebuilt host tools. It is,
however, possible to build without the SDK's toolchain by using another
toolchain as described in the :ref:`toolchains` section.
As already noted above, the SDK also includes prebuilt host tools. To use the
SDK's prebuilt host tools with a toolchain from another source, you must set the
:envvar:`ZEPHYR_SDK_INSTALL_DIR` environment variable to the Zephyr SDK
installation directory. To build without the Zephyr SDK's prebuilt host tools,
the :envvar:`ZEPHYR_SDK_INSTALL_DIR` environment variable must be unset.
To make sure this variable is unset, run:
.. code-block:: console
unset ZEPHYR_SDK_INSTALL_DIR
.. _Zephyr SDK Releases: https://github.com/zephyrproject-rtos/sdk-ng/tags
.. _CMake Downloads: https://cmake.org/download
ESP32-DevKitC
展开英文原文(RST)
.. zephyr:board:: esp32_devkitc
Overview
********
ESP32 is a series of low cost, low power system on a chip microcontrollers
with integrated Wi-Fi & dual-mode Bluetooth. The ESP32 series employs a
Tensilica Xtensa LX6 microprocessor in both dual-core and single-core
variations. ESP32 is created and developed by Espressif Systems, a
Shanghai-based Chinese company, and is manufactured by TSMC using their 40nm
process. For more information, check `ESP32-DevKitC`_.
The features include the following:
- Dual core Xtensa microprocessor (LX6), running at 160 or 240MHz
- 520KB of SRAM
- 802.11b/g/n/e/i
- Bluetooth v4.2 BR/EDR and BLE
- Various peripherals:
- 12-bit ADC with up to 18 channels
- 2x 8-bit DACs
- 10x touch sensors
- Temperature sensor
- 4x SPI
- 2x I2S
- 2x I2C
- 3x UART
- SD/SDIO/MMC host
- Slave (SDIO/SPI)
- Ethernet MAC
- CAN bus 2.0
- IR (RX/TX)
- Motor PWM
- LED PWM with up to 16 channels
- Hall effect sensor
- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES)
- 5uA deep sleep current
For more information, check the datasheet at `ESP32 Datasheet`_ or the technical reference
manual at `ESP32 Technical Reference Manual`_.
Asymmetric Multiprocessing (AMP)
********************************
ESP32-DevKitC-WROVER allows 2 different applications to be executed in ESP32 SoC. Due to its dual-core architecture, each core can be enabled to execute customized tasks in stand-alone mode
and/or exchanging data over OpenAMP framework. See :zephyr:code-sample-category:`ipc` folder as code reference.
Supported Features
==================
.. zephyr:board-supported-hw::
System requirements
===================
Prerequisites
-------------
Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command
below to retrieve those files.
.. code-block:: console
west blobs fetch hal_espressif
.. note::
It is recommended running the command above after :file:`west update`.
Building & Flashing
*******************
.. zephyr:board-supported-runners::
Simple boot
===========
The board could be loaded using the single binary image, without 2nd stage bootloader.
It is the default option when building the application without additional configuration.
.. note::
Simple boot does not provide any security features nor OTA updates.
MCUboot bootloader
==================
User may choose to use MCUboot bootloader instead. In that case the bootloader
must be built (and flashed) at least once.
There are two options to be used when building an application:
1. Sysbuild
2. Manual build
.. note::
User can select the MCUboot bootloader by adding the following line
to the board default configuration file.
.. code:: cfg
CONFIG_BOOTLOADER_MCUBOOT=y
Sysbuild
========
The sysbuild makes possible to build and flash all necessary images needed to
bootstrap the board with the ESP32 SoC.
To build the sample application using sysbuild use the command:
.. zephyr-app-commands::
:tool: west
:zephyr-app: samples/hello_world
:board: esp32_devkitc
:goals: build
:west-args: --sysbuild
:compact:
By default, the ESP32 sysbuild creates bootloader (MCUboot) and application
images. But it can be configured to create other kind of images.
Build directory structure created by sysbuild is different from traditional
Zephyr build. Output is structured by the domain subdirectories:
.. code-block::
build/
├── hello_world
│ └── zephyr
│ ├── zephyr.elf
│ └── zephyr.bin
├── mcuboot
│ └── zephyr
│ ├── zephyr.elf
│ └── zephyr.bin
└── domains.yaml
.. note::
With ``--sysbuild`` option the bootloader will be re-build and re-flash
every time the pristine build is used.
For more information about the system build please read the :ref:`sysbuild` documentation.
Manual build
============
During the development cycle, it is intended to build & flash as quickly possible.
For that reason, images can be built one at a time using traditional build.
The instructions following are relevant for both manual build and sysbuild.
The only difference is the structure of the build directory.
.. note::
Remember that bootloader (MCUboot) needs to be flash at least once.
Build and flash applications as usual (see :ref:`build_an_application` and
:ref:`application_run` for more details).
.. zephyr-app-commands::
:zephyr-app: samples/hello_world
:board: esp32_devkitc/esp32/procpu
:goals: build
The usual ``flash`` target will work with the ``esp32_devkitc`` board
configuration. Here is an example for the :zephyr:code-sample:`hello_world`
application.
.. zephyr-app-commands::
:zephyr-app: samples/hello_world
:board: esp32_devkitc/esp32/procpu
:goals: flash
Open the serial monitor using the following command:
.. code-block:: shell
west espressif monitor
After the board has automatically reset and booted, you should see the following
message in the monitor:
.. code-block:: console
***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx *****
Hello World! esp32_devkitc
Debugging
*********
ESP32 support on OpenOCD is available at `OpenOCD ESP32`_.
On the ESP32-DevKitC board, the JTAG pins are not run to a
standard connector (e.g. ARM 20-pin) and need to be manually connected
to the external programmer (e.g. a Flyswatter2):
+------------+-----------+
| ESP32 pin | JTAG pin |
+============+===========+
| 3V3 | VTRef |
+------------+-----------+
| EN | nTRST |
+------------+-----------+
| IO14 | TMS |
+------------+-----------+
| IO12 | TDI |
+------------+-----------+
| GND | GND |
+------------+-----------+
| IO13 | TCK |
+------------+-----------+
| IO15 | TDO |
+------------+-----------+
Further documentation can be obtained from the SoC vendor in `JTAG debugging for ESP32`_.
Here is an example for building the :zephyr:code-sample:`hello_world` application.
.. zephyr-app-commands::
:zephyr-app: samples/hello_world
:board: esp32_devkitc/esp32/procpu
:goals: build flash
You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application.
.. zephyr-app-commands::
:zephyr-app: samples/hello_world
:board: esp32_devkitc/esp32/procpu
:goals: debug
Note on Debugging with GDB Stub
===============================
GDB stub is enabled on ESP32.
* When adding breakpoints, please use hardware breakpoints with command
``hbreak``. Command ``break`` uses software breakpoints which requires
modifying memory content to insert break/trap instructions.
This does not work as the code is on flash which cannot be randomly
accessed for modification.
References
**********
.. target-notes::
.. _`ESP32-DevKitC`: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32/esp32-devkitc/index.html
.. _`ESP32 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
.. _`ESP32 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf
.. _`JTAG debugging for ESP32`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html
.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases
Hello World
展开英文原文(RST)
.. zephyr:code-sample:: hello_world
:name: Hello World
Print "Hello World" to the console.
Overview
********
A simple sample that can be used with any :ref:`supported board <boards>` and
prints "Hello World" to the console.
Building and Running
********************
This application can be built and executed on QEMU as follows:
.. zephyr-app-commands::
:zephyr-app: samples/hello_world
:host-os: unix
:board: qemu_x86
:goals: run
:compact:
To build for another board, change "qemu_x86" above to that board's name.
Sample Output
=============
.. code-block:: console
Hello World! x86
Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`.
Blinky
展开英文原文(RST)
.. zephyr:code-sample:: blinky
:name: Blinky
:relevant-api: gpio_interface
Blink an LED forever using the GPIO API.
Overview
********
The Blinky sample blinks an LED forever using the :ref:`GPIO API <gpio_api>`.
The source code shows how to:
#. Get a pin specification from the :ref:`devicetree <dt-guide>` as a
:c:struct:`gpio_dt_spec`
#. Configure the GPIO pin as an output
#. Toggle the pin forever
See :zephyr:code-sample:`pwm-blinky` for a similar sample that uses the PWM API instead.
.. _blinky-sample-requirements:
Requirements
************
Your board must:
#. Have an LED connected via a GPIO pin (these are called "User LEDs" on many of
Zephyr's :ref:`boards`).
#. Have the LED configured using the ``led0`` devicetree alias.
Building and Running
********************
Build and flash Blinky as follows, changing ``reel_board`` for your board:
.. zephyr-app-commands::
:zephyr-app: samples/basic/blinky
:board: reel_board
:goals: build flash
:compact:
After flashing, the LED starts to blink and messages with the current LED state
are printed on the console. If a runtime error occurs, the sample exits without
printing to the console.
Build errors
************
You will see a build error at the source code line defining the ``struct
gpio_dt_spec led`` variable if you try to build Blinky for an unsupported
board.
On GCC-based toolchains, the error looks like this:
.. code-block:: none
error: '__device_dts_ord_DT_N_ALIAS_led_P_gpios_IDX_0_PH_ORD' undeclared here (not in a function)
Adding board support
********************
To add support for your board, add something like this to your devicetree:
.. code-block:: DTS
/ {
aliases {
led0 = &myled0;
};
leds {
compatible = "gpio-leds";
myled0: led_0 {
gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
};
};
};
The above sets your board's ``led0`` alias to use pin 13 on GPIO controller
``gpio0``. The pin flags :c:macro:`GPIO_ACTIVE_HIGH` mean the LED is on when
the pin is set to its high state, and off when the pin is in its low state.
Tips:
- See :dtcompatible:`gpio-leds` for more information on defining GPIO-based LEDs
in devicetree.
- If you're not sure what to do, check the devicetrees for supported boards which
use the same SoC as your target. See :ref:`get-devicetree-outputs` for details.
- See :zephyr_file:`include/zephyr/dt-bindings/gpio/gpio.h` for the flags you can use
in devicetree.
- If the LED is built in to your board hardware, the alias should be defined in
your :ref:`BOARD.dts file <devicetree-in-out-files>`. Otherwise, you can
define one in a :ref:`devicetree overlay <set-devicetree-overlays>`.
Application Development
展开英文原文(RST)
.. _application:
Application Development
#######################
.. note::
In this document, we'll assume:
- your **application directory**, :file:`<app>`, is something like :file:`<home>/zephyrproject/app`
- its **build directory** is :file:`<app>/build`
These terms are defined below. On Linux/macOS, <home> is equivalent to
``~``. On Windows, it's ``%userprofile%``.
Keeping your application inside the workspace (:file:`<home>/zephyrproject`)
makes it easier to use ``west build`` and other commands with it. (You can
put your application anywhere as long as :ref:`ZEPHYR_BASE
<important-build-vars>` is set appropriately, though.)
Overview
********
Zephyr's build system is based on `CMake`_.
The build system is application-centric, and requires Zephyr-based applications
to initiate building the Zephyr source code. The application build controls
the configuration and build process of both the application and Zephyr itself,
compiling them into a single binary.
The main zephyr repository contains Zephyr's source code, configuration files,
and build system. You also likely have installed various :ref:`modules`
alongside the zephyr repository, which provide third party source code
integration.
The files in the **application directory** link Zephyr and any modules with the
application. This directory contains all application-specific files, such as
application-specific configuration files and source code.
Here are the files in a simple Zephyr application:
.. code-block:: none
<app>
├── CMakeLists.txt
├── app.overlay
├── prj.conf
├── VERSION
└── src
└── main.c
These contents are:
* **CMakeLists.txt**: This file tells the build system where to find the other
application files, and links the application directory with Zephyr's CMake
build system. This link provides features supported by Zephyr's build system,
such as board-specific configuration files, the ability to run and
debug compiled binaries on real or emulated hardware, and more.
* **app.overlay**: This is a devicetree overlay file that specifies
application-specific changes which should be applied to the base devicetree
for any board you build for. The purpose of devicetree overlays is
usually to configure something about the hardware used by the application.
The build system looks for :file:`app.overlay` by default, but you can add
more devicetree overlays, and other default files are also searched for.
See :ref:`devicetree` for more information about devicetree.
* **prj.conf**: This is a Kconfig fragment that specifies application-specific
values for one or more Kconfig options. These application settings are merged
with other settings to produce the final configuration. The purpose of
Kconfig fragments is usually to configure the software features used by
the application.
The build system looks for :file:`prj.conf` by default, but you can add more
Kconfig fragments, and other default files are also searched for.
See :ref:`application-kconfig` below for more information.
* **VERSION**: A text file that contains several version information fields.
These fields let you manage the lifecycle of the application and automate
providing the application version when signing application images.
See :ref:`app-version-details` for more information about this file and how to use it.
* **main.c**: A source code file. Applications typically contain source files
written in C, C++, or assembly language. The Zephyr convention is to place
them in a subdirectory of :file:`<app>` named :file:`src`.
Once an application has been defined, you will use CMake to generate a **build
directory**, which contains the files you need to build the application and
Zephyr, then link them together into a final binary you can run on your board.
The easiest way to do this is with :ref:`west build <west-building>`, but you
can use CMake directly also. Application build artifacts are always generated
in a separate build directory: Zephyr does not support "in-tree" builds.
The following sections describe how to create, build, and run Zephyr
applications, followed by more detailed reference material.
.. _zephyr-app-types:
Application types
*****************
We distinguish three basic types of Zephyr application based on where
:file:`<app>` is located:
.. table::
+------------------------------+--------------------------------+
| Application type | :file:`<app>` location |
+------------------------------+--------------------------------+
| :ref:`repository | zephyr repository |
| <zephyr-repo-app>` | |
+------------------------------+--------------------------------+
| :ref:`workspace | west workspace where Zephyr is |
| <zephyr-workspace-app>` | installed |
+------------------------------+--------------------------------+
| :ref:`freestanding | other locations |
| <zephyr-freestanding-app>` | |
+------------------------------+--------------------------------+
We'll discuss these more below. To learn how the build system supports each
type, see :ref:`cmake_pkg`.
.. _zephyr-repo-app:
Zephyr repository application
=============================
An application located within the ``zephyr`` source code repository in a Zephyr
:ref:`west workspace <west-workspaces>` is referred to as a Zephyr repository
application. In the following example, the :zephyr:code-sample:`hello_world sample
<hello_world>` is a Zephyr repository application:
.. code-block:: none
zephyrproject/
├─── .west/
│ └─── config
└─── zephyr/
├── arch/
├── boards/
├── cmake/
├── samples/
│ ├── hello_world/
│ └── ...
├── tests/
└── ...
.. _zephyr-workspace-app:
Zephyr workspace application
============================
An application located within a :ref:`workspace <west-workspaces>`, but outside
the zephyr repository itself, is referred to as a Zephyr workspace application.
In the following example, ``app`` is a Zephyr workspace application:
.. code-block:: none
zephyrproject/
├─── .west/
│ └─── config
├─── zephyr/
├─── bootloader/
├─── modules/
├─── tools/
├─── <vendor/private-repositories>/
└─── applications/
└── app/
.. _zephyr-freestanding-app:
Zephyr freestanding application
===============================
A Zephyr application located outside of a Zephyr :ref:`workspace
<west-workspaces>` is referred to as a Zephyr freestanding application. In the
following example, ``app`` is a Zephyr freestanding application:
.. code-block:: none
<home>/
├─── zephyrproject/
│ ├─── .west/
│ │ └─── config
│ ├── zephyr/
│ ├── bootloader/
│ ├── modules/
│ └── ...
│
└─── app/
├── CMakeLists.txt
├── prj.conf
└── src/
└── main.c
.. _zephyr-creating-app:
Creating an Application
***********************
In Zephyr, you can either use a reference workspace application or create your application by hand.
.. _zephyr-creating-app-from-example:
Using a Reference Workspace Application
=======================================
The `example-application`_ Git repository contains a reference :ref:`workspace
application <zephyr-workspace-app>`. It is recommended to use it as a reference
when creating your own application as described in the following sections.
The example-application repository demonstrates how to use several
commonly-used features, such as:
- Custom :ref:`board ports <board_porting_guide>`
- Custom :ref:`devicetree bindings <dt-bindings>`
- Custom :ref:`device drivers <device_model_api>`
- Continuous Integration (CI) setup, including using :ref:`twister <twister_script>`
- A custom west :ref:`extension command <west-extensions>`
Basic example-application Usage
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The easiest way to get started with the example-application repository within
an existing Zephyr workspace is to follow these steps:
.. code-block:: console
cd <home>/zephyrproject
git clone https://github.com/zephyrproject-rtos/example-application my-app
The directory name :file:`my-app` above is arbitrary: change it as needed. You
can now go into this directory and adapt its contents to suit your needs. Since
you are using an existing Zephyr workspace, you can use ``west build`` or any
other west commands to build, flash, and debug.
Advanced example-application Usage
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can also use the example-application repository as a starting point for
building your own customized Zephyr-based software distribution. This lets you
do things like:
- remove Zephyr modules you don't need
- add additional custom repositories of your own
- override repositories provided by Zephyr with your own versions
- share the results with others and collaborate further
The example-application repository contains a :file:`west.yml` file and is
therefore also a west :ref:`manifest repository <west-workspace>`. Use this to
create a new, customized workspace by following these steps:
.. code-block:: console
cd <home>
mkdir my-workspace
cd my-workspace
git clone https://github.com/zephyrproject-rtos/example-application my-manifest-repo
west init -l my-manifest-repo
This will create a new workspace with the :ref:`T2 topology <west-t2>`, with
:file:`my-manifest-repo` as the manifest repository. The :file:`my-workspace`
and :file:`my-manifest-repo` names are arbitrary: change them as needed.
Next, customize the manifest repository. The initial contents of this
repository will match the example-application's contents when you clone it. You
can then edit :file:`my-manifest-repo/west.yml` to your liking, changing the
set of repositories in it as you wish. See :ref:`west-manifest-import` for many
examples of how to add or remove different repositories from your workspace as
needed. Make any other changes you need to other files.
When you are satisfied, you can run:
.. code-block::
west update
and your workspace will be ready for use.
If you push the resulting :file:`my-manifest-repo` repository somewhere else,
you can share your work with others. For example, let's say you push the
repository to ``https://git.example.com/my-manifest-repo``. Other people can
then set up a matching workspace by running:
.. code-block::
west init -m https://git.example.com/my-manifest-repo my-workspace
cd my-workspace
west update
From now on, you can collaborate on the shared software by pushing changes to
the repositories you are using and updating :file:`my-manifest-repo/west.yml`
as needed to add and remove repositories, or change their contents.
.. _zephyr-creating-app-by-hand:
Creating an Application by Hand
===============================
You can follow these steps to create a basic application directory from
scratch. However, using the `example-application`_ repository or one of
Zephyr's :zephyr:code-sample-category:`samples` as a starting point is likely to be easier.
#. Create an application directory.
For example, in a Unix shell or Windows ``cmd.exe`` prompt:
.. code-block:: console
mkdir app
.. warning::
Building Zephyr or creating an application in a directory with spaces
anywhere on the path is not supported. So the Windows path
:file:`C:\\Users\\YourName\\app` will work, but
:file:`C:\\Users\\Your Name\\app` will not.
#. Create your source code files.
It's recommended to place all application source code in a subdirectory
named :file:`src`. This makes it easier to distinguish between project
files and sources.
Continuing the previous example, enter:
.. code-block:: console
cd app
mkdir src
#. Place your application source code in the :file:`src` sub-directory. For
this example, we'll assume you created a file named :file:`src/main.c`.
#. Create a file named :file:`CMakeLists.txt` in the ``app`` directory with the
following contents:
.. code-block:: cmake
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr)
project(my_zephyr_app)
target_sources(app PRIVATE src/main.c)
Notes:
- The ``cmake_minimum_required()`` call is required by CMake. It is also
invoked by the Zephyr package on the next line. CMake will error out if
its version is older than either the version in your
:file:`CMakeLists.txt` or the version number in the Zephyr package.
- ``find_package(Zephyr)`` pulls in the Zephyr build system, which creates a
CMake target named ``app`` (see :ref:`cmake_pkg`). Adding sources to this
target is how you include them in the build. The Zephyr package will
define ``Zephyr-Kernel`` as a CMake project and enable support for the
``C``, ``CXX``, ``ASM`` languages.
- ``project(my_zephyr_app)`` defines your application's CMake
project. This must be called after ``find_package(Zephyr)`` to avoid
interference with Zephyr's ``project(Zephyr-Kernel)``.
- ``target_sources(app PRIVATE src/main.c)`` is to add your source file to
the ``app`` target. This must come after ``find_package(Zephyr)`` which
defines the target. You can add as many files as you want with
``target_sources()``.
#. Create at least one Kconfig fragment for your application (usually named
:file:`prj.conf`) and set Kconfig option values needed by your application
there. See :ref:`application-kconfig`. If no Kconfig options need to be set,
create an empty file.
#. Configure any devicetree overlays needed by your application, usually in a
file named :file:`app.overlay`. See :ref:`set-devicetree-overlays`.
#. Set up any other files you may need, such as :ref:`twister <twister_script>`
configuration files, continuous integration files, documentation, etc.
.. _important-build-vars:
Important Build System Variables
********************************
You can control the Zephyr build system using many variables. This
section describes the most important ones that every Zephyr developer
should know about.
.. note::
The variables :makevar:`BOARD`, :makevar:`CONF_FILE`, and
:makevar:`DTC_OVERLAY_FILE` can be supplied to the build system in
3 ways (in order of precedence):
* As a parameter to the ``west build`` or ``cmake`` invocation via the
``-D`` command-line switch. If you have multiple overlay files, you should
use quotations, ``"file1.overlay;file2.overlay"``
* As :ref:`env_vars`.
* As a ``set(<VARIABLE> <VALUE>)`` statement in your :file:`CMakeLists.txt`
* :makevar:`ZEPHYR_BASE`: Zephyr base variable used by the build system.
``find_package(Zephyr)`` will automatically set this as a cached CMake
variable. But ``ZEPHYR_BASE`` can also be set as an environment variable in
order to force CMake to use a specific Zephyr installation.
* :makevar:`BOARD`: Selects the board that the application's build
will use for the default configuration. See :ref:`boards` for
built-in boards, and :ref:`board_porting_guide` for information on
adding board support.
* :makevar:`CONF_FILE`: Indicates the name of one or more Kconfig configuration
fragment files. Multiple filenames can be separated with either spaces or
semicolons. Each file includes Kconfig configuration values that override
the default configuration values.
See :ref:`initial-conf` for more information.
* :makevar:`EXTRA_CONF_FILE`: Additional Kconfig configuration fragment files.
Multiple filenames can be separated with either spaces or semicolons. This
can be useful in order to leave :makevar:`CONF_FILE` at its default value,
but "mix in" some additional configuration options.
* :makevar:`DTC_OVERLAY_FILE`: One or more devicetree overlay files to use.
Multiple files can be separated with semicolons.
See :ref:`set-devicetree-overlays` for examples and :ref:`devicetree-intro`
for information about devicetree and Zephyr.
* :makevar:`EXTRA_DTC_OVERLAY_FILE`: Additional devicetree overlay files to use.
Multiple files can be separated with semicolons. This can be useful to leave
:makevar:`DTC_OVERLAY_FILE` at its default value, but "mix in" some additional
overlay files.
* :makevar:`SHIELD`: see :ref:`shields`
* :makevar:`ZEPHYR_MODULES`: A `CMake list`_ containing absolute paths of
additional directories with source code, Kconfig, etc. that should be used in
the application build. See :ref:`modules` for details. If you set this
variable, it must be a complete list of all modules to use, as the build
system will not automatically pick up any modules from west.
* :makevar:`EXTRA_ZEPHYR_MODULES`: Like :makevar:`ZEPHYR_MODULES`, except these
will be added to the list of modules found via west, instead of replacing it.
* :makevar:`FILE_SUFFIX`: Optional suffix for filenames that will be added to Kconfig
fragments and devicetree overlays (if these files exists, otherwise will fallback to
the name without the prefix). See :ref:`application-file-suffixes` for details.
.. note::
You can use a :ref:`cmake_build_config_package` to share common settings for
these variables.
.. _zephyr-app-cmakelists:
Application CMakeLists.txt
**************************
Every application must have a :file:`CMakeLists.txt` file. This file is the
entry point, or top level, of the build system. The final :file:`zephyr.elf`
image contains both the application and the kernel libraries.
This section describes some of what you can do in your :file:`CMakeLists.txt`.
Make sure to follow these steps in order.
#. If you only want to build for one board, add the name of the board
configuration for your application on a new line. For example:
.. code-block:: cmake
set(BOARD qemu_x86)
Refer to :ref:`boards` for more information on available boards.
The Zephyr build system determines a value for :makevar:`BOARD` by checking
the following, in order (when a BOARD value is found, CMake stops looking
further down the list):
- Any previously used value as determined by the CMake cache takes highest
precedence. This ensures you don't try to run a build with a different
:makevar:`BOARD` value than you set during the build configuration step.
- Any value given on the CMake command line (directly or indirectly via
``west build``) using ``-DBOARD=YOUR_BOARD`` will be checked for and
used next.
- If an :ref:`environment variable <env_vars>` ``BOARD`` is set, its value
will then be used.
- Finally, if you set ``BOARD`` in your application :file:`CMakeLists.txt`
as described in this step, this value will be used.
#. If your application uses a configuration file or files other than
the usual :file:`prj.conf`, add lines setting the :makevar:`CONF_FILE`
variable to these files appropriately. If multiple filenames are given,
separate them by a single space or semicolon. CMake lists can be used to
build up configuration fragment files in a modular way when you want to
avoid setting :makevar:`CONF_FILE` in a single place. For example:
.. code-block:: cmake
set(CONF_FILE "fragment_file1.conf")
list(APPEND CONF_FILE "fragment_file2.conf")
See :ref:`initial-conf` for more information.
#. If your application uses devicetree overlays, you may need to set
:ref:`DTC_OVERLAY_FILE <important-build-vars>`.
See :ref:`set-devicetree-overlays`.
#. If your application has its own kernel configuration options,
create a :file:`Kconfig` file in the same directory as your
application's :file:`CMakeLists.txt`.
See :ref:`the Kconfig section of the manual <kconfig>` for detailed
Kconfig documentation.
An (unlikely) advanced use case would be if your application has its own
unique configuration **options** that are set differently depending on the
build configuration.
If you just want to set application specific **values** for existing Zephyr
configuration options, refer to the :makevar:`CONF_FILE` description above.
Structure your :file:`Kconfig` file like this:
.. literalinclude:: application-kconfig.include
:language: kconfig
.. note::
Environment variables in ``source`` statements are expanded directly, so
you do not need to define an ``option env="ZEPHYR_BASE"`` Kconfig
"bounce" symbol. If you use such a symbol, it must have the same name as
the environment variable.
See :ref:`kconfig_extensions` for more information.
The :file:`Kconfig` file is automatically detected when placed in
the application directory, but it is also possible for it to be
found elsewhere if the CMake variable :makevar:`KCONFIG_ROOT` is
set with an absolute path.
#. Specify that the application requires Zephyr on a new line, **after any
lines added from the steps above**:
.. code-block:: cmake
find_package(Zephyr)
project(my_zephyr_app)
.. note:: ``find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})`` can be used if
enforcing a specific Zephyr installation by explicitly
setting the ``ZEPHYR_BASE`` environment variable should be
supported. All samples in Zephyr supports the ``ZEPHYR_BASE``
environment variable.
#. Now add any application source files to the 'app' target
library, each on their own line, like so:
.. code-block:: cmake
target_sources(app PRIVATE src/main.c)
Below is a simple example :file:`CMakeList.txt`:
.. code-block:: cmake
set(BOARD qemu_x86)
find_package(Zephyr)
project(my_zephyr_app)
target_sources(app PRIVATE src/main.c)
The Cmake property ``HEX_FILES_TO_MERGE``
leverages the application configuration provided by
Kconfig and CMake to let you merge externally built hex files
with the hex file generated when building the Zephyr application.
For example:
.. code-block:: cmake
set_property(GLOBAL APPEND PROPERTY HEX_FILES_TO_MERGE
${app_bootloader_hex}
${PROJECT_BINARY_DIR}/${KERNEL_HEX_NAME}
${app_provision_hex})
.. _zephyr-app-cmakecache:
CMakeCache.txt
**************
CMake uses a CMakeCache.txt file as persistent key/value string
storage used to cache values between runs, including compile and build
options and paths to library dependencies. This cache file is created
when CMake is run in an empty build folder.
For more details about the CMakeCache.txt file see the official CMake
documentation `runningcmake`_ .
.. _runningcmake: http://cmake.org/runningcmake/
Application Configuration
*************************
.. _application-configuration-directory:
Application Configuration Directory
===================================
Zephyr will use configuration files from the application's configuration
directory except for files with an absolute path provided by the arguments
described earlier, for example ``CONF_FILE``, ``EXTRA_CONF_FILE``,
``DTC_OVERLAY_FILE``, and ``EXTRA_DTC_OVERLAY_FILE``.
The application configuration directory is defined by the
``APPLICATION_CONFIG_DIR`` variable.
``APPLICATION_CONFIG_DIR`` will be set by one of the sources below with the
highest priority listed first.
1. If ``APPLICATION_CONFIG_DIR`` is specified by the user with
``-DAPPLICATION_CONFIG_DIR=<path>`` or in a CMake file before
``find_package(Zephyr)`` then this folder is used a the application's
configuration directory.
2. The application's source directory.
.. _application-kconfig:
Kconfig Configuration
=====================
Application configuration options are usually set in :file:`prj.conf` in the
application directory. For example, C++ support could be enabled with this
assignment:
.. code-block:: cfg
CONFIG_CPP=y
Looking at :zephyr:code-sample-category:`existing samples <samples>` is a good way to get
started.
See :ref:`setting_configuration_values` for detailed documentation on setting
Kconfig configuration values. The :ref:`initial-conf` section on the same page
explains how the initial configuration is derived. See :ref:`kconfig-search`
for a complete list of configuration options.
See :ref:`hardening` for security information related with Kconfig options.
The other pages in the :ref:`Kconfig section of the manual <kconfig>` are also
worth going through, especially if you planning to add new configuration
options.
Experimental features
~~~~~~~~~~~~~~~~~~~~~
Zephyr is a project under constant development and thus there are features that
are still in early stages of their development cycle. Such features will be
marked ``[EXPERIMENTAL]`` in their Kconfig title.
The :kconfig:option:`CONFIG_WARN_EXPERIMENTAL` setting can be used to enable warnings
at CMake configure time if any experimental feature is enabled.
.. code-block:: cfg
CONFIG_WARN_EXPERIMENTAL=y
For example, if option ``CONFIG_FOO`` is experimental, then enabling it and
:kconfig:option:`CONFIG_WARN_EXPERIMENTAL` will print the following warning at
CMake configure time when you build an application:
.. code-block:: none
warning: Experimental symbol FOO is enabled.
Devicetree Overlays
===================
See :ref:`set-devicetree-overlays`.
.. _application-file-suffixes:
File Suffixes
=============
Zephyr applications might want to have a single code base with multiple configurations for
different build/product variants which would necessitate different Kconfig options and devicetree
configuration. In order to better configure this, Zephyr provides a :makevar:`FILE_SUFFIX` option
when configuring applications that can be automatically appended to filenames. This is applied to
Kconfig fragments and board overlays but with a fallback so that if such files do not exist, the
files without these suffixes will be used instead.
Given the following example project layout:
.. code-block:: none
<app>
├── CMakeLists.txt
├── prj.conf
├── prj_mouse.conf
├── boards
│ ├── native_sim.overlay
│ └── qemu_cortex_m3_mouse.overlay
└── src
└── main.c
* If this is built normally without ``FILE_SUFFIX`` being defined for ``native_sim`` then
``prj.conf`` and ``boards/native_sim.overlay`` will be used.
* If this is build normally without ``FILE_SUFFIX`` being defined for ``qemu_cortex_m3`` then
``prj.conf`` will be used, no application devicetree overlay will be used.
* If this is built with ``FILE_SUFFIX`` set to ``mouse`` for ``native_sim`` then
``prj_mouse.conf`` and ``boards/native_sim.overlay`` will be used (there is no
``native_sim_mouse.overlay`` file so it falls back to ``native_sim.overlay``).
* If this is build with ``FILE_SUFFIX`` set to ``mouse`` for ``qemu_cortex_m3`` then
``prj_mouse.conf`` will be used and ``boards/qemu_cortex_m3_mouse.overlay`` will be used.
Application-Specific Code
*************************
Application-specific source code files are normally added to the
application's :file:`src` directory. If the application adds a large
number of files the developer can group them into sub-directories
under :file:`src`, to whatever depth is needed.
Application-specific source code should not use symbol name prefixes that have
been reserved by the kernel for its own use. For more information, see `Naming
Conventions
<https://github.com/zephyrproject-rtos/zephyr/wiki/Naming-Conventions>`_.
Third-party Library Code
========================
It is possible to build library code outside the application's :file:`src`
directory but it is important that both application and library code targets
the same Application Binary Interface (ABI). On most architectures there are
compiler flags that control the ABI targeted, making it important that both
libraries and applications have certain compiler flags in common. It may also
be useful for glue code to have access to Zephyr kernel header files.
To make it easier to integrate third-party components, the Zephyr
build system has defined CMake functions that give application build
scripts access to the zephyr compiler options. The functions are
documented and defined in :zephyr_file:`cmake/modules/extensions.cmake`
and follow the naming convention ``zephyr_get_<type>_<format>``.
The following variables will often need to be exported to the
third-party build system.
* ``CMAKE_C_COMPILER``, ``CMAKE_AR``.
* ``ARCH`` and ``BOARD``, together with several variables that identify the
Zephyr kernel version.
:zephyr_file:`samples/application_development/external_lib` is a sample
project that demonstrates some of these features.
.. _build_an_application:
Building an Application
***********************
The Zephyr build system compiles and links all components of an application
into a single application image that can be run on simulated hardware or real
hardware.
Like any other CMake-based system, the build process takes place :ref:`in
two stages <cmake-details>`. First, build files (also known as a buildsystem)
are generated using the ``cmake`` command-line tool while specifying a
generator. This generator determines the native build tool the buildsystem
will use in the second stage.
The second stage runs the native build tool to actually build the
source files and generate an image. To learn more about these concepts refer to
the `CMake introduction`_ in the official CMake documentation.
Although the default build tool in Zephyr is :std:ref:`west <west>`, Zephyr's
meta-tool, which invokes ``cmake`` and the underlying build tool (``ninja`` or
``make``) behind the scenes, you can also choose to invoke ``cmake`` directly if
you prefer. On Linux and macOS you can choose between the ``make`` and
``ninja``
generators (i.e. build tools), whereas on Windows you need to use ``ninja``,
since ``make`` is not supported on this platform.
For simplicity we will use ``ninja`` throughout this guide, and if you
choose to use ``west build`` to build your application know that it will
default to ``ninja`` under the hood.
As an example, let's build the Hello World sample for the ``reel_board``:
.. zephyr-app-commands::
:tool: all
:zephyr-app: samples/hello_world
:board: reel_board
:goals: build
On Linux and macOS, you can also build with ``make`` instead of ``ninja``:
Using west:
- to use ``make`` just once, add ``-- -G"Unix Makefiles"`` to the west build
command line; see the :ref:`west build <west-building-generator>`
documentation for an example.
- to use ``make`` by default from now on, run ``west config build.generator
"Unix Makefiles"``.
Using CMake directly:
.. zephyr-app-commands::
:tool: cmake
:zephyr-app: samples/hello_world
:generator: make
:host-os: unix
:board: reel_board
:goals: build
Basics
======
#. Navigate to the application directory :file:`<app>`.
#. Enter the following commands to build the application's :file:`zephyr.elf`
image for the board specified in the command-line parameters:
.. zephyr-app-commands::
:tool: all
:cd-into:
:board: <board>
:goals: build
If desired, you can build the application using the configuration settings
specified in an alternate :file:`.conf` file using the :code:`CONF_FILE`
parameter. These settings will override the settings in the application's
:file:`.config` file or its default :file:`.conf` file. For example:
.. zephyr-app-commands::
:tool: all
:cd-into:
:board: <board>
:gen-args: -DCONF_FILE=prj.alternate.conf
:goals: build
:compact:
As described in the previous section, you can instead choose to permanently
set the board and configuration settings by either exporting :makevar:`BOARD`
and :makevar:`CONF_FILE` environment variables or by setting their values
in your :file:`CMakeLists.txt` using ``set()`` statements.
Additionally, ``west`` allows you to :ref:`set a default board
<west-building-config>`.
.. _build-directory-contents:
Build Directory Contents
========================
When using the Ninja generator a build directory looks like this:
.. code-block:: none
<app>/build
├── build.ninja
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── rules.ninja
└── zephyr
The most notable files in the build directory are:
* :file:`build.ninja`, which can be invoked to build the application.
* A :file:`zephyr` directory, which is the working directory of the
generated build system, and where most generated files are created and
stored.
After running ``ninja``, the following build output files will be written to
the :file:`zephyr` sub-directory of the build directory. (This is **not the
Zephyr base directory**, which contains the Zephyr source code etc. and is
described above.)
* :file:`.config`, which contains the configuration settings
used to build the application.
.. note::
The previous version of :file:`.config` is saved to :file:`.config.old`
whenever the configuration is updated. This is for convenience, as
comparing the old and new versions can be handy.
* Various object files (:file:`.o` files and :file:`.a` files) containing
compiled kernel and application code.
* :file:`zephyr.elf`, which contains the final combined application and
kernel binary. Other binary output formats, such as :file:`.hex` and
:file:`.bin`, are also supported.
.. _application_rebuild:
Rebuilding an Application
=========================
Application development is usually fastest when changes are continually tested.
Frequently rebuilding your application makes debugging less painful
as the application becomes more complex. It's usually a good idea to
rebuild and test after any major changes to the application's source files,
CMakeLists.txt files, or configuration settings.
.. important::
The Zephyr build system rebuilds only the parts of the application image
potentially affected by the changes. Consequently, rebuilding an application
is often significantly faster than building it the first time.
Sometimes the build system doesn't rebuild the application correctly
because it fails to recompile one or more necessary files. You can force
the build system to rebuild the entire application from scratch with the
following procedure:
#. Open a terminal console on your host computer, and navigate to the
build directory :file:`<app>/build`.
#. Enter one of the following commands, depending on whether you want to use
``west`` or ``cmake`` directly to delete the application's generated
files, except for the :file:`.config` file that contains the
application's current configuration information.
.. code-block:: console
west build -t clean
or
.. code-block:: console
ninja clean
Alternatively, enter one of the following commands to delete *all*
generated files, including the :file:`.config` files that contain
the application's current configuration information for those board
types.
.. code-block:: console
west build -t pristine
or
.. code-block:: console
ninja pristine
If you use west, you can take advantage of its capability to automatically
:ref:`make the build folder pristine <west-building-config>` whenever it is
required.
#. Rebuild the application normally following the steps specified
in :ref:`build_an_application` above.
.. _application_board_version:
Building for a board revision
=============================
The Zephyr build system has support for specifying multiple hardware revisions
of a single board with small variations. Using revisions allows the board
support files to make minor adjustments to a board configuration without
duplicating all the files described in :ref:`create-your-board-directory` for
each revision.
To build for a particular revision, use ``<board>@<revision>`` instead of plain
``<board>``. For example:
.. zephyr-app-commands::
:tool: all
:cd-into:
:board: <board>@<revision>
:goals: build
:compact:
Check your board's documentation for details on whether it has multiple
revisions, and what revisions are supported.
When targeting a board revision, the active revision will be printed at CMake
configure time, like this:
.. code-block:: console
-- Board: plank, Revision: 1.5.0
.. _application_run:
Run an Application
******************
An application image can be run on a real board or emulated hardware.
.. _application_run_board:
Running on a Board
==================
Most boards supported by Zephyr let you flash a compiled binary using
the ``flash`` target to copy the binary to the board and run it.
Follow these instructions to flash and run an application on real
hardware:
#. Build your application, as described in :ref:`build_an_application`.
#. Make sure your board is attached to your host computer. Usually, you'll do
this via USB.
#. Run one of these console commands from the build directory,
:file:`<app>/build`, to flash the compiled Zephyr image and run it on
your board:
.. code-block:: console
west flash
or
.. code-block:: console
ninja flash
The Zephyr build system integrates with the board support files to
use hardware-specific tools to flash the Zephyr binary to your
hardware, then run it.
Each time you run the flash command, your application is rebuilt and flashed
again.
In cases where board support is incomplete, flashing via the Zephyr build
system may not be supported. If you receive an error message about flash
support being unavailable, consult :ref:`your board's documentation <boards>`
for additional information on how to flash your board.
.. note:: When developing on Linux, it's common to need to install
board-specific udev rules to enable USB device access to
your board as a non-root user. If flashing fails,
consult your board's documentation to see if this is
necessary.
.. _application_run_qemu:
Running in an Emulator
======================
Zephyr has built-in emulator support for QEMU.
It allows you to run and test an application virtually, before
(or in lieu of) loading and running it on actual target hardware.
Check out :ref:`beyond-GSG` for additional steps needed on Windows.
Follow these instructions to run an application via QEMU:
#. Build your application for one of the QEMU boards, as described in
:ref:`build_an_application`.
For example, you could set ``BOARD`` to:
- ``qemu_x86`` to emulate running on an x86-based board
- ``qemu_cortex_m3`` to emulate running on an ARM Cortex M3-based board
#. Run one of these console commands from the build directory,
:file:`<app>/build`, to run the Zephyr binary in QEMU:
.. code-block:: console
west build -t run
or
.. code-block:: console
ninja run
#. Press :kbd:`Ctrl A, X` to stop the application from running
in QEMU.
The application stops running and the terminal console prompt
redisplays.
Each time you execute the run command, your application is rebuilt and run
again.
.. note::
If the (Linux only) :ref:`Zephyr SDK <toolchain_zephyr_sdk>` is installed, the ``run``
target will use the SDK's QEMU binary by default. To use another version of
QEMU, :ref:`set the environment variable <env_vars>` ``QEMU_BIN_PATH``
to the path of the QEMU binary you want to use instead.
.. note::
You can choose a specific emulator by appending ``_<emulator>`` to your
target name, for example ``west build -t run_qemu`` or ``ninja run_qemu``
for QEMU.
.. _custom_board_definition:
Custom Board, Devicetree and SOC Definitions
********************************************
In cases where the board or platform you are developing for is not yet
supported by Zephyr, you can add board, Devicetree and SOC definitions
to your application without having to add them to the Zephyr tree.
The structure needed to support out-of-tree board and SOC development
is similar to how boards and SOCs are maintained in the Zephyr tree. By using
this structure, it will be much easier to upstream your platform related work into
the Zephyr tree after your initial development is done.
Add the custom board to your application or a dedicated repository using the
following structure:
.. code-block:: console
boards/
soc/
CMakeLists.txt
prj.conf
README.rst
src/
where the ``boards`` directory hosts the board you are building for:
.. code-block:: console
.
├── boards
│ └── vendor
│ └── my_custom_board
│ ├── doc
│ │ └── img
│ └── support
└── src
and the ``soc`` directory hosts any SOC code. You can also have boards that are
supported by a SOC that is available in the Zephyr tree.
Boards
======
Use the vendor name as the folder name (which must match the vendor prefix in
:zephyr_file:`dts/bindings/vendor-prefixes.txt` if submitting upstream to Zephyr, or be
``others`` if it is not a vendor board) under ``boards`` for ``my_custom_board``.
Documentation (under ``doc/``) and support files (under ``support/``) are optional, but
will be needed when submitting to Zephyr.
The contents of ``my_custom_board`` should follow the same guidelines for any
Zephyr board, and provide the following files::
my_custom_board_defconfig
my_custom_board.dts
my_custom_board.yaml
board.cmake
board.h
CMakeLists.txt
doc/
Kconfig.my_custom_board
Kconfig.defconfig
support/
Once the board structure is in place, you can build your application
targeting this board by specifying the location of your custom board
information with the ``-DBOARD_ROOT`` parameter to the CMake
build system:
.. zephyr-app-commands::
:tool: all
:board: <board name>
:gen-args: -DBOARD_ROOT=<path to boards>
:goals: build
:compact:
This will use your custom board configuration and will generate the
Zephyr binary into your application directory.
You can also define the ``BOARD_ROOT`` variable in the application
:file:`CMakeLists.txt` file. Make sure to do so **before** pulling in the Zephyr
boilerplate with ``find_package(Zephyr ...)``.
.. note::
When specifying ``BOARD_ROOT`` in a CMakeLists.txt, then an absolute path must
be provided, for example ``list(APPEND BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/<extra-board-root>)``.
When using ``-DBOARD_ROOT=<board-root>`` both absolute and relative paths can
be used. Relative paths are treated relatively to the application directory.
.. note::
When using sysbuild, then ``BOARD_ROOT`` must defined in a module or in the sysbuild
``CMakeLists.txt`` file, see :ref:`sysbuild_var_override` for details.
SOC Definitions
===============
Similar to board support, the structure is similar to how SOCs are maintained in
the Zephyr tree, for example:
.. code-block:: none
soc
└── st
└── stm32
├── common
└── stm32l0x
The file :zephyr_file:`soc/Kconfig` will create the top-level
``SoC/CPU/Configuration Selection`` menu in Kconfig.
Out of tree SoC definitions can be added to this menu using the ``SOC_ROOT``
CMake variable. This variable contains a semicolon-separated list of directories
which contain SoC support files.
Following the structure above, the following files can be added to load
more SoCs into the menu.
.. code-block:: none
soc
└── st
└── stm32
└── stm32l0x
├── Kconfig
├── Kconfig.soc
└── Kconfig.defconfig
The Kconfig files above may describe the SoC or load additional SoC Kconfig files.
An example of loading ``stm31l0`` specific Kconfig files in this structure:
.. code-block:: none
soc
└── st
└── stm32
├── Kconfig.soc
└── stm32l0x
└── Kconfig.soc
can be done with the following content in ``st/stm32/Kconfig.soc``:
.. code-block:: kconfig
rsource "*/Kconfig.soc"
Once the SOC structure is in place, you can build your application
targeting this platform by specifying the location of your custom platform
information with the ``-DSOC_ROOT`` parameter to the CMake
build system:
.. zephyr-app-commands::
:tool: all
:board: <board name>
:gen-args: -DSOC_ROOT=<path to soc> -DBOARD_ROOT=<path to boards>
:goals: build
:compact:
This will use your custom platform configurations and will generate the
Zephyr binary into your application directory.
See :ref:`modules_build_settings` for information on setting SOC_ROOT in a module's
:file:`zephyr/module.yml` file.
Or you can define the ``SOC_ROOT`` variable in the application
:file:`CMakeLists.txt` file. Make sure to do so **before** pulling in the
Zephyr boilerplate with ``find_package(Zephyr ...)``.
.. note::
When specifying ``SOC_ROOT`` in a CMakeLists.txt, then an absolute path must
be provided, for example ``list(APPEND SOC_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/<extra-soc-root>``.
When using ``-DSOC_ROOT=<soc-root>`` both absolute and relative paths can be
used. Relative paths are treated relatively to the application directory.
.. _dts_root:
Devicetree Definitions
======================
Devicetree directory trees are found in ``APPLICATION_SOURCE_DIR``,
``BOARD_DIR``, and ``ZEPHYR_BASE``, but additional trees, or DTS_ROOTs,
can be added by creating this directory tree::
include/
dts/common/
dts/arm/
dts/
dts/bindings/
Where 'arm' is changed to the appropriate architecture. Each directory
is optional. The binding directory contains bindings and the other
directories contain files that can be included from DT sources.
Once the directory structure is in place, you can use it by specifying
its location through the ``DTS_ROOT`` CMake Cache variable:
.. zephyr-app-commands::
:tool: all
:board: <board name>
:gen-args: -DDTS_ROOT=<path to dts root>
:goals: build
:compact:
You can also define the variable in the application :file:`CMakeLists.txt`
file. Make sure to do so **before** pulling in the Zephyr boilerplate with
``find_package(Zephyr ...)``.
.. note::
When specifying ``DTS_ROOT`` in a CMakeLists.txt, then an absolute path must
be provided, for example ``list(APPEND DTS_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/<extra-dts-root>``.
When using ``-DDTS_ROOT=<dts-root>`` both absolute and relative paths can be
used. Relative paths are treated relatively to the application directory.
Devicetree source are passed through the C preprocessor, so you can
include files that can be located in a ``DTS_ROOT`` directory. By
convention devicetree include files have a ``.dtsi`` extension.
You can also use the preprocessor to control the content of a devicetree
file, by specifying directives through the ``DTS_EXTRA_CPPFLAGS`` CMake
Cache variable:
.. zephyr-app-commands::
:tool: all
:board: <board name>
:gen-args: -DDTS_EXTRA_CPPFLAGS=-DTEST_ENABLE_FEATURE
:goals: build
:compact:
.. _CMake: https://www.cmake.org
.. _CMake introduction: https://cmake.org/cmake/help/latest/manual/cmake.1.html#description
.. _CMake list: https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#lists
.. _example-application: https://github.com/zephyrproject-rtos/example-application
Devicetree HOWTOs
展开英文原文(RST)
.. _dt-howtos:
Devicetree HOWTOs
#################
This page has step-by-step advice for getting things done with devicetree.
.. tip:: See :ref:`dt-trouble` for troubleshooting advice.
.. _get-devicetree-outputs:
Get your devicetree and generated header
****************************************
A board's devicetree (:ref:`BOARD.dts <devicetree-in-out-files>`) pulls in
common node definitions via ``#include`` preprocessor directives. This at least
includes the SoC's ``.dtsi``. One way to figure out the devicetree's contents
is by opening these files, e.g. by looking in
``dts/<ARCH>/<vendor>/<soc>.dtsi``, but this can be time consuming.
If you just want to see the "final" devicetree for your board, build an
application and open the :file:`zephyr.dts` file in the build directory.
.. tip::
You can build :zephyr:code-sample:`hello_world` to see the "base" devicetree for your board
without any additional changes from :ref:`overlay files <dt-input-files>`.
For example, using the :zephyr:board:`qemu_cortex_m3` board to build
:zephyr:code-sample:`hello_world`:
.. code-block:: sh
# --cmake-only here just forces CMake to run, skipping the
# build process to save time.
west build -b qemu_cortex_m3 samples/hello_world --cmake-only
You can change ``qemu_cortex_m3`` to match your board.
CMake prints the input and output file locations like this:
.. code-block:: none
-- Found BOARD.dts: .../zephyr/boards/arm/qemu_cortex_m3/qemu_cortex_m3.dts
-- Generated zephyr.dts: .../zephyr/build/zephyr/zephyr.dts
-- Generated devicetree_generated.h: .../zephyr/build/zephyr/include/generated/zephyr/devicetree_generated.h
The :file:`zephyr.dts` file is the final devicetree in DTS format.
The :file:`devicetree_generated.h` file is the corresponding generated header.
See :ref:`devicetree-in-out-files` for details about these files.
.. _dt-get-device:
Get a struct device from a devicetree node
******************************************
When writing Zephyr applications, you'll often want to get a driver-level
:ref:`struct device <device_model_api>` corresponding to a devicetree node.
For example, with this devicetree fragment, you might want the struct device
for ``serial@40002000``:
.. code-block:: devicetree
/ {
soc {
serial0: serial@40002000 {
status = "okay";
current-speed = <115200>;
/* ... */
};
};
aliases {
my-serial = &serial0;
};
chosen {
zephyr,console = &serial0;
};
};
Start by making a :ref:`node identifier <dt-node-identifiers>` for the device
you are interested in. There are different ways to do this; pick whichever one
works best for your requirements. Here are some examples:
.. code-block:: c
/* Option 1: by node label */
#define MY_SERIAL DT_NODELABEL(serial0)
/* Option 2: by alias */
#define MY_SERIAL DT_ALIAS(my_serial)
/* Option 3: by chosen node */
#define MY_SERIAL DT_CHOSEN(zephyr_console)
/* Option 4: by path */
#define MY_SERIAL DT_PATH(soc, serial_40002000)
Once you have a node identifier there are two ways to proceed. One way to get a
device is to use :c:macro:`DEVICE_DT_GET`:
.. code-block:: c
const struct device *const uart_dev = DEVICE_DT_GET(MY_SERIAL);
if (!device_is_ready(uart_dev)) {
/* Not ready, do not use */
return -ENODEV;
}
There are variants of :c:macro:`DEVICE_DT_GET` such as
:c:macro:`DEVICE_DT_GET_OR_NULL`, :c:macro:`DEVICE_DT_GET_ONE` or
:c:macro:`DEVICE_DT_GET_ANY`. This idiom fetches the device pointer at
build-time, which means there is no runtime penalty. This method is useful if
you want to store the device pointer as configuration data. But because the
device may not be initialized, or may have failed to initialize, you must verify
that the device is ready to be used before passing it to any API functions.
(This check is done for you by :c:func:`device_get_binding`.)
In some situations the device cannot be known at build-time, e.g., if it depends
on user input like in a shell application. In this case you can get the
``struct device`` by combining :c:func:`device_get_binding` with the device
name:
.. code-block:: c
const char *dev_name = /* TODO: insert device name from user */;
const struct device *uart_dev = device_get_binding(dev_name);
You can then use ``uart_dev`` with :ref:`uart_api` API functions like
:c:func:`uart_configure`. Similar code will work for other device types; just
make sure you use the correct API for the device.
If you're having trouble, see :ref:`dt-trouble`. The first thing to check is
that the node has ``status = "okay"``, like this:
.. code-block:: c
#define MY_SERIAL DT_NODELABEL(my_serial)
#if DT_NODE_HAS_STATUS(MY_SERIAL, okay)
const struct device *const uart_dev = DEVICE_DT_GET(MY_SERIAL);
#else
#error "Node is disabled"
#endif
If you see the ``#error`` output, make sure to enable the node in your
devicetree. In some situations your code will compile but it will fail to link
with a message similar to:
.. code-block:: none
...undefined reference to `__device_dts_ord_N'
collect2: error: ld returned 1 exit status
This likely means there's a Kconfig issue preventing the device driver from
being built, resulting in a reference that does not exist. If your code compiles
successfully, the last thing to check is if the device is ready, like this:
.. code-block:: c
if (!device_is_ready(uart_dev)) {
printk("Device not ready\n");
}
If you find that the device is not ready, it likely means that the device's
initialization function failed. Enabling logging or debugging driver code may
help in such situations. Note that you can also use :c:func:`device_get_binding`
to obtain a reference at runtime. If it returns ``NULL`` it can either mean that
device's driver failed to initialize or that it does not exist.
.. _dts-find-binding:
Find a devicetree binding
*************************
:ref:`dt-bindings` are YAML files which declare what you can do with the nodes
they describe, so it's critical to be able to find them for the nodes you are
using.
If you don't have them already, :ref:`get-devicetree-outputs`. To find a node's
binding, open the generated header file, which starts with a list of nodes in a
block comment:
.. code-block:: c
/*
* [...]
* Nodes in dependency order (ordinal and path):
* 0 /
* 1 /aliases
* 2 /chosen
* 3 /flash@0
* 4 /memory@20000000
* (etc.)
* [...]
*/
Make note of the path to the node you want to find, like ``/flash@0``. Search
for the node's output in the file, which starts with something like this if the
node has a matching binding:
.. code-block:: c
/*
* Devicetree node:
* /flash@0
*
* Binding (compatible = soc-nv-flash):
* $ZEPHYR_BASE/dts/bindings/mtd/soc-nv-flash.yaml
* [...]
*/
See :ref:`missing-dt-binding` for troubleshooting.
.. _set-devicetree-overlays:
Set devicetree overlays
***********************
Devicetree overlays are explained in :ref:`devicetree-intro`. The CMake
variable :makevar:`DTC_OVERLAY_FILE` contains a space- or semicolon-separated
list of overlay files to use. If :makevar:`DTC_OVERLAY_FILE` specifies multiple
files, they are included in that order by the C preprocessor. A file in a
Zephyr module can be referred to by escaping the Zephyr module dir variable
like ``\${ZEPHYR_<module>_MODULE_DIR}/<path-to>/dts.overlay``
when setting the DTC_OVERLAY_FILE variable.
You can set :makevar:`DTC_OVERLAY_FILE` to contain exactly the files you want
to use. Here is an :ref:`example <west-building-dtc-overlay-file>` using
``west build``.
If you don't set :makevar:`DTC_OVERLAY_FILE`, the build system will follow
these steps, looking for files in your application configuration directory to
use as devicetree overlays:
#. If the file :file:`socs/<SOC>_<BOARD_QUALIFIERS>.overlay` exists, it will be used.
#. If the file :file:`boards/<BOARD>.overlay` exists, it will be used in addition to the above.
#. If the current board has :ref:`multiple revisions <porting_board_revisions>`
and :file:`boards/<BOARD>_<revision>.overlay` exists, it will be used in addition to the above.
#. If one or more files have been found in the previous steps, the build system
stops looking and just uses those files.
#. Otherwise, if :file:`<BOARD>.overlay` exists, it will be used, and the build
system will stop looking for more files.
#. Otherwise, if :file:`app.overlay` exists, it will be used.
Extra devicetree overlays may be provided using ``EXTRA_DTC_OVERLAY_FILE`` which
will still allow the build system to automatically use devicetree overlays
described in the above steps.
The build system appends overlays specified in ``EXTRA_DTC_OVERLAY_FILE``
to the overlays in ``DTC_OVERLAY_FILE`` when processing devicetree overlays.
This means that changes made via ``EXTRA_DTC_OVERLAY_FILE`` have higher
precedence than those made via ``DTC_OVERLAY_FILE``.
All configuration files will be taken from the application's configuration
directory except for files with an absolute path that are given with the
``DTC_OVERLAY_FILE`` or ``EXTRA_DTC_OVERLAY_FILE`` argument.
See :ref:`Application Configuration Directory <application-configuration-directory>`
on how the application configuration directory is defined.
Using :ref:`shields` will also add devicetree overlay files.
The :makevar:`DTC_OVERLAY_FILE` value is stored in the CMake cache and used
in successive builds.
The :ref:`build system <build_overview>` prints all the devicetree overlays it
finds in the configuration phase, like this:
.. code-block:: none
-- Found devicetree overlay: .../some/file.overlay
.. _use-dt-overlays:
Use devicetree overlays
***********************
See :ref:`set-devicetree-overlays` for how to add an overlay to the build.
Overlays can override node property values in multiple ways.
For example, if your BOARD.dts contains this node:
.. code-block:: devicetree
/ {
soc {
serial0: serial@40002000 {
status = "okay";
current-speed = <115200>;
/* ... */
};
};
};
These are equivalent ways to override the ``current-speed`` value in an
overlay:
.. Disable syntax highlighting as this construct does not seem supported by pygments
.. code-block:: none
/* Option 1 */
&serial0 {
current-speed = <9600>;
};
/* Option 2 */
&{/soc/serial@40002000} {
current-speed = <9600>;
};
We'll use the ``&serial0`` style for the rest of these examples.
You can add aliases to your devicetree using overlays: an alias is just a
property of the ``/aliases`` node. For example:
.. code-block:: devicetree
/ {
aliases {
my-serial = &serial0;
};
};
Chosen nodes work the same way. For example:
.. code-block:: devicetree
/ {
chosen {
zephyr,console = &serial0;
};
};
To delete a property (in addition to deleting properties in general, this is
how to set a boolean property to false if it's true in BOARD.dts):
.. code-block:: devicetree
&serial0 {
/delete-property/ some-unwanted-property;
};
You can add subnodes using overlays. For example, to configure a SPI or I2C
child device on an existing bus node, do something like this:
.. code-block:: devicetree
/* SPI device example */
&spi1 {
my_spi_device: temp-sensor@0 {
compatible = "...";
label = "TEMP_SENSOR_0";
/* reg is the chip select number, if needed;
* If present, it must match the node's unit address. */
reg = <0>;
/* Configure other SPI device properties as needed.
* Find your device's DT binding for details. */
spi-max-frequency = <4000000>;
};
};
/* I2C device example */
&i2c2 {
my_i2c_device: touchscreen@76 {
compatible = "...";
label = "TOUCHSCREEN";
/* reg is the I2C device address.
* It must match the node's unit address. */
reg = <76>;
/* Configure other I2C device properties as needed.
* Find your device's DT binding for details. */
};
};
Other bus devices can be configured similarly:
- create the device as a subnode of the parent bus
- set its properties according to its binding
Assuming you have a suitable device driver associated with the
``my_spi_device`` and ``my_i2c_device`` compatibles, you should now be able to
enable the driver via Kconfig and :ref:`get the struct device <dt-get-device>`
for your newly added bus node, then use it with that driver API.
.. _dt-create-devices:
Write device drivers using devicetree APIs
******************************************
"Devicetree-aware" :ref:`device drivers <device_model_api>` should create a
``struct device`` for each ``status = "okay"`` devicetree node with a
particular :ref:`compatible <dt-important-props>` (or related set of
compatibles) supported by the driver.
Writing a devicetree-aware driver begins by defining a :ref:`devicetree binding
<dt-bindings>` for the devices supported by the driver. Use existing bindings
from similar drivers as a starting point. A skeletal binding to get started
needs nothing more than this:
.. code-block:: yaml
description: <Human-readable description of your binding>
compatible: "foo-company,bar-device"
include: base.yaml
See :ref:`dts-find-binding` for more advice on locating existing bindings.
After writing your binding, your driver C file can then use the devicetree API
to find ``status = "okay"`` nodes with the desired compatible, and instantiate
a ``struct device`` for each one. There are two options for instantiating each
``struct device``: using instance numbers, and using node labels.
In either case:
- Each ``struct device``\ 's name should be set to its devicetree node's
``label`` property. This allows the driver's users to :ref:`dt-get-device` in
the usual way.
- Each device's initial configuration should use values from devicetree
properties whenever practical. This allows users to configure the driver
using :ref:`devicetree overlays <use-dt-overlays>`.
Examples for how to do this follow. They assume you've already implemented the
device-specific configuration and data structures and API functions, like this:
.. code-block:: c
/* my_driver.c */
#include <zephyr/drivers/some_api.h>
/* Define data (RAM) and configuration (ROM) structures: */
struct my_dev_data {
/* per-device values to store in RAM */
};
struct my_dev_cfg {
uint32_t freq; /* Just an example: initial clock frequency in Hz */
/* other configuration to store in ROM */
};
/* Implement driver API functions (drivers/some_api.h callbacks): */
static int my_driver_api_func1(const struct device *dev, uint32_t *foo) { /* ... */ }
static int my_driver_api_func2(const struct device *dev, uint64_t bar) { /* ... */ }
static struct some_api my_api_funcs = {
.func1 = my_driver_api_func1,
.func2 = my_driver_api_func2,
};
.. _dt-create-devices-inst:
Option 1: create devices using instance numbers
===============================================
Use this option, which uses :ref:`devicetree-inst-apis`, if possible. However,
they only work when devicetree nodes for your driver's ``compatible`` are all
equivalent, and you do not need to be able to distinguish between them.
To use instance-based APIs, begin by defining ``DT_DRV_COMPAT`` to the
lowercase-and-underscores version of the compatible that the device driver
supports. For example, if your driver's compatible is ``"vnd,my-device"`` in
devicetree, you would define ``DT_DRV_COMPAT`` to ``vnd_my_device`` in your
driver C file:
.. code-block:: c
/*
* Put this near the top of the file. After the includes is a good place.
* (Note that you can therefore run "git grep DT_DRV_COMPAT drivers" in
* the zephyr Git repository to look for example drivers using this style).
*/
#define DT_DRV_COMPAT vnd_my_device
.. important::
As shown, the DT_DRV_COMPAT macro should have neither quotes nor special
characters. Remove quotes and convert special characters to underscores
when creating ``DT_DRV_COMPAT`` from the compatible property.
Finally, define an instantiation macro, which creates each ``struct device``
using instance numbers. Do this after defining ``my_api_funcs``.
.. code-block:: c
/*
* This instantiation macro is named "CREATE_MY_DEVICE".
* Its "inst" argument is an arbitrary instance number.
*
* Put this near the end of the file, e.g. after defining "my_api_funcs".
*/
#define CREATE_MY_DEVICE(inst) \
static struct my_dev_data my_data_##inst = { \
/* initialize RAM values as needed, e.g.: */ \
.freq = DT_INST_PROP(inst, clock_frequency), \
}; \
static const struct my_dev_cfg my_cfg_##inst = { \
/* initialize ROM values as needed. */ \
}; \
DEVICE_DT_INST_DEFINE(inst, \
my_dev_init_function, \
NULL, \
&my_data_##inst, \
&my_cfg_##inst, \
MY_DEV_INIT_LEVEL, MY_DEV_INIT_PRIORITY, \
&my_api_funcs);
Notice the use of APIs like :c:macro:`DT_INST_PROP` and
:c:macro:`DEVICE_DT_INST_DEFINE` to access devicetree node data. These
APIs retrieve data from the devicetree for instance number ``inst`` of
the node with compatible determined by ``DT_DRV_COMPAT``.
Finally, pass the instantiation macro to :c:macro:`DT_INST_FOREACH_STATUS_OKAY`:
.. code-block:: c
/* Call the device creation macro for each instance: */
DT_INST_FOREACH_STATUS_OKAY(CREATE_MY_DEVICE)
``DT_INST_FOREACH_STATUS_OKAY`` expands to code which calls
``CREATE_MY_DEVICE`` once for each enabled node with the compatible determined
by ``DT_DRV_COMPAT``. It does not append a semicolon to the end of the
expansion of ``CREATE_MY_DEVICE``, so the macro's expansion must end in a
semicolon or function definition to support multiple devices.
Option 2: create devices using node labels
==========================================
Some device drivers cannot use instance numbers. One example is an SoC
peripheral driver which relies on vendor HAL APIs specialized for individual IP
blocks to implement Zephyr driver callbacks. Cases like this should use
:c:macro:`DT_NODELABEL` to refer to individual nodes in the devicetree
representing the supported peripherals on the SoC. The devicetree.h
:ref:`devicetree-generic-apis` can then be used to access node data.
For this to work, your :ref:`SoC's dtsi file <dt-input-files>` must define node
labels like ``mydevice0``, ``mydevice1``, etc. appropriately for the IP blocks
your driver supports. The resulting devicetree usually looks something like
this:
.. code-block:: devicetree
/ {
soc {
mydevice0: dev@0 {
compatible = "vnd,my-device";
};
mydevice1: dev@1 {
compatible = "vnd,my-device";
};
};
};
The driver can use the ``mydevice0`` and ``mydevice1`` node labels in the
devicetree to operate on specific device nodes:
.. code-block:: c
/*
* This is a convenience macro for creating a node identifier for
* the relevant devices. An example use is MYDEV(0) to refer to
* the node with label "mydevice0".
*/
#define MYDEV(idx) DT_NODELABEL(mydevice ## idx)
/*
* Define your instantiation macro; "idx" is a number like 0 for mydevice0
* or 1 for mydevice1. It uses MYDEV() to create the node label from the
* index.
*/
#define CREATE_MY_DEVICE(idx) \
static struct my_dev_data my_data_##idx = { \
/* initialize RAM values as needed, e.g.: */ \
.freq = DT_PROP(MYDEV(idx), clock_frequency), \
}; \
static const struct my_dev_cfg my_cfg_##idx = { /* ... */ }; \
DEVICE_DT_DEFINE(MYDEV(idx), \
my_dev_init_function, \
NULL, \
&my_data_##idx, \
&my_cfg_##idx, \
MY_DEV_INIT_LEVEL, MY_DEV_INIT_PRIORITY, \
&my_api_funcs)
Notice the use of APIs like :c:macro:`DT_PROP` and
:c:macro:`DEVICE_DT_DEFINE` to access devicetree node data.
Finally, manually detect each enabled devicetree node and use
``CREATE_MY_DEVICE`` to instantiate each ``struct device``:
.. code-block:: c
#if DT_NODE_HAS_STATUS(DT_NODELABEL(mydevice0), okay)
CREATE_MY_DEVICE(0)
#endif
#if DT_NODE_HAS_STATUS(DT_NODELABEL(mydevice1), okay)
CREATE_MY_DEVICE(1)
#endif
Since this style does not use ``DT_INST_FOREACH_STATUS_OKAY()``, the driver
author is responsible for calling ``CREATE_MY_DEVICE()`` for every possible
node, e.g. using knowledge about the peripherals available on supported SoCs.
.. _dt-drivers-that-depend:
Device drivers that depend on other devices
*******************************************
At times, one ``struct device`` depends on another ``struct device`` and
requires a pointer to it. For example, a sensor device might need a pointer to
its SPI bus controller device. Some advice:
- Write your devicetree binding in a way that permits use of
:ref:`devicetree-hw-api` from devicetree.h if possible.
- In particular, for bus devices, your driver's binding should include a
file like :zephyr_file:`dts/bindings/spi/spi-device.yaml` which provides
common definitions for devices addressable via a specific bus. This enables
use of APIs like :c:macro:`DT_BUS` to obtain a node identifier for the bus
node. You can then :ref:`dt-get-device` for the bus in the usual way.
Search existing bindings and device drivers for examples.
.. _dt-apps-that-depend:
Applications that depend on board-specific devices
**************************************************
One way to allow application code to run unmodified on multiple boards is by
supporting a devicetree alias to specify the hardware specific portions, as is
done in the :zephyr:code-sample:`blinky` sample. The application can then be configured in
:ref:`BOARD.dts <devicetree-in-out-files>` files or via :ref:`devicetree
overlays <use-dt-overlays>`.
Setting Kconfig Configuration Values
展开英文原文(RST)
.. _setting_configuration_values:
Setting Kconfig configuration values
####################################
The :ref:`menuconfig and guiconfig interfaces <menuconfig>` can be used to test
out configurations during application development. This page explains how to
make settings permanent.
All Kconfig options can be searched in the :ref:`Kconfig search page
<kconfig-search>`.
.. note::
Before making changes to Kconfig files, it's a good idea to also go through
the :ref:`kconfig_tips_and_tricks` page.
Visible and invisible Kconfig symbols
*************************************
When making Kconfig changes, it's important to understand the difference
between *visible* and *invisible* symbols.
- A visible symbol is a symbol defined with a prompt. Visible symbols show
up in the interactive configuration interfaces (hence *visible*), and can be
set in configuration files.
Here's an example of a visible symbol:
.. code-block:: kconfig
config FPU
bool "Support floating point operations"
depends on HAS_FPU
The symbol is shown like this in ``menuconfig``, where it can be toggled:
.. code-block:: none
[ ] Support floating point operations
- An *invisible* symbol is a symbol without a prompt. Invisible symbols are
not shown in the interactive configuration interfaces, and users have no
direct control over their value. They instead get their value from defaults
or from other symbols.
Here's an example of an invisible symbol:
.. code-block:: kconfig
config CPU_HAS_FPU
bool
help
This symbol is y if the CPU has a hardware floating point unit.
In this case, ``CPU_HAS_FPU`` is enabled through other symbols having
``select CPU_HAS_FPU``.
Setting symbols in configuration files
**************************************
Visible symbols can be configured by setting them in configuration files. The
initial configuration is produced by merging a :file:`*_defconfig` file for the
board with application settings, usually from :file:`prj.conf`. See
:ref:`initial-conf` below for more details.
Assignments in configuration files use this syntax:
.. code-block:: cfg
CONFIG_<symbol name>=<value>
There should be no spaces around the equals sign.
``bool`` symbols can be enabled or disabled by setting them to ``y`` or ``n``,
respectively. The ``FPU`` symbol from the example above could be enabled like
this:
.. code-block:: cfg
CONFIG_FPU=y
.. note::
A boolean symbol can also be set to ``n`` with a comment formatted like
this:
.. code-block:: cfg
# CONFIG_SOME_OTHER_BOOL is not set
This is the format you will see in the merged configuration
saved to :file:`zephyr/.config` in the build directory.
This style is accepted for historical reasons: Kconfig configuration files
can be parsed as makefiles (though Zephyr doesn't use this). Having
``n``-valued symbols correspond to unset variables simplifies tests in Make.
Other symbol types are assigned like this:
.. code-block:: cfg
CONFIG_SOME_STRING="cool value"
CONFIG_SOME_INT=123
Comments use a #:
.. code-block:: cfg
# This is a comment
Assignments in configuration files are only respected if the dependencies for
the symbol are satisfied. A warning is printed otherwise. To figure out what
the dependencies of a symbol are, use one of the :ref:`interactive
configuration interfaces <menuconfig>` (you can jump directly to a symbol with
:kbd:`/`), or look up the symbol in the :ref:`Kconfig search page
<kconfig-search>`.
.. _initial-conf:
The Initial Configuration
*************************
The initial configuration for an application comes from merging configuration
settings from three sources:
1. A ``BOARD``-specific configuration file stored in
:file:`boards/<VENDOR>/<BOARD>/<BOARD>_defconfig`
2. Any CMake cache entries prefix with ``CONFIG_``
3. The application configuration
The application configuration can come from the sources below (each file is
known as a Kconfig fragment, which are then merged to get the final
configuration used for a particular build). By default, :file:`prj.conf` is
used.
#. If ``CONF_FILE`` is set, the configuration file(s) specified in it are
merged and used as the application configuration. ``CONF_FILE`` can be set
in various ways:
1. In :file:`CMakeLists.txt`, before calling ``find_package(Zephyr)``
2. By passing ``-DCONF_FILE=<conf file(s)>``, either directly or via ``west``
3. From the CMake variable cache
#. Otherwise, if :file:`boards/<BOARD>.conf` exists in the application
configuration directory, the result of merging it with :file:`prj.conf` is
used.
#. Otherwise, if board revisions are used and
:file:`boards/<BOARD>_<revision>.conf` exists in the application
configuration directory, the result of merging it with :file:`prj.conf` and
:file:`boards/<BOARD>.conf` is used.
#. Otherwise, :file:`prj.conf` is used from the application configuration
directory. If it does not exist then a fatal error will be emitted.
Furthermore, applications can have SoC overlay configuration that is applied to
it, the file :file:`socs/<SOC>_<BOARD_QUALIFIERS>.conf` will be applied if it exists,
after the main project configuration has been applied and before any board overlay
configuration files have been applied.
All configuration files will be taken from the application's configuration
directory except for files with an absolute path that are given with the
``CONF_FILE``, ``EXTRA_CONF_FILE``, ``DTC_OVERLAY_FILE``, and
``EXTRA_DTC_OVERLAY_FILE`` arguments. For these,
a file in a Zephyr module can be referred by escaping the Zephyr module dir
variable like this ``\${ZEPHYR_<module>_MODULE_DIR}/<path-to>/<file>``
when setting any of said variables in the application's :file:`CMakeLists.txt`.
See :ref:`Application Configuration Directory <application-configuration-directory>`
on how the application configuration directory is defined.
If a symbol is assigned both in :file:`<BOARD>_defconfig` and in the
application configuration, the value set in the application configuration takes
precedence.
The merged configuration is saved to :file:`zephyr/.config` in the build
directory.
As long as :file:`zephyr/.config` exists and is up-to-date (is newer than any
``BOARD`` and application configuration files), it will be used in preference
to producing a new merged configuration. :file:`zephyr/.config` is also the
configuration that gets modified when making changes in the :ref:`interactive
configuration interfaces <menuconfig>`.
Tracking Kconfig symbols
************************
It is possible to create Kconfig symbols which takes the default value of
another Kconfig symbol.
This is valuable when you want a symbol specific to an application or subsystem
but do not want to rely directly on the common symbol. For example, you might
want to decouple the settings so they can be independently configured, or to
ensure you always have a locally named setting, even if the external setting name changes.
is later changed.
For example, consider the common ``FOO_STRING`` setting where a subsystem wants
to have a ``SUB_FOO_STRING`` but still allow for customization.
This can be done like this:
.. code-block:: kconfig
config FOO_STRING
string "Foo"
default "foo"
config SUB_FOO_STRING
string "Sub-foo"
default FOO_STRING
This ensures that the default value of ``SUB_FOO_STRING`` is identical to
``FOO_STRING`` while still allows users to configure both settings
independently.
It is also possible to make ``SUB_FOO_STRING`` invisible and thereby keep the
two symbols in sync, unless the value of the tracking symbol is changed in a
:file:`defconfig` file.
.. code-block:: kconfig
config FOO_STRING
string "Foo"
default "foo"
config SUB_FOO_STRING
string
default FOO_STRING
help
Hidden symbol which follows FOO_STRING
Can be changed through *.defconfig files.
Configuring invisible Kconfig symbols
*************************************
When making changes to the default configuration for a board, you might have to
configure invisible symbols. This is done in
:file:`boards/<VENDOR>/<BOARD>/Kconfig.defconfig`, which is a regular
:file:`Kconfig` file.
.. note::
Assignments in :file:`.config` files have no effect on invisible symbols,
so this scheme is not just an organizational issue.
Assigning values in :file:`Kconfig.defconfig` relies on defining a Kconfig
symbol in multiple locations. As an example, say we want to set ``FOO_WIDTH``
below to 32:
.. code-block:: kconfig
config FOO_WIDTH
int
To do this, we extend the definition of ``FOO_WIDTH`` as follows, in
:file:`Kconfig.defconfig`:
.. code-block:: kconfig
if BOARD_MY_BOARD
config FOO_WIDTH
default 32
endif
.. note::
Since the type of the symbol (``int``) has already been given at the first
definition location, it does not need to be repeated here. Only giving the
type once at the "base" definition of the symbol is a good idea for reasons
explained in :ref:`kconfig_shorthands`.
``default`` values in :file:`Kconfig.defconfig` files have priority over
``default`` values given on the "base" definition of a symbol. Internally, this
is implemented by including the :file:`Kconfig.defconfig` files first. Kconfig
uses the first ``default`` with a satisfied condition, where an empty condition
corresponds to ``if y`` (is always satisfied).
Note that conditions from surrounding top-level ``if``\ s are propagated to
symbol properties, so the above ``default`` is equivalent to
``default 32 if BOARD_MY_BOARD``.
.. _multiple_symbol_definitions:
Multiple symbol definitions
---------------------------
When a symbol is defined in multiple locations, each definition acts as an
independent symbol that happens to share the same name. This means that
properties are not appended to previous definitions. If the conditions
for **ANY** definition result in the symbol resolving to ``y``, the symbol
will be ``y``. It is therefore not possible to make the dependencies of a
symbol more restrictive by defining it in multiple locations.
For example, the dependencies of the symbol ``FOO`` below are satisfied if
either ``DEP1`` **OR** ``DEP2`` are true, it does not require both:
.. code-block:: none
config FOO
...
depends on DEP1
config FOO
...
depends on DEP2
.. warning::
Symbols without explicit dependencies still follow the above rule. A
symbol without any dependencies will result in the symbol always being
assignable. The definition below will result in ``FOO`` always being
enabled by default, regardless of the value of ``DEP1``.
.. code-block:: kconfig
config FOO
bool "FOO"
depends on DEP1
config FOO
default y
This dependency weakening can be avoided with the :ref:`configdefault
<kconfig_extensions>` extension if the desire is only to add a new default
without modifying any other behaviour of the symbol.
.. note::
When making changes to :file:`Kconfig.defconfig` files, always check the
symbol's direct dependencies in one of the :ref:`interactive configuration
interfaces <menuconfig>` afterwards. It is often necessary to repeat
dependencies from the base definition of the symbol to avoid weakening a
symbol's dependencies.
Motivation for Kconfig.defconfig files
--------------------------------------
One motivation for this configuration scheme is to avoid making fixed
``BOARD``-specific settings configurable in the interactive configuration
interfaces. If all board configuration were done via :file:`<BOARD>_defconfig`,
all symbols would have to be visible, as values given in
:file:`<BOARD>_defconfig` have no effect on invisible symbols.
Having fixed settings be user-configurable would clutter up the configuration
interfaces and make them harder to understand, and would make it easier to
accidentally create broken configurations.
When dealing with fixed board-specific settings, also consider whether they
should be handled via :ref:`devicetree <dt-guide>` instead.
Configuring choices
-------------------
There are two ways to configure a Kconfig ``choice``:
1. By setting one of the choice symbols to ``y`` in a configuration file.
Setting one choice symbol to ``y`` automatically gives all other choice
symbols the value ``n``.
If multiple choice symbols are set to ``y``, only the last one set to ``y``
will be honored (the rest will get the value ``n``). This allows a choice
selection from a board :file:`defconfig` file to be overridden from an
application :file:`prj.conf` file.
2. By changing the ``default`` of the choice in :file:`Kconfig.defconfig`.
As with symbols, changing the default for a choice is done by defining the
choice in multiple locations. For this to work, the choice must have a name.
As an example, assume that a choice has the following base definition (here,
the name of the choice is ``FOO``):
.. code-block:: kconfig
choice FOO
bool "Foo choice"
default B
config A
bool "A"
config B
bool "B"
endchoice
To change the default symbol of ``FOO`` to ``A``, you would add the
following definition to :file:`Kconfig.defconfig`:
.. code-block:: kconfig
choice FOO
default A
endchoice
The :file:`Kconfig.defconfig` method should be used when the dependencies of
the choice might not be satisfied. In that case, you're setting the default
selection whenever the user makes the choice visible.
More Kconfig resources
======================
The :ref:`kconfig_tips_and_tricks` page has some tips for writing Kconfig
files.
The :zephyr_file:`kconfiglib.py <scripts/kconfig/kconfiglib.py>` docstring
(at the top of the file) goes over how symbol values are calculated in detail.