doc: update board porting guide to match new hardware model
Update board porting guide to the design changes in the new hw model.
New section added:
- board.yml file description
Updated sections:
- Board on SoCs example table updated to new format and extra examples
added.
- Board directory description and its files
- Writing devicetree file section updated to match new lookup patterns
- Writing Kconfig file section updated to match new lookup patterns
- Board revision handling updated
In getting started guide a note has been added with short description
of the new board and board identifier scheme.
Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
pull/69687/head
Torsten Rasmussen2 years agocommitted byCarles Cufi
@ -560,6 +560,17 @@ users. Users may also use the ``-p auto`` option, which will use
@@ -560,6 +560,17 @@ 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 :ref:`nRF5340DK <nrf5340dk_nrf5340>` the board must be provided as:
``nrf5340dk/nrf5340/cpuapp``. Also read :ref:`board_and_identifiers` for more
@ -8,17 +8,78 @@ directory* with various files in it. Files in the board directory inherit
@@ -8,17 +8,78 @@ directory* with various files in it. Files in the board directory inherit
support for at least one SoC and all of its features. Therefore, Zephyr must
support your :term:`SoC` as well.
.._board_and_identifiers:
Board and board identifiers
***************************
A board may be a physical piece of hardware or an emulated board.
Furthermore a board may contain one or multiple SoCs. Also, each SoC may contain
one or multiple CPU clusters. A CPU cluster refers to a group of CPU cores.
Only CPU cores of same architecture can be in the same cluster. In the case
where a physical SoC considers a CPU cluster to contain CPU cores of different
architectures then those must be modelled as multiple clusters, where all CPU
cores within a cluster is having the same architecture.
It is possible to have only a single CPU core within a CPU cluster.
It's possible to define variants for dedicated use-cases.
Examples of such use-cases are:
- Variant which enables non-secure builds for SoCs containing a security
processor.
- Variant enabling / changing the type of RAM used in by the build.
A ``/`` is used as separator between the board name and the following:
SoC, CPU cluster, and variant identifiers.
If a board contains only a single core SoC, then the SoC can be omitted when
building.
Let's say there is a board named ``plank`` with a single-core SoC ``soc1``.
The board including the identifier is: ``plank/soc1``.
As ``plank`` is a single SoC board, then the following is sufficient: ``plank``
to use as board when building.
If ``plank`` defines board variants, then those are identified by appending the
``/<variant>`` name after the SoC, for example to build for the ``foo`` variant,
use: ``plank/soc1/foo``, and if omitting the SoC use: ``plank//foo``.
Here the double ``//`` indicates to the build system that the SoC has been
omitted.
So to build hello world for ``plank``, variant ``foo``, you can do:
..code-block:: console
west build -b plank//foo samples/hello_world
When using multi-core SoCs, the CPU cluster is identified after the SoC
identifier.
If ``soc1`` above has two cores, ``first`` and ``second``, then those are
identified as: ``plank/soc1/first`` and ``plank/soc1/second``.
And similar to before, if the board has only a single SoC, the SoC can be
omitted, that is ``plank//first`` and ``plank//second`` is an identical short
form.
.._hw_support_hierarchy:
Boards, SoCs, etc.
******************
Zephyr's hardware support hierarchy has these layers, from most to least
specific:
- Board: a particular CPU instance and its peripherals in a concrete hardware
specification
- Board: a specific board which usually corresponds to a physical board.
A board may contain multiple SoCs.
A build targets a specific CPU cluster on a board which has multiple
CPUs, be these in different SOCs or in a SOC with multiple AMP CPU
clusters.
- SoC: the exact system on a chip the board's CPU is part of
- SoC series: a smaller group of tightly related SoCs
- SoC family: a wider group of SoCs with similar characteristics
- CPU Cluster: a cluster of one or more CPU cores.
- CPU core: a particular CPU in an architecture
- Architecture: an instruction set architecture
@ -34,39 +95,26 @@ You can visualize the hierarchy like this:
@@ -34,39 +95,26 @@ You can visualize the hierarchy like this:
Here are some examples. Notice how the SoC series and family levels are
@ -78,7 +126,7 @@ Start by making sure your SoC is supported by Zephyr. If it is, it's time to
@@ -78,7 +126,7 @@ Start by making sure your SoC is supported by Zephyr. If it is, it's time to
board documentation to find out for sure.
- asking your SoC vendor
If you need to add SoC, CPU core, or even architecture support, this is the
If you need to add a SoC, CPU cluster, or even architecture support, this is the
wrong page, but here is some general advice.
Architecture
@ -107,7 +155,7 @@ Zephyr SoC support files are in architecture-specific subdirectories of
@@ -107,7 +155,7 @@ Zephyr SoC support files are in architecture-specific subdirectories of
When adding a new SoC family or series for a vendor that already has SoC
support within Zephyr, please try to extract common functionality into shared
files to avoid duplication. If there is no support for your vendor yet, you can
add it in a new directory ``zephyr/soc/<YOUR-ARCH>/<YOUR-SOC>``; please use
add it in a new directory ``zephyr/soc/<VENDOR>/<YOUR-SOC>``; please use
self-explanatory directory names.
.._create-your-board-directory:
@ -123,52 +171,72 @@ You need to give your board a unique name. Run ``west boards`` for a list of
@@ -123,52 +171,72 @@ You need to give your board a unique name. Run ``west boards`` for a list of
names that are already taken, and pick something new. Let's say your board is
called ``plank`` (please don't actually use that name).
Start by creating the board directory ``zephyr/boards/<ARCH>/plank``, where
``<ARCH>`` is your SoC's architecture subdirectory. (You don't have to put your
Start by creating the board directory ``zephyr/boards/<VENDOR>/plank``, where
``<VENDOR>`` is your vendor subdirectory. (You don't have to put your
board directory in the zephyr repository, but it's the easiest way to get
started. See :ref:`custom_board_definition` for documentation on moving your
board directory to a separate repository once it's working.)
..note::
A ``<VENDOR>`` subdirectory is mandatory if contributing your board
to Zephyr, but if your board is placed in a local repo, then any folder
structure under ``<your-repo>/boards`` is permitted.
If the vendor is defined in the list in
:zephyr_file:`dts/bindings/vendor-prefixes.txt` then you must use
that vendor prefix as ``<VENDOR>``. ``others`` may be used as vendor prefix if
the vendor is not defined.
..note::
The board directory name does not need to match the name of the board.
Multiple boards can even defined be in one directory.
For example, for boards with multi-core SoC, a logical board might be created
for each core following the naming scheme `<board>_<soc-core>`, with definitions
for all of these different boards defined inside the same directory. This and
similar schemes are common for upstream vendor boards.
Your board directory should look like this:
..code-block:: none
boards/<ARCH>/plank
boards/<VENDOR>/plank
├── board.yml
├── board.cmake
├── CMakeLists.txt
├── doc
│ ├── plank.png
│ └── index.rst
├── Kconfig.board
├── Kconfig.plank
├── Kconfig.defconfig
├── plank_defconfig
├── plank_<identifier>_defconfig
├── plank.dts
├── plank_<identifier>.dts
└── plank.yaml
Replace ``plank`` with your board's name, of course.
The mandatory files are:
#. :file:`plank.dts`: a hardware description in :ref:`devicetree
<dt-guide>` format. This declares your SoC, connectors, and any
other hardware components such as LEDs, buttons, sensors, or communication
peripherals (USB, BLE controller, etc).
#. :file:`board.yml`: a YAML file describing the high-level meta data of the
boards such as the boards names, their SoCs, and variants.
CPU clusters for multi-core SoCs are not described in this file as they are
inherited from the SoC's YAML description.
#. :file:`plank.dts` or :file:`plank_<identifier>.dts`: a hardware description
in :ref:`devicetree <dt-guide>` format. This declares your SoC, connectors,
and any other hardware components such as LEDs, buttons, sensors, or
communication peripherals (USB, BLE controller, etc).
#. :file:`Kconfig.plank`: the base software configuration for selecting SoC and
other board and SoC related settings. Kconfig settings outside of the board
and SoC tree must not be selected. To select general Zephyr Kconfig settings
software configuration in :ref:`kconfig` formats. This provides default
settings for software features and peripheral drivers.
The optional files are:
- :file:`Kconfig`, :file:`Kconfig.defconfig` software configuration in
:ref:`kconfig` formats. This provides default settings for software features
and peripheral drivers.
- :file:`plank_defconfig` and :file:`plank_<identifier>_defconfig`: software
configuration in Kconfig ``.conf`` format.
- :file:`board.cmake`: used for :ref:`flash-and-debug-support`
- :file:`CMakeLists.txt`: if you need to add additional source files to
your build.
@ -178,12 +246,70 @@ The optional files are:
@@ -178,12 +246,70 @@ The optional files are:
- :file:`plank.yaml`: a YAML file with miscellaneous metadata used by the
:ref:`twister_script`.
Board identifiers of the form ``<soc>/<cpucluster>/<variant>`` are sanitized so
that ``/`` is replaced with ``_`` when used for filenames, for example:
``soc1/foo`` becomes ``soc1_foo`` when used in filenames.
.._board_description:
Write your board YAML
*********************
The board YAML file describes the board at a high level.
This includes the SoC, board variants, and board revisions.
Detailed configurations, such as hardware description and configuration are done
in devicetree and Kconfig.
The skeleton of the board YAML file is:
..code-block:: yaml
board:
name: <board-name>
vendor: <board-vendor>
revision:
format: <major.minor.patch|letter|number|custom>
default: <default-revision-value>
exact: <true|false>
revisions:
- name: <revA>
- name: <revB>
...
socs:
- name: <soc-1>
variants:
- name: <variant-1>
- name: <variant-2>
variants:
- name: <sub-variant-2-1>
...
- name: <soc-2>
...
It is possible to have multiple boards located in the board folder.
If multiple boards are placed in the same board folder, then the file
:file:`board.yml` must describe those in a list as:
..code-block:: yaml
boards:
- name: <board-name-1>
vendor: <board-vendor>
...
- name: <board-name-2>
vendor: <board-vendor>
...
...
.._default_board_configuration:
Write your devicetree
*********************
The devicetree file :file:`boards/<ARCH>/plank/plank.dts` describes your board
The devicetree file :file:`boards/<vendor>/plank/plank.dts` or
:file:`boards/<vendor>/plank/plank_<identifier>.dts` describes your board
hardware in the Devicetree Source (DTS) format (as usual, change ``plank`` to
your board's name). If you're new to devicetree, see :ref:`devicetree-intro`.
@ -195,48 +321,59 @@ In general, :file:`plank.dts` should look like this:
@@ -195,48 +321,59 @@ In general, :file:`plank.dts` should look like this:
#include <your_soc_vendor/your_soc.dtsi>
/ {
model = "A human readable name";
compatible = "yourcompany,plank";
chosen {
zephyr,console = &your_uart_console;
zephyr,sram = &your_memory_node;
/* other chosen settings for your hardware */
};
/*
* Your board-specific hardware: buttons, LEDs, sensors, etc.
*/
leds {
compatible = "gpio-leds";
led0: led_0 {
gpios = < /* GPIO your LED is hooked up to */ >;
label = "LED 0";
};
/* ... other LEDs ... */
};
buttons {
compatible = "gpio-keys";
/* ... your button definitions ... */
};
/* These aliases are provided for compatibility with samples */
aliases {
led0 = &led0; /* now you support the blinky sample! */
/* other aliases go here */
};
model = "A human readable name";
compatible = "yourcompany,plank";
chosen {
zephyr,console = &your_uart_console;
zephyr,sram = &your_memory_node;
/* other chosen settings for your hardware */
};
/*
* Your board-specific hardware: buttons, LEDs, sensors, etc.
*/
leds {
compatible = "gpio-leds";
led0: led_0 {
gpios = < /* GPIO your LED is hooked up to */ >;
label = "LED 0";
};
/* ... other LEDs ... */
};
buttons {
compatible = "gpio-keys";
/* ... your button definitions ... */
};
/* These aliases are provided for compatibility with samples */
aliases {
led0 = &led0; /* now you support the blinky sample! */
/* other aliases go here */
};
};
&some_peripheral_you_want_to_enable { /* like a GPIO or SPI controller */
status = "okay";
status = "okay";
};
&another_peripheral_you_want {
status = "okay";
status = "okay";
};
Only one ``.dts`` file will be used, and the most specific file which exists
will be used.
This means that if both :file:`plank.dts` and :file:`plank_soc1_foo.dts` exist,
then when building for ``plank`` / ``plank/soc1``, then :file:`plank.dts` is
used. When building for ``plank//foo`` / ``plank/soc1/foo`` the
:file:`plank_soc1_foo.dts` is used.
This allows board maintainers to write a base devicetree file for the board
or write specific devicetree files for a given board's SoC or variant.
If you're in a hurry, simple hardware can usually be supported by copy/paste
followed by trial and error. If you want to understand details, you will need
to read the rest of the devicetree documentation and the devicetree
@ -273,9 +410,9 @@ follows (with unimportant parts skipped):
@@ -273,9 +410,9 @@ follows (with unimportant parts skipped):
..code-block:: devicetree
can0: can@40024000 {
...
status = "disabled";
...
...
status = "disabled";
...
};
It is up to the board :file:`.dts` or application overlay files to enable these
@ -289,8 +426,8 @@ controller and sets the bus speed:
@@ -289,8 +426,8 @@ controller and sets the bus speed:
..code-block:: devicetree
&can0 {
status = "okay";
bus-speed = <125000>;
status = "okay";
bus-speed = <125000>;
};
The ``&can0 { ... };`` syntax adds/overrides properties on the node with label
@ -300,6 +437,8 @@ Other examples of board-specific customization is pointing properties in
@@ -300,6 +437,8 @@ Other examples of board-specific customization is pointing properties in
``aliases`` and ``chosen`` to the right nodes (see :ref:`dt-alias-chosen`), and
making GPIO/pinmux assignments.
.._board_kconfig_files:
Write Kconfig files
*******************
@ -310,33 +449,61 @@ application for it.
@@ -310,33 +449,61 @@ application for it.
Setting Kconfig configuration values is documented in detail in
:ref:`setting_configuration_values`.
There are three mandatory Kconfig files in the board directory for a board
named ``plank``:
There is one mandatory Kconfig file in the board directory, and several optional
files for a board named ``plank``:
..code-block:: none
boards/<ARCH>/plank
├── Kconfig.board
boards/<vendor>/plank
├── Kconfig
├── Kconfig.plank
├── Kconfig.defconfig
└── plank_defconfig
├── plank_defconfig
└── plank_<identifier>_defconfig
:file:`Kconfig.plank`
A shared Kconfig file which can be sourced both in Zephyr Kconfig and sysbuild
Kconfig trees.
:file:`Kconfig.board`
Included by :zephyr_file:`boards/Kconfig` to include your board
in the list of options.
This file selects the SoC in the Kconfig tree and potential other SoC related
Kconfig settings. This file must not select anything outside the re-usable
Kconfig board and SoC trees.
This should at least contain a definition for a ``BOARD_PLANK`` option,
which looks something like this:
A :file:`Kconfig.plank` may look like this:
..code-block:: kconfig
config BOARD_PLANK
bool "Plank board"
depends on SOC_SERIES_YOUR_SOC_SERIES_HERE
select SOC_PART_NUMBER_ABCDEFGH
select SOC_SOC1
The Kconfig symbols :kconfig:option:`BOARD_<board>` and
:kconfig:option:`BOARD_<board_with_identifier>` are constructed by the build
system, therefore no type shall be defined in above code snippet.
:file:`Kconfig`
Included by :zephyr_file:`boards/Kconfig`.
This file can add Kconfig settings which are specific to the current board.
Not all boards have a :file:`Kconfig` file.
A board specific setting should be defining a custom setting and usually with
a prompt, like this:
..code-block:: kconfig
config BOARD_FEATURE
bool "Board specific feature"
If the setting name is identical to an existing Kconfig setting in Zephyr and
only modifies the default value of said setting, then
:file:`Kconfig.defconfig` should be used instead.
:file:`Kconfig.defconfig`
Board-specific default values for Kconfig options.
Not all boards have a :file:`Kconfig.defconfig` file.
The entire file should be inside an ``if BOARD_PLANK`` / ``endif`` pair of
lines, like this:
@ -347,35 +514,42 @@ named ``plank``:
@@ -347,35 +514,42 @@ named ``plank``:
# Always set CONFIG_BOARD here. This isn't meant to be customized,
# but is set as a "default" due to Kconfig language restrictions.
config BOARD
default "plank"
default "plank"
# Other options you want enabled by default go next. Examples:
See :ref:`application_board_version` for basics on this feature from the user
perspective.
To create a new board revision for the ``plank`` board, create these additional
files in the board folder:
..code-block:: none
boards/<ARCH>/plank
├── plank_<revision>.conf # optional
├── plank_<revision>.overlay # optional
└── revision.cmake
When the user builds for board ``plank@<revision>``:
Board revisions are described in the ``revision`` entry of the
:file:`board.yml`.
- The optional Kconfig settings specified in the file
:file:`plank_<revision>.conf` will be merged into the board's default Kconfig
configuration.
..code-block:: yaml
- The optional devicetree overlay :file:`plank_<revision>.overlay` will be added
to the common :file:`plank.dts` devicetree file
board:
revision:
format: <major.minor.patch|letter|number|custom>
default: <default-revision-value>
exact: <true|false>
revisions:
- name: <revA>
- name: <revB>
- The :file:`revision.cmake` file controls how the Zephyr build system matches
the ``<board>@<revision>`` string specified by the user when building an
application for the board.
Zephyr natively supports the following revision formats:
Currently, ``<revision>`` can be either a numeric ``MAJOR.MINOR.PATCH`` style
revision like ``1.5.0``, an integer number like ``1``, or single letter like
``A``, ``B``, etc. Zephyr provides a CMake board extension function,
``board_check_revision()``, to make it easy to match either style from
:file:`revision.cmake`.
- ``major.minor.patch``: match a three digit revision, such as ``1.2.3``.
- ``number``: matches integer revisions
- ``letter``: matches single letter revisions from ``A`` to ``Z`` only
Valid board revisions may be specified as arguments to the
``board_check_revision()`` function, like:
..code-block:: cmake
board_check_revision(FORMAT MAJOR.MINOR.PATCH
VALID_REVISIONS 0.1.0 0.3.0 ...
)
..note::
``VALID_REVISIONS`` can be omitted if all valid revisions have specific
Kconfig fragments, such as ``<board>_0_1_0.conf``, ``<board>_0_3_0.conf``.
This allows you to just place Kconfig revision fragments in the board
folder and not have to keep the corresponding ``VALID_REVISIONS`` in sync.
The following sections describe how to support these styles of revision
numbers.
MAJOR.MINOR.PATCH revisions
===========================
Let's say you want to add support for revisions ``0.5.0``, ``1.0.0``, and
``1.5.0`` of the ``plank`` board with both Kconfig fragments and devicetree
overlays. Create :file:`revision.cmake` with
``board_check_revision(FORMAT MAJOR.MINOR.PATCH)``, and create the following
additional files in the board directory:
..code-block:: none
boards/<ARCH>/plank
├── plank_0_5_0.conf
├── plank_0_5_0.overlay
├── plank_1_0_0.conf
├── plank_1_0_0.overlay
├── plank_1_5_0.conf
├── plank_1_5_0.overlay
└── revision.cmake
Notice how the board files have changed periods (".") in the revision number to
underscores ("_").
.._board_fuzzy_revision_matching:
Fuzzy revision matching
-----------------------
To support "fuzzy" ``MAJOR.MINOR.PATCH`` revision matching for the ``plank``
board, use the following code in :file:`revision.cmake`:
..code-block:: cmake
=======================
board_check_revision(FORMAT MAJOR.MINOR.PATCH)
Fuzzy revision matching is enabled per default.
If the user selects a revision between those available, the closest revision
number that is not larger than the user's choice is used. For example, if the
user builds for ``plank@0.7.0``, the build system will target revision
``0.5.0``.
board ``plank`` defines revisions ``0.5.0``, and ``1.5.0`` and the user builds
for ``plank@0.7.0``, the build system will target revision ``0.5.0``.
The build system will print this at CMake configuration time:
@ -617,149 +738,107 @@ The build system will print this at CMake configuration time:
@@ -617,149 +738,107 @@ The build system will print this at CMake configuration time:
This allows you to only create revision configuration files for board revision
numbers that introduce incompatible changes.
Any revision less than the minimum defined will be treated as an error.
You may use ``0.0.0`` as a minimum revision to build for by creating the file
:file:`plank_0_0_0.conf` in the board directory. This will be used for any
revision lower than ``0.5.0``, for example if the user builds for
``plank@0.1.0``.
Similar for ``letter`` where revision ``A``, ``D``, and ``F`` could be defined
and the user builds for ``plank@E``, the build system will target revision ``D``
.
Exact revision matching
-----------------------
Alternatively, the ``EXACT`` keyword can be given to ``board_check_revision()``
in :file:`revision.cmake` to allow exact matches only, like this:
=======================
..code-block:: cmake
Exact revision matching is enabled when ``exact: true`` is specified in the