doc: dts: Add more details, implementation notes, and examples
Rewrite most of the 'Input and output files' section to add more details and implementation notes, and to make some description more more concrete: - Mention dtlib, edtlib, and gen_defines.py, and explain what they do - Add an example of how macros get generated from the devicetree, and explain the DT_<node>_<property> format of the generated identifiers. Merge the 'Include files generation' section into the 'Input and output files' section at the same time. - Explain that the base devicetree and the overlays just get concatenated, and why this works - Add more details on how dts_fixup.h files work - Mention that the C dtc compiler is only run to catch errors and warnings from it - Mention that the concatenated devicetree appears in zephyr/<BOARD>.dts.pre.tmp - Mention /include/, which is the native DTS mechanism for including other files - Misc. other minor tweaks Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
This commit is contained in:
parent
fbd3d4b907
commit
9f18df0274
1 changed files with 164 additions and 72 deletions
|
@ -191,40 +191,176 @@ more detail.
|
||||||
|
|
||||||
Devicetree input (green) and output (yellow) files
|
Devicetree input (green) and output (yellow) files
|
||||||
|
|
||||||
DTS files usually have ``.dts`` or ``.dtsi`` (for Devicetree Source Include)
|
DTS files usually have a :file:`.dts`, :file:`.dtsi` (*i* for *include*), or
|
||||||
extensions. Zephyr's build system looks for a file named :file:`BOARD.dts` in
|
:file:`.overlay` extension. The C preprocessor is run on all devicetree files
|
||||||
the board definition directory; this file contains the board's base
|
to expand macro references. :file:`.dts` files usually include :file:`.dtsi`
|
||||||
devicetree. See :ref:`dt_k6x_example` for real-world examples.
|
files via the C preprocessor with ``#include``.
|
||||||
|
|
||||||
The build system combines the board's DTS with additional input files called
|
.. note::
|
||||||
*overlays* to produce a final devicetree source file. Overlays are also written
|
|
||||||
in the DTS format, but have a :file:`.overlay` extension to make it clear that
|
|
||||||
they're overlays. You can specify the overlay files to use at build time using
|
|
||||||
the :makevar:`DTC_OVERLAY_FILE` CMake variable described in
|
|
||||||
:ref:`important-build-vars`. The build system also looks for devicetree
|
|
||||||
overlays in several locations by default; see :ref:`application_dt` for the
|
|
||||||
list.
|
|
||||||
|
|
||||||
Overlays can be used to add or delete nodes from the tree, or to modify node
|
DTS also also has a native mechanism, ``/include/ "<filename>"``, for
|
||||||
properties and their values. Along with Kconfig, devicetree overlays let you
|
including other files, though it is less commonly used.
|
||||||
reconfigure the kernel and device drivers without modifying their source code.
|
|
||||||
|
|
||||||
Before they are combined, the C preprocessor is run on :file:`BOARD.dts` and any
|
Each board has a base devicetree, stored in the board's directory in
|
||||||
overlays. This allows these files to use C macros and include directives.
|
:file:`boards/` as :file:`BOARD.dts`. This base devicetree can be extended or
|
||||||
|
modified with one or more *overlays* -- DTS files with a :file:`.overlay`
|
||||||
|
extension. Overlays adapt the base devicetree for different board variants or
|
||||||
|
applications. Along with :ref:`kconfig`, this makes it possible to reconfigure
|
||||||
|
the kernel and device drivers without modifying source code.
|
||||||
|
|
||||||
The combined devicetree is written to a DTS file named
|
The build system automatically picks up :file:`.overlay` files stored in
|
||||||
:file:`BOARD.dts_compiled` in the application build directory. This file
|
certain locations. It is also possible to explicitly list the overlays to
|
||||||
contains the final devicetree.
|
include, via the :makevar:`DTC_OVERLAY_FILE` CMake variable. See
|
||||||
|
:ref:`application_dt` and :ref:`important-build-vars` for details.
|
||||||
|
|
||||||
This devicetree and the set of :ref:`bindings` are then used to generate C
|
After running the C preprocessor, the resulting :file:`BOARD.dts` and
|
||||||
definitions using scripts in :zephyr_file:`scripts/dts/`. These definitions can
|
:file:`.overlay` files are combined by concatenating them, with the overlays
|
||||||
be included via the ``generated_dts_board.h`` header file, which the build
|
put last. This relies on DTS merging multiple definitions of nodes. See
|
||||||
system places on the C preprocessor include path. This file is not generated;
|
:ref:`dt_k6x_example` for an example of how this works (in the context of
|
||||||
it is in :zephyr_file:`include/generated_dts_board.h`. (Its name was chosen
|
``.dtsi`` files, but the principle is the same for overlays). Putting the
|
||||||
for backwards compatibility.)
|
contents of the :file:`.overlay` files last allows them to override properties
|
||||||
|
from the base devicetree, if needed.
|
||||||
|
|
||||||
**Do not include the generated C headers in the build directory directly**. Use
|
.. note::
|
||||||
``generated_dts_board.h`` instead.
|
|
||||||
|
The preprocessed and concatenated DTS sources are stored in
|
||||||
|
:file:`zephyr/BOARD.dts.pre.tmp` in the build directory. Looking at this
|
||||||
|
file can be handy for debugging.
|
||||||
|
|
||||||
|
The merged devicetree, along with any :ref:`bindings <bindings>` referenced
|
||||||
|
from it, is used to generate C preprocessor macros. This is handled by the
|
||||||
|
libraries and scripts listed below, located in :zephyr_file:`scripts/dts/`.
|
||||||
|
Note that the source code has extensive comments and documentation.
|
||||||
|
|
||||||
|
:zephyr_file:`dtlib.py <scripts/dts/dtlib.py>`
|
||||||
|
A low-level DTS parsing library
|
||||||
|
|
||||||
|
:zephyr_file:`edtlib.py <scripts/dts/edtlib.py>`
|
||||||
|
A library layered on top of dtlib that uses bindings to interpret
|
||||||
|
properties and give a higher-level view of the devicetree. Uses dtlib to do
|
||||||
|
the DTS parsing.
|
||||||
|
|
||||||
|
:zephyr_file:`gen_defines.py <scripts/dts/gen_defines.py>`
|
||||||
|
A script that uses edtlib to generate C preprocessor macros from the
|
||||||
|
devicetree and bindings.
|
||||||
|
|
||||||
|
The output from :file:`gen_defines.py` is stored in
|
||||||
|
:file:`include/generated/generated_dts_board_unfixed.h` in the build directory.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
In addition to the Python code above, the standard ``dtc`` DTS compiler is
|
||||||
|
also run on the devicetree. This is just to catch any errors or warnings it
|
||||||
|
generates. The output is unused.
|
||||||
|
|
||||||
|
Most devices currently use :file:`dts_fixup.h` files that rename macros from
|
||||||
|
:file:`generated_dts_board_unfixed.h` to names that are more meaningful for the
|
||||||
|
device. By default, these fixup files are in the :file:`board/` and
|
||||||
|
:file:`soc/` directories. Any :file:`dts_fixup.h` files are concatenated and
|
||||||
|
stored as :file:`include/generated_dts_board_fixups.h` in the build directory.
|
||||||
|
|
||||||
|
Fixup files exist for historical reasons, and Zephyr might move away from using
|
||||||
|
them. When writing new code, feel free to create any macro aliases you need in
|
||||||
|
whatever way is handiest for the code.
|
||||||
|
|
||||||
|
To reference macros generated from devicetree, code should include the
|
||||||
|
:file:`generated_dts_board.h` header, which appears on the C preprocessor
|
||||||
|
include path. This file appears at :zephyr_file:`include/generated_dts_board.h`
|
||||||
|
and is not a generated file. It includes the generated
|
||||||
|
:file:`include/generated_dts_board_unfixed.h` and
|
||||||
|
:file:`include/generated_dts_board_fixups.h` files.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Do not include the generated C headers from the build directory directly.
|
||||||
|
Include ``generated_dts_board.h`` instead.
|
||||||
|
|
||||||
|
Generated macros
|
||||||
|
================
|
||||||
|
|
||||||
|
Take the DTS node below as an example.
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
sim@40047000 {
|
||||||
|
compatible = "nxp,kinetis-sim";
|
||||||
|
reg = <0x40047000 0x1060>;
|
||||||
|
label = "SIM";
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
Below is sample header content generated for this node, in
|
||||||
|
:file:`include/generated_dts_board_unfixed.h` in the build directory.
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Devicetree node:
|
||||||
|
* /soc/sim@40047000
|
||||||
|
*
|
||||||
|
* Binding (compatible = nxp,kinetis-sim):
|
||||||
|
* $ZEPHYR_BASE/dts/bindings/arm/nxp,kinetis-sim.yaml
|
||||||
|
*
|
||||||
|
* Dependency Ordinal: 24
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* 7 /soc
|
||||||
|
*
|
||||||
|
* Supports:
|
||||||
|
* 25 /soc/i2c@40066000
|
||||||
|
* 26 /soc/i2c@40067000
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Kinetis System Integration Module (SIM) IP node
|
||||||
|
*/
|
||||||
|
#define DT_NXP_KINETIS_SIM_40047000_BASE_ADDRESS 0x40047000
|
||||||
|
#define DT_INST_0_NXP_KINETIS_SIM_BASE_ADDRESS DT_NXP_KINETIS_SIM_40047000_BASE_ADDRESS
|
||||||
|
#define DT_NXP_KINETIS_SIM_40047000_SIZE 4192
|
||||||
|
#define DT_INST_0_NXP_KINETIS_SIM_SIZE DT_NXP_KINETIS_SIM_40047000_SIZE
|
||||||
|
/* Human readable string describing the device (used by Zephyr for API name) */
|
||||||
|
#define DT_NXP_KINETIS_SIM_40047000_LABEL "SIM"
|
||||||
|
#define DT_INST_0_NXP_KINETIS_SIM_LABEL DT_NXP_KINETIS_SIM_40047000_LABEL
|
||||||
|
#define DT_INST_0_NXP_KINETIS_SIM 1
|
||||||
|
|
||||||
|
Generated macro names follow the format ``DT_<node>_<property>``. For
|
||||||
|
``DT_NXP_KINETIS_SIM_40047000_BASE_ADDRESS``, the node part is
|
||||||
|
``NXP_KINETIS_SIM_40047000``, based on the compatible string that matched a
|
||||||
|
binding for the node (``nxp,kinetis-sim``) and the node's unit address
|
||||||
|
(``...@4004700``).
|
||||||
|
|
||||||
|
The ``*_BASE_ADDRESS`` part of the identifier is a fixed identifier generated
|
||||||
|
from the special ``reg`` property on the node. ``*_SIZE`` is also generated
|
||||||
|
from ``reg``. Other suffixes, like ``*_LABEL``, are generated directly from the
|
||||||
|
property name.
|
||||||
|
|
||||||
|
The second macro (``DT_INST_0_NXP_KINETIS_SIM_BASE_ADDRESS``) is an alias for
|
||||||
|
the first macro. The node identifier ``...INST_0_NXP_KINETIS_SIM_...`` means
|
||||||
|
"the first node with compatible string ``nxp,kinetis-sim``.
|
||||||
|
|
||||||
|
Aliases are also generated from any properties in the ``/aliases`` node. Take
|
||||||
|
the DTS fragment below as an example.
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
aliases {
|
||||||
|
i2c-1 = &i2c;
|
||||||
|
};
|
||||||
|
|
||||||
|
This would generate additional ``DT_ALIAS_I2C_1_...`` aliases for all
|
||||||
|
properties in the output for the node with the devicetree label ``i2c``.
|
||||||
|
|
||||||
|
Aliases that replace the property name part can also be generated, e.g. via
|
||||||
|
``*-names = "foo", "bar"`` properties. For example, ``reg-names = "control",
|
||||||
|
"mem"`` will generate ``DT_<node>_CONTROL_BASE_ADDRESS/SIZE`` and
|
||||||
|
``DT_<node>_MEM_BASE_ADDRESS_SIZE`` aliases.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The above is just a short overview of common ways macro names get generated,
|
||||||
|
and not complete. For the nitty-gritty, see the source code in
|
||||||
|
:zephyr_file:`gen_defines.py <scripts/dts/gen_defines.py>`, and check the
|
||||||
|
output generated for some existing boards and applications.
|
||||||
|
|
||||||
Zephyr device drivers typically use information from ``generated_dts_board.h``
|
Zephyr device drivers typically use information from ``generated_dts_board.h``
|
||||||
to statically allocate and initialize :ref:`struct device <device_struct>`
|
to statically allocate and initialize :ref:`struct device <device_struct>`
|
||||||
|
@ -239,12 +375,6 @@ usually take a ``struct device*`` as their first argument. This allows the
|
||||||
driver API to use information from devicetree to interact with the device
|
driver API to use information from devicetree to interact with the device
|
||||||
hardware.
|
hardware.
|
||||||
|
|
||||||
Temporary "fixup" files are currently required for devicetree support on most
|
|
||||||
devices. These fixup files by default reside in the board and soc directories
|
|
||||||
and are named ``dts_fixup.h``. These fixup files map the generated include
|
|
||||||
information to the current driver/source usage. They exist for historical
|
|
||||||
reasons; Zephyr is moving away from needing or using these files.
|
|
||||||
|
|
||||||
.. _dt_k6x_example:
|
.. _dt_k6x_example:
|
||||||
|
|
||||||
Example: FRDM-K64F and Hexiwear K64
|
Example: FRDM-K64F and Hexiwear K64
|
||||||
|
@ -704,44 +834,6 @@ This should now be written like this:
|
||||||
The legacy syntax is still supported for backwards compatibility, but generates
|
The legacy syntax is still supported for backwards compatibility, but generates
|
||||||
deprecation warnings. Support will be dropped in the Zephyr 2.3 release.
|
deprecation warnings. Support will be dropped in the Zephyr 2.3 release.
|
||||||
|
|
||||||
Include files generation
|
|
||||||
************************
|
|
||||||
|
|
||||||
At build time, after a board's ``.dts`` file has been processed by the DTC
|
|
||||||
(Devicetree Compiler), a corresponding ``.dts_compiled`` file is generated
|
|
||||||
under the ``zephyr`` directory.
|
|
||||||
This ``.dts_compiled`` file is processed by the python DTS parsing script
|
|
||||||
and generates an include file named
|
|
||||||
``include/generated/generated_dts_board_unfixed.h``
|
|
||||||
that holds all the information extracted from the DTS file with
|
|
||||||
the format specified by the YAML bindings. For example:
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
/* gpio_keys */
|
|
||||||
#define DT_GPIO_KEYS_0 1
|
|
||||||
|
|
||||||
/* button_0 */
|
|
||||||
#define DT_GPIO_KEYS_BUTTON_0_GPIOS_CONTROLLER "GPIO_2"
|
|
||||||
#define DT_GPIO_KEYS_BUTTON_0_GPIOS_FLAGS 0
|
|
||||||
#define DT_GPIO_KEYS_BUTTON_0_GPIOS_PIN 6
|
|
||||||
#define DT_GPIO_KEYS_BUTTON_0_LABEL "User SW2"
|
|
||||||
|
|
||||||
#define DT_GPIO_KEYS_SW1_GPIOS_CONTROLLER DT_GPIO_KEYS_BUTTON_0_GPIOS_CONTROLLER
|
|
||||||
#define DT_GPIO_KEYS_SW1_GPIOS_FLAGS DT_GPIO_KEYS_BUTTON_0_GPIOS_FLAGS
|
|
||||||
#define DT_GPIO_KEYS_SW1_GPIOS_PIN DT_GPIO_KEYS_BUTTON_0_GPIOS_PIN
|
|
||||||
#define DT_ALIAS_SW1_GPIOS_CONTROLLE DT_GPIO_KEYS_BUTTON_0_GPIOS_CONTROLLER
|
|
||||||
#define DT_ALIAS_SW1_GPIOS_FLAGS DT_GPIO_KEYS_BUTTON_0_GPIOS_FLAGS
|
|
||||||
#define DT_ALIAS_SW1_GPIOS_PIN DT_GPIO_KEYS_BUTTON_0_GPIOS_PIN
|
|
||||||
#define DT_ALIAS_SW1_LABEL DT_GPIO_KEYS_BUTTON_0_LABEL
|
|
||||||
|
|
||||||
|
|
||||||
Additionally, a file named ``generated_dts_board_fixups.h`` is
|
|
||||||
generated in the same directory concatenating all board-related fixup files.
|
|
||||||
|
|
||||||
The include file ``include/generated_dts_board.h`` includes both these generated
|
|
||||||
files, giving Zephyr C source files access to the board's devicetree information.
|
|
||||||
|
|
||||||
GPIO Nexus Nodes
|
GPIO Nexus Nodes
|
||||||
****************
|
****************
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue