doc: finish reworking the board porting guide

Now that the west parts of this file are in better shape, it seems a
shame not to flesh out the rest a bit more.

It's been a while since we looked at this document, as it's still
referring to boards (like Arduino 101) that are no longer supported by
Zephyr, and is generally lacking in concrete, step-by-step advice
for going from zero to working board.

Let's fix that.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This commit is contained in:
Martí Bolívar 2020-03-04 14:55:19 -08:00 committed by Johan Hedberg
commit fe6107f2b3
3 changed files with 344 additions and 121 deletions

View file

@ -65,6 +65,9 @@ Glossary of Terms
The set of Zephyr-supplied files that implement the Zephyr kernel, The set of Zephyr-supplied files that implement the Zephyr kernel,
including its core services, device drivers, network stack, and so on. including its core services, device drivers, network stack, and so on.
SoC
`System on a chip`_
west west
A multi-repo meta-tool developed for the Zephyr project. See :ref:`west`. A multi-repo meta-tool developed for the Zephyr project. See :ref:`west`.
@ -92,3 +95,5 @@ Glossary of Terms
(eXecute In Place) a method of executing programs directly from long (eXecute In Place) a method of executing programs directly from long
term storage rather than copying it into RAM, saving writable memory for term storage rather than copying it into RAM, saving writable memory for
dynamic data and not the static program code. dynamic data and not the static program code.
.. _System on a chip: https://en.wikipedia.org/wiki/System_on_a_chip

View file

@ -3,40 +3,26 @@
Board Porting Guide Board Porting Guide
################### ###################
When building an application you must specify the target hardware and To add Zephyr support for a new :term:`board`, you at least need a *board
the exact board or model. Specifying the board name results in a binary that directory* with various files in it. Files in the board directory inherit
is suited for the target hardware by selecting the right Zephyr features and support for at least one SoC and all of its features. Therefore, Zephyr must
components and setting the right Zephyr configuration for that specific target support your :term:`SoC` as well.
hardware.
A board is defined as a special configuration of an SoC with possible additional Boards, SoCs, etc.
components. ******************
For example, a board might have sensors and flash memory implemented as
additional features on top of what the SoC provides. Such additional hardware is
configured and referenced in the Zephyr board configuration.
The board implements at least one SoC and thus inherits all of the features Zephyr's hardware support hierarchy has these layers, from most to least
that are provided by the SoC. When porting a board to Zephyr, you should specific:
first make sure the SoC is implemented in Zephyr.
Hardware Configuration Hierarchy - Board: a particular CPU instance and its peripherals in a concrete hardware
******************************** specification
- 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 core: a particular CPU in an architecture
- Architecture: an instruction set architecture
Hardware definitions in Zephyr follow a well-defined hierarchy of configurations You can visualize the hierarchy like this:
and layers, below are the layers from top to bottom:
- Board
- SoC
- SoC Series
- SoC Family
- CPU Core
- Architecture
This design contributes to code reuse and implementation of device drivers and
features at the bottom of the hierarchy making a board configuration as simple
as a selection of features that are implemented by the underlying layers. The
figures below shows this hierarchy with a few example of boards currently
available in the source tree:
.. figure:: board/hierarchy.png .. figure:: board/hierarchy.png
:width: 500px :width: 500px
@ -45,135 +31,349 @@ available in the source tree:
Configuration Hierarchy Configuration Hierarchy
Here are some examples. Notice how the SoC series and family levels are
not always used.
Hierarchy Example .. list-table::
:header-rows: 1
+------------+-----------+--------------+------------+--------------+---------+ * - Board
|Board |FRDM K64F |nRF52 NITROGEN|nRF51XX |Quark SE C1000|Arduino | - SoC
| | | | |Devboard |101 | - SoC series
+============+===========+==============+============+==============+=========+ - SoC family
|SOC |MK64F12 |nRF52832 |nRF51XX |Quark SE C1000|Curie | - CPU core
+------------+-----------+--------------+------------+--------------+---------+ - Architecture
|SOC Series |Kinetis K6x|Nordic NRF52 |Nordic NRF51|Quark SE |Quark SE | * - :ref:`nrf52_pca10040 <nrf52_pca10040>`
| |Series | | | | | - nRF52832
+------------+-----------+--------------+------------+--------------+---------+ - nRF52
|SOC Family |NXP Kinetis|Nordic NRF5 |Nordic NRF5 |Quark |Quark | - Nordic nRF5
+------------+-----------+--------------+------------+--------------+---------+ - Arm Cortex-M4
|CPU Core |Cortex-M4 |Cortex-M4 |Cortex-M0 |Lakemont |Lakemont | - Arm
+------------+-----------+--------------+------------+--------------+---------+ * - :ref:`frdm_k64f <frdm_k64f>`
|Architecture|ARM |ARM |ARM |x86 |x86 | - MK64F12
+------------+-----------+--------------+------------+--------------+---------+ - Kinetis K6x
- NXP Kinetis
- Arm Cortex-M4
- Arm
* - :ref:`stm32h474i_disco <stm32h747i_disco_board>`
- STM32H747XI
- STM32H7
- STMicro STM32
- Arm Cortex-M7
- Arm
* - :ref:`rv32m1_vega_ri5cy <rv32m1_vega>`
- RV32M1
- (Not used)
- (Not used)
- RI5CY
- RISC-V
Make sure your SoC is supported
*******************************
Start by making sure your SoC is supported by Zephyr. If it is, it's time to
:ref:`create-your-board-directory`. If you don't know, try:
- checking :ref:`boards` for names that look relevant, and reading individual
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
wrong page, but here is some general advice.
Architecture Architecture
============ ============
If your CPU architecture is already supported by Zephyr, there is no
architecture work involved in porting to your board. If your CPU architecture See :ref:`architecture_porting_guide`.
is not supported by the Zephyr kernel, you can add support by following the
instructions available at :ref:`architecture_porting_guide`.
CPU Core CPU Core
======== ========
Some OS code depends on the CPU core that your board is using. For CPU core support files go in ``core`` subdirectories under :zephyr_file:`arch`,
example, a given CPU core has a specific assembly language instruction set, and e.g. :zephyr_file:`arch/x86/core`.
may require special cross compiler or compiler settings to use the appropriate
instruction set.
If your CPU architecture is already supported by Zephyr, there is no CPU core See :ref:`gs_toolchain` for information about toolchains (compiler, linker,
work involved in porting to your platform or board. You need only to select the etc.) supported by Zephyr. If you need to support a new toolchain,
appropriate CPU in your configuration and the rest will be taken care of by the :ref:`build_overview` is a good place to start learning about the build system.
configuration system in Zephyr which will select the features implemented Please reach out to the community if you are looking for advice or want to
by the corresponding CPU. collaborate on toolchain support.
Platform
========
This layer implements most of the features that need porting and is split into
three layers to allow for code reuse when dealing with implementations with
slight differences.
SoC Family
----------
This layer is a container of all SoCs of the same class that, for example
implement one single type of CPU core but differ in peripherals and features.
The base hardware will in most cases be the same across all SoCs and MCUs of
this family.
SoC Series
----------
Moving closer to the SoC, the series is derived from an SoC family. A series is
defined by a feature set that serves the purpose of distinguishing different
SoCs belonging to the same family.
SoC SoC
--- ===
Finally, an SoC is actual hardware component that is physically available on a Zephyr SoC support files are in architecture-specific subdirectories of
board. :zephyr_file:`soc`. They are generally grouped by SoC family.
Board 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
self-explanatory directory names.
A board implements an SoC with all its features, together with peripherals .. _create-your-board-directory:
available on the board that differentiates the board with additional interfaces
and features not available in the SoC.
A board port on Zephyr typically consists of two parts: Create your board directory
***************************
- A hardware description (usually done by device tree), which specifies embedded Once you've found an existing board that uses your SoC, you can usually start
SoC reference, connectors and any other hardware components such as LEDs, by copy/pasting its board directory and changing its contents for your
buttons, sensors or communication peripherals (USB, BLE controller, ...). hardware.
- A software configuration (done using Kconfig) of features and peripheral You need to give your board a unique name. Run ``west boards`` for a list of
drivers. This default board configuration is subordinated to features names that are already taken, and pick something new. Let's say your board is
activation which is application responsibility. Though, it should also enable called ``plank`` (please don't actually use that name).
a minimal set of features common to many applications and to applicable
project-provided :ref:`samples-and-demos`.
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
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.)
Your board directory should look like this:
.. code-block:: none
boards/<ARCH>/plank
├── board.cmake
├── CMakeLists.txt
├── doc
│   ├── plank.png
│   └── index.rst
├── Kconfig.board
├── Kconfig.defconfig
├── plank_defconfig
├── plank.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` 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.board`, :file:`Kconfig.defconfig`, :file:`plank_defconfig`:
software configuration in :ref:`kconfig` formats. This provides default
settings for software features and peripheral drivers.
The optional files are:
- :file:`board.cmake`: used for :ref:`flash-and-debug-support`
- :file:`CMakeLists.txt`: if you need to add additional source files to
your build.
One common use for this file is to add a :file:`pinmux.c` file in your board
directory to the build, which configures pin controllers at boot time. In
that case, :file:`CMakeLists.txt` usually looks like this:
.. code-block:: cmake
if(CONFIG_PINMUX)
zephyr_library()
zephyr_library_sources(pinmux.c)
zephyr_library_include_directories(${ZEPHYR_BASE}/drivers)
endif()
- :file:`doc/index.rst`, :file:`doc/plank.png`: documentation for and a picture
of your board. You only need this if you're :ref:`contributing-your-board` to
Zephyr.
- :file:`plank.yaml`: a YAML file with miscellaneous metadata used by the
:ref:`sanitycheck_script`.
.. _default_board_configuration: .. _default_board_configuration:
Default board configuration Write your devicetree
*************************** *********************
When porting Zephyr to a board, you must provide the board's default The devicetree file :file:`boards/<ARCH>/plank/plank.dts` describes your board
Kconfig configuration, which is used in application builds unless explicitly hardware in the Devicetree Source (DTS) format (as usual, change ``plank`` to
overridden. your board's name). If you're new to devicetree, see :ref:`devicetree-intro`.
In general, :file:`plank.dts` should look like this:
.. code-block:: none
/dts-v1/;
#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 */
};
};
&some_peripheral_you_want_to_enable { /* like a GPIO or SPI controller */
status = "okay";
};
&another_peripheral_you_want {
status = "okay";
};
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
specification.
Write Kconfig files
*******************
Zephyr uses the Kconfig language to configure software features. Your board
needs to provide some Kconfig settings before you can compile a Zephyr
application for it.
Setting Kconfig configuration values is documented in detail in Setting Kconfig configuration values is documented in detail in
:ref:`setting_configuration_values`, which you should go through. Note that the :ref:`setting_configuration_values`.
default board configuration might involve both :file:`<BOARD>_defconfig` and
:file:`Kconfig.defconfig` files. The rest of this section contains some
board-specific guidelines.
In order to provide consistency across the various boards and ease the work of There are three mandatory Kconfig files in the board directory for a board
users providing applications that are not board specific, the following named ``plank``:
guidelines should be followed when porting a board. Unless explicitly stated,
peripherals should be disabled by default.
- Configure and enable a working clock configuration, along with a tick source. .. code-block:: none
boards/<ARCH>/plank
├── Kconfig.board
├── Kconfig.defconfig
└── plank_defconfig
:file:`Kconfig.board`
Included by :zephyr_file:`boards/Kconfig` to include your board
in the list of options.
This should at least contain a definition for a ``BOARD_PLANK`` option,
which looks something like this:
.. code-block:: none
config BOARD_PLANK
bool "Plank board"
depends on SOC_SERIES_YOUR_SOC_SERIES_HERE
select SOC_PART_NUMBER_ABCDEFGH
:file:`Kconfig.defconfig`
Board-specific default values for Kconfig options.
The entire file should be inside an ``if BOARD_PLANK`` / ``endif`` pair of
lines, like this:
.. code-block:: none
if BOARD_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"
# Other options you want enabled by default go next. Examples:
config FOO
default y
if NETWORKING
config SOC_ETHERNET_DRIVER
default y
endif # NETWORKING
endif # BOARD_PLANK
:file:`plank_defconfig`
A Kconfig fragment that is merged as-is into the final build directory
:file:`.config` whenever an application is compiled for your board.
You should at least select your board's SOC and do any mandatory settings for
your system clock, console, etc. The results are architecture-specific, but
typically look something like this:
.. code-block:: none
CONFIG_SOC_${VENDOR_XYZ3000}=y /* select your SoC */
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=120000000 /* set up your clock, etc */
CONFIG_SERIAL=y
Build, test, and fix
********************
Now it's time to build and test the application(s) you want to run on your
board until you're satisfied.
For example:
.. code-block:: console
west build -b plank samples/hello_world
west flash
For ``west flash`` to work, see :ref:`flash-and-debug-support` below. You can
also just flash :file:`build/zephyr/zephyr.elf`, :file:`zephyr.hex`, or
:file:`zephyr.bin` with any other tools you prefer.
.. _porting-general-recommendations:
General recommendations
***********************
For consistency and to make it easier for users to build generic applications
that are not board specific for your board, please follow these guidelines
while porting.
- Unless explicitly recommended otherwise by this section, leave peripherals
and their drivers disabled by default.
- Configure and enable a system clock, along with a tick source.
- Provide pin and driver configuration that matches the board's valuable - Provide pin and driver configuration that matches the board's valuable
components such as sensors, buttons or LEDs, and communication interfaces components such as sensors, buttons or LEDs, and communication interfaces
such as USB, Ethernet connector, or Bluetooth/Wi-Fi chip. such as USB, Ethernet connector, or Bluetooth/Wi-Fi chip.
- When a well-known connector is present (such as used on an Arduino or - If your board uses a well-known connector standard (like Arduino, Mikrobus,
96board), configure pins to fit this connector. Grove, or 96Boards connectors), add connector nodes to your DTS and configure
pin muxes accordingly.
- Configure components that enable the use of these pins, such as - Configure components that enable the use of these pins, such as
configuring an SPI instance for Arduino SPI. configuring an SPI instance to use the usual Arduino SPI pins.
- If available, configure and enable a serial output for the console. - If available, configure and enable a serial output for the console
using the ``zephyr,console`` chosen node in the devicetree.
- Propose and configure a default network interface. - If your board supports networking, configure a default interface.
- Enable all GPIO ports. - Enable all GPIO ports connected to peripherals or expansion connectors.
- If available, enable pinmux and interrupt controller drivers. - If available, enable pinmux and interrupt controller drivers.
.. _flash-and-debug-support:
Flash and debug support Flash and debug support
*********************** ***********************
@ -237,3 +437,23 @@ first ``include`` sets the default runner if it's not already set. For example,
including ``nrfjprog.board.cmake`` first means that ``nrjfprog`` is the default including ``nrfjprog.board.cmake`` first means that ``nrjfprog`` is the default
flash runner for this board. Since ``nrfjprog`` does not support debugging, flash runner for this board. Since ``nrfjprog`` does not support debugging,
``jlink`` is the default debug runner. ``jlink`` is the default debug runner.
.. _contributing-your-board:
Contributing your board
***********************
If you want to contribute your board to Zephyr, first -- thanks!
There are some extra things you'll need to do:
#. Make sure you've followed all the :ref:`porting-general-recommendations`.
They are requirements for boards included with Zephyr.
#. Add documentation for your board using the template file
:zephyr_file:`doc/templates/board.tmpl`. See :ref:`zephyr_doc` for
information on how to build your documentation before submitting
your pull request.
#. Prepare a pull request adding your board which follows the
:ref:`contribute_guidelines`.

View file

@ -3,9 +3,7 @@
Porting Porting
####### #######
This section contains details regarding porting the Zephyr kernel to new These pages document how to port Zephyr to new hardware.
architectures, SoCs and boards. This section also describes the standard
API interfaces supported by Zephyr.
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1