| .. _device-tree: |
| |
| Devicetree |
| ########## |
| |
| Zephyr uses the *devicetree* data structure to describe the hardware available |
| on a board, as well as its initial configuration in an application. Note that |
| "devicetree" -- without spaces -- is preferred to "device tree". The |
| `Devicetree specification`_ fully defines this data structure and its source |
| and binary representations. |
| |
| .. _device-tree-intro: |
| |
| Introduction |
| ************ |
| |
| .. _Devicetree specification: https://www.devicetree.org/ |
| |
| This figure shows how devicetree fits into the Zephyr build system: |
| |
| .. figure:: zephyr_dt_build_flow.png |
| :figclass: align-center |
| |
| Devicetree build flow |
| |
| Zephyr's build system generates C preprocessor macros from devicetree |
| definitions. These macros can be referenced in :ref:`device drivers |
| <device_drivers>` and other C code. All macro identifiers that are directly |
| generated by the devicetree scripts start with ``DT_*``. |
| |
| Some devicetree-related identifiers also start with ``CONFIG_*``, which is the |
| identifier prefix used by :ref:`Kconfig <kconfig>`. This happens when |
| devicetree-related information is referenced from Kconfig symbol definitions, |
| via the :ref:`Kconfig preprocessor <kconfig-functions>`. |
| |
| This differs significantly from how devicetree is used on Linux. The |
| Linux kernel would instead read the entire devicetree data structure in its |
| binary form, parsing it at runtime in order to load and initialize device |
| drivers. Zephyr does not work this way because the size of the devicetree |
| binary and associated handling code would be too large to fit comfortably on |
| the relatively constrained devices Zephyr supports. |
| |
| As the name indicates, a devicetree is a tree. The human-readable text format |
| for this tree is called DTS (for devicetree source), and is defined in the |
| Devicetree Specification. Here is an example DTS file: |
| |
| .. code-block:: none |
| |
| /dts-v1/; |
| |
| / { |
| a-node { |
| subnode_label: a-sub-node { |
| foo = <3>; |
| }; |
| }; |
| }; |
| |
| This example has three nodes: |
| |
| #. A root node |
| #. A node named ``a-node``, which is a child of the root node |
| #. A node named ``a-sub-node``, which is a child of ``a-node`` |
| |
| Nodes can be given *labels*, which are unique shorthands that can be used to |
| refer to the labeled node elsewhere in the devicetree. Above, ``a-sub-node`` |
| has label ``subnode_label``. |
| |
| Devicetree nodes have *paths* identifying their locations in the tree. Like |
| Unix file system paths, devicetree paths are strings separated by slashes |
| (``/``), and the root node's path is a single slash: ``/``. Otherwise, each |
| node's path is formed by concatenating the node's ancestors' names with the |
| node's own name, separated by slashes. For example, the full path to |
| ``a-sub-node`` is ``/a-node/a-sub-node``. |
| |
| Devicetree nodes can also have *properties*. Properties are name/value |
| pairs. The values are simple byte arrays. Node ``a-sub-node`` has a property |
| named ``foo``, whose value is a 32-bit big-endian unsigned integer with value |
| 3. The size and type of ``foo``\ 's value are implied by the enclosing angle |
| brackets (``<`` and ``>``) in the DTS. Refer to the Devicetree Specification |
| for a complete list of ways to write a property value in a DTS file. |
| |
| In practice, devicetree nodes correspond to some hardware, and the node |
| hierarchy reflects the hardware's physical layout. For example, let's consider |
| a board with three I2C peripherals connected to an I2C bus master on an SoC, |
| like this: |
| |
| .. figure:: zephyr_dt_i2c_high_level.png |
| :alt: representation of a board with three I2C peripherals |
| :figclass: align-center |
| |
| Nodes corresponding to the I2C bus master and each I2C peripheral would be |
| present in this board's devicetree. Reflecting the hardware layout, the |
| devicetree's peripheral nodes would be children of the bus master node. Similar |
| conventions exist for representing other types of hardware in devicetree. |
| |
| The corresponding DTS would look something like this: |
| |
| .. code-block:: none |
| |
| / { |
| soc { |
| i2c-bus-master { |
| i2c-peripheral-1 { |
| }; |
| i2c-peripheral-2 { |
| }; |
| i2c-peripheral-3 { |
| }; |
| }; |
| }; |
| }; |
| |
| Properties are used in practice to describe or configure the hardware the node |
| represents. For example, an I2C peripheral's node has a property whose value is |
| the peripheral's address on the bus. |
| |
| Here's a tree representing the same example, but with real-world node |
| names and properties you might see when working with I2C devices. |
| |
| .. figure:: zephyr_dt_i2c_example.png |
| :figclass: align-center |
| |
| I2C devicetree example with real-world names and properties |
| |
| Above, node names -- like ``i2c@40003000`` -- are at the top of each node, with |
| a gray background, except for the root node, which is shown using its path |
| ``/``. Properties are shown as ``name=value`` pairs below the node names. |
| |
| Some important properties are: |
| |
| compatible |
| Says what kind of device the node represents. The value is a |
| string in the format "vendor,device", like ``"avago,apds9960"``, or a |
| sequence of these, like ``"ti,hdc", "ti,hdc1010"``. The build system uses |
| the compatible property to find the right :ref:`binding <bindings>` for the |
| node. |
| |
| label |
| The device's name according to Zephyr's :ref:`device_drivers`. The value |
| can be passed to :c:func:`device_get_binding()` to retrieve the |
| corresponding driver-level :ref:`struct device* <device_struct>`. This |
| pointer can then be passed to the correct driver API by application code to |
| interact with the device. For example, calling |
| ``device_get_binding("I2C_0")`` would return a pointer to a device |
| structure which could be passed to :ref:`I2C API <i2c_api>` functions like |
| :c:func:`i2c_transfer()`. The generated C header will also contain a macro |
| which expands to this string. |
| |
| reg |
| Information used to address the device. This could be a memory-mapped I/O |
| address range (as with ``i2c@40003000``\ 's reg property), an I2C bus |
| address (as with ``apds9960@39`` and its devicetree siblings), a SPI chip |
| select line, or some other value depending on the kind of device the node |
| represents. |
| |
| This tree has the following DTS. |
| |
| .. code-block:: none |
| |
| / { |
| soc { |
| i2c@40003000 { |
| compatible = "nordic,nrf-twim"; |
| label = "I2C_0"; |
| reg = <0x40003000 0x1000>; |
| |
| apds9960@39 { |
| compatible = "avago,apds9960"; |
| label = "APDS9960"; |
| reg = <0x39>; |
| }; |
| ti_hdc@43 { |
| compatible = "ti,hdc", "ti,hdc1010"; |
| label = "HDC1010; |
| reg = <0x43>; |
| }; |
| mma8652fc@1d { |
| compatible = "nxp,fxos8700", "nxp,mma8652fc"; |
| label = "MMA8652FC"; |
| reg = <0x1d>; |
| }; |
| }; |
| }; |
| }; |
| |
| Input and output files |
| ********************** |
| |
| The first figure in the :ref:`device-tree-intro` shows how devicetree fits into |
| the Zephyr build system. This section describes the input and output files in |
| more detail. |
| |
| .. figure:: zephyr_dt_inputs_outputs.png |
| :figclass: align-center |
| |
| Devicetree input (green) and output (yellow) files |
| |
| DTS files usually have a :file:`.dts`, :file:`.dtsi` (*i* for *include*), or |
| :file:`.overlay` extension. The C preprocessor is run on all devicetree files |
| to expand macro references. :file:`.dts` files usually include :file:`.dtsi` |
| files via the C preprocessor with ``#include``. |
| |
| .. note:: |
| |
| DTS also also has a native mechanism, ``/include/ "<filename>"``, for |
| including other files, though it is less commonly used. |
| |
| Each board has a base devicetree, stored in the board's directory in |
| :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 build system automatically picks up :file:`.overlay` files stored in |
| certain locations. It is also possible to explicitly list the overlays to |
| include, via the :makevar:`DTC_OVERLAY_FILE` CMake variable. See |
| :ref:`application_dt` and :ref:`important-build-vars` for details. |
| |
| After running the C preprocessor, the resulting :file:`<BOARD>.dts` and |
| :file:`.overlay` files are combined by concatenating them, with the overlays |
| put last. This relies on DTS merging multiple definitions of nodes. See |
| :ref:`dt_k6x_example` for an example of how this works (in the context of |
| ``.dtsi`` files, but the principle is the same for overlays). Putting the |
| contents of the :file:`.overlay` files last allows them to override properties |
| from the base devicetree, if needed. |
| |
| .. note:: |
| |
| 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/devicetree_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:`devicetree_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/devicetree_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:`devicetree.h` header, which appears on the C preprocessor include path. |
| This file appears at :zephyr_file:`include/devicetree.h` and is not a generated |
| file. It includes the generated :file:`include/devicetree_unfixed.h` and |
| :file:`include/devicetree_fixups.h` files. |
| |
| .. warning:: |
| |
| Do not include the generated C headers from the build directory directly. |
| Include :file:`devicetree.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/devicetree_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 :file:`devicetree.h` to |
| statically allocate and initialize :ref:`struct device <device_struct>` |
| instances. Property values from :file:`devicetree.h` are usually stored in ROM |
| in the value pointed to by a ``device->config->config_info`` field. For |
| example, a ``struct device`` corresponding to an I2C peripheral would store the |
| peripheral address in its ``reg`` property there. |
| |
| Application source code with a pointer to the ``struct device`` can then pass |
| it to driver APIs in :zephyr_file:`include/drivers/`. These API functions |
| usually take a ``struct device*`` as their first argument. This allows the |
| driver API to use information from devicetree to interact with the device |
| hardware. |
| |
| .. _dt_k6x_example: |
| |
| Example: FRDM-K64F and Hexiwear K64 |
| =================================== |
| |
| .. Give the filenames instead of the full paths below, as it's easier to read. |
| The cramped 'foo.dts<path>' style avoids extra spaces before commas. |
| |
| The FRDM-K64F and Hexiwear K64 board devicetrees are defined in |
| :zephyr_file:`frdm_k64fs.dts <boards/arm/frdm_k64f/frdm_k64f.dts>` and |
| :zephyr_file:`hexiwear_k64.dts <boards/arm/hexiwear_k64/hexiwear_k64.dts>` |
| respectively. Both boards have NXP SoCs from the same Kinetis SoC family, the |
| K6X. |
| |
| Common devicetree definitions for K6X are stored in :zephyr_file:`nxp_k6x.dtsi |
| <dts/arm/nxp/nxp_k6x.dtsi>`, which is included by both board :file:`.dts` |
| files. :zephyr_file:`nxp_k6x.dtsi<dts/arm/nxp/nxp_k6x.dtsi>` in turn includes |
| :zephyr_file:`armv7-m.dtsi<dts/arm/armv7-m.dtsi>`, which has common definitions |
| for Arm v7-M cores. |
| |
| Since :zephyr_file:`nxp_k6x.dtsi<dts/arm/nxp/nxp_k6x.dtsi>` is meant to be |
| generic across K6X-based boards, it leaves many devices disabled by default |
| using ``status`` properties. For example, there is a CAN controller defined as |
| follows (with unimportant parts skipped): |
| |
| .. code-block:: none |
| |
| can0: can@40024000 { |
| ... |
| status = "disabled"; |
| ... |
| }; |
| |
| It is up to the board :file:`.dts` or application overlay files to enable these |
| devices as desired, by setting ``status = "okay"``. The board :file:`.dts` |
| files are also responsible for any board-specific configuration of the device, |
| such as adding nodes for on-board sensors, LEDs, buttons, etc. |
| |
| For example, FRDM-K64 (but not Hexiwear K64) :file:`.dts` enables the CAN |
| controller and sets the bus speed: |
| |
| .. code-block:: none |
| |
| &can0 { |
| status = "okay"; |
| bus-speed = <125000>; |
| }; |
| |
| The ``&can0 { ... };`` syntax adds/overrides properties on the node with label |
| ``can0``, i.e. the ``can@4002400`` node defined in the :file:`.dtsi` file. |
| |
| 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. |
| |
| .. _dt_vs_kconfig: |
| |
| Devicetree vs Kconfig |
| ********************* |
| |
| Along with devicetree, Zephyr also uses the Kconfig language to configure the |
| source code. Whether to use devicetree or Kconfig for a particular purpose can |
| sometimes be confusing. This section should help you decide which one to use. |
| |
| In short: |
| |
| * Use devicetree to describe **hardware** and its **boot-time configuration**. |
| Examples include peripherals on a board, boot-time clock frequencies, |
| interrupt lines, etc. |
| * Use Kconfig to configure **software support** to build into the final |
| image. Examples include whether to add networking support, which drivers are |
| needed by the application, etc. |
| |
| In other words, devicetree mainly deals with hardware, and Kconfig with |
| software. |
| |
| For example, consider a board containing a SoC with 2 UART, or serial port, |
| instances. |
| |
| * The fact that the board has this UART **hardware** is described with two UART |
| nodes in the devicetree. These provide the UART type (via the ``compatible`` |
| property) and certain settings such as the address range of the hardware |
| peripheral registers in memory (via the ``reg`` property). |
| * Additionally, the UART **boot-time configuration** is also described with |
| devicetree. This could include configuration such as the RX IRQ line's |
| priority and the UART baud rate. These may be modifiable at runtime, but |
| their boot-time configuration is described in devicetree. |
| * Whether or not to include **software support** for UART in the build is |
| controlled via Kconfig. Applications which do not need to use the UARTs can |
| remove the driver source code from the build using Kconfig, even though the |
| board's devicetree still includes UART nodes. |
| |
| As another example, consider a device with a 2.4GHz, multi-protocol radio |
| supporting both the Bluetooth Low Energy and 802.15.4 wireless technologies. |
| |
| * Devicetree should be used to describe the presence of the radio **hardware**, |
| what driver or drivers it's compatible with, etc. |
| * **Boot-time configuration** for the radio, such as TX power in dBm, should |
| also be specified using devicetree. |
| * Kconfig should determine which **software features** should be built for the |
| radio, such as selecting a BLE or 802.15.4 protocol stack. |
| |
| There are two noteworthy **exceptions** to these rules: |
| |
| * Devicetree's ``chosen`` keyword, which allows the user to select a specific |
| instance of a hardware device to be used for a particular purpose. An example |
| of this is selecting a particular UART for use as the system's console. |
| * Devicetree's ``status`` keyword, which allows the user to enable or disable a |
| particular instance of a hardware device. This takes precedence over related |
| Kconfig options which serve a similar purpose. |
| |
| Currently supported boards |
| ************************** |
| |
| Devicetree is currently supported on all embedded targets except posix |
| (boards/posix). |
| |
| Adding support for a board |
| ************************** |
| |
| Adding devicetree support for a given board requires adding a number of files. |
| These files will contain the DTS information that describes a platform, the |
| bindings in YAML format, and any fixup files required to support the platform. |
| |
| It is best practice to separate common peripheral information that could be |
| used across multiple cores, SoC families, or boards in :file:`.dtsi` files, |
| reserving the :file:`.dts` suffix for the primary DTS file for a given board. |
| |
| Devicetree Source File Template |
| =============================== |
| |
| A board's :file:`.dts` file contains at least a version line, optional |
| includes, and a root node definition with ``model`` and ``compatible`` |
| properties. These property values denote the particular board. |
| |
| .. code-block:: none |
| |
| /dts-v1/; |
| |
| #include <vendor/soc.dtsi> |
| |
| / { |
| model = "Human readable board name"; |
| compatible = "vendor,soc-on-your-board's-mcu"; |
| /* rest of file */ |
| }; |
| |
| You can use other board :file:`.dts` files as a starting point. |
| |
| The following is a more precise list of required files: |
| |
| * Base architecture support |
| |
| * Add architecture-specific DTS directory, if not already present. |
| Example: dts/arm for Arm. |
| * Add target specific devicetree files for base SoC. These should be |
| .dtsi files to be included in the board-specific devicetree files. |
| * Add target specific YAML binding files in the dts/bindings/ directory. |
| Create the yaml directory if not present. |
| |
| * SoC family support |
| |
| * Add one or more SoC family .dtsi files that describe the hardware |
| for a set of devices. The file should contain all the relevant |
| nodes and base configuration that would be applicable to all boards |
| utilizing that SoC family. |
| * Add SoC family YAML binding files that describe the nodes present in the .dtsi file. |
| |
| * Board specific support |
| |
| * Add a board level .dts file that includes the SoC family .dtsi files |
| and enables the nodes required for that specific board. |
| * Board .dts file should specify the SRAM and FLASH devices, if present. |
| |
| * Flash device node might specify flash partitions. For more details see |
| :ref:`flash_partitions` |
| |
| * Add board-specific YAML binding files, if required. This would occur if the |
| board has additional hardware that is not covered by the SoC family |
| .dtsi/.yaml files. |
| |
| * Fixup files |
| |
| * Fixup files contain mappings from existing Kconfig options to the actual |
| underlying DTS derived configuration #defines. Fixup files are temporary |
| artifacts until additional DTS changes are made to make them unnecessary. |
| |
| * Overlay Files (optional) |
| |
| * Overlay files contain tweaks or changes to the SoC and Board support files |
| described above. They can be used to modify devicetree configurations |
| without having to change the SoC and Board files. See |
| :ref:`application_dt` for more information on overlay files and the Zephyr |
| build system. |
| |
| .. _dt-alias-chosen: |
| |
| ``aliases`` and ``chosen`` nodes |
| ================================ |
| |
| Using an alias with a common name for a particular node makes it easier for you |
| to write board-independent source code. Devicetree ``aliases`` nodes are used |
| for this purpose, by mapping certain generic, commonly used names to specific |
| hardware resources: |
| |
| .. code-block:: yaml |
| |
| aliases { |
| led0 = &led0; |
| sw0 = &button0; |
| sw1 = &button1; |
| uart-0 = &uart0; |
| uart-1 = &uart1; |
| }; |
| |
| Certain software subsystems require a specific hardware resource to bind to in |
| order to function properly. Some of those subsystems are used with many |
| different boards, which makes using the devicetree ``chosen`` nodes very |
| convenient. By doing, so the software subsystem can rely on having the specific |
| hardware peripheral assigned to it. In the following example we bind the shell |
| to ``uart1`` in this board: |
| |
| .. code-block:: yaml |
| |
| chosen { |
| zephyr,shell-uart = &uart1; |
| }; |
| |
| The table below lists Zephyr-specific ``chosen`` properties. The macro |
| identifiers that start with ``CONFIG_*`` are generated from Kconfig symbols |
| that reference devicetree data via the :ref:`Kconfig preprocessor |
| <kconfig-functions>`. |
| |
| .. note:: |
| |
| Since the particular devicetree isn't known while generating Kconfig |
| documentation, the Kconfig symbol reference pages linked below do not |
| include information derived from devicetree. Instead, you might see e.g. an |
| empty default: |
| |
| .. code-block:: none |
| |
| default "" if HAS_DTS |
| |
| To see how the preprocessor is used for a symbol, look it up directly in the |
| :file:`Kconfig` file where it is defined instead. The reference page for the |
| symbol gives the definition location. |
| |
| .. list-table:: |
| :header-rows: 1 |
| |
| * - ``chosen`` node name |
| - Generated macros |
| |
| * - ``zephyr,flash`` |
| - ``DT_FLASH_BASE_ADDRESS``/``DT_FLASH_SIZE``/``DT_FLASH_ERASE_BLOCK_SIZE``/``DT_FLASH_WRITE_BLOCK_SIZE`` |
| * - ``zephyr,code-partition`` |
| - ``DT_CODE_PARTITION_OFFSET``/``DT_CODE_PARTITION_SIZE`` |
| * - ``zephyr,sram`` |
| - :option:`CONFIG_SRAM_BASE_ADDRESS`/:option:`CONFIG_SRAM_SIZE` |
| * - ``zephyr,ccm`` |
| - ``DT_CCM_BASE_ADDRESS``/``DT_CCM_SIZE`` |
| * - ``zephyr,dtcm`` |
| - ``DT_DTCM_BASE_ADDRESS``/``DT_DTCM_SIZE`` |
| * - ``zephyr,ipc_shm`` |
| - ``DT_IPC_SHM_BASE_ADDRESS``/``DT_IPC_SHM_SIZE`` |
| * - ``zephyr,console`` |
| - :option:`CONFIG_UART_CONSOLE_ON_DEV_NAME` |
| * - ``zephyr,shell-uart`` |
| - :option:`CONFIG_UART_SHELL_ON_DEV_NAME` |
| * - ``zephyr,bt-uart`` |
| - :option:`CONFIG_BT_UART_ON_DEV_NAME` |
| * - ``zephyr,uart-pipe`` |
| - :option:`CONFIG_UART_PIPE_ON_DEV_NAME` |
| * - ``zephyr,bt-mon-uart`` |
| - :option:`CONFIG_BT_MONITOR_ON_DEV_NAME` |
| * - ``zephyr,bt-c2h-uart`` |
| - :option:`CONFIG_BT_CTLR_TO_HOST_UART_DEV_NAME` |
| * - ``zephyr,uart-mcumgr`` |
| - :option:`CONFIG_UART_MCUMGR_ON_DEV_NAME` |
| |
| |
| Adding support for devicetree in drivers |
| **************************************** |
| |
| As drivers and other source code is converted over to make use of devicetree |
| generated information, these drivers may require changes to match the generated |
| #define information. |
| |
| |
| Source Tree Hierarchy |
| ********************* |
| |
| The devicetree files are located in a couple of different directories. The |
| directory split is done based on architecture, and there is also a common |
| directory where architecture agnostic devicetree and YAML binding files are |
| located. |
| |
| Assuming the current working directory is the ZEPHYR_BASE, the directory |
| hierarchy looks like the following:: |
| |
| dts/common/ |
| dts/<ARCH>/ |
| dts/bindings/ |
| boards/<ARCH>/<BOARD>/ |
| |
| The common directory contains a ``skeleton.dtsi`` which provides devicetree root |
| node definition. The bindings subdirectory contains YAML binding files used |
| to instruct how the python DTS parsing script should extract nodes information |
| in a format that will be usable by the system. |
| |
| Example: Subset of DTS/YAML files for NXP FRDM K64F (Subject to Change):: |
| |
| dts/arm/armv7-m.dtsi |
| dts/arm/k6x/nxp_k6x.dtsi |
| boards/arm/frdm_k64f/frdm_k64f.dts |
| dts/bindings/interrupt-controller/arm,v7m-nvic.yaml |
| dts/bindings/gpio/nxp,kinetis-gpio.yaml |
| dts/bindings/pinctrl/nxp,kinetis-pinmux.yaml |
| dts/bindings/serial/nxp,kinetis-uart.yaml |
| |
| .. _bindings: |
| |
| Devicetree Bindings |
| ******************* |
| |
| ``.dts`` files describe the available hardware devices, but don't tell the |
| system which pieces of information are useful, or what kind of configuration |
| output (``#define``'s) should be generated. *Bindings* provide this |
| information. Bindings are files in YAML format. |
| |
| Configuration output is only generated for devices that have bindings. |
| |
| Nodes are mapped to bindings via their ``compatible`` string(s). Take |
| the following node as an example: |
| |
| .. code-block:: none |
| |
| bar-device { |
| compatible = "foo-company,bar-device"; |
| ... |
| }; |
| |
| This node would get mapped to a binding with this in it: |
| |
| .. code-block:: yaml |
| |
| compatible: "foo-company,bar-device" |
| |
| You might also run across this legacy syntax, which works the same way: |
| |
| .. code-block:: yaml |
| |
| ... |
| |
| properties: |
| compatible: |
| constraint: "foo-company,bar-device" |
| |
| ... |
| |
| Bindings are stored in :zephyr_file:`dts/bindings/`. The filename usually |
| matches the ``compatible`` string. |
| |
| If a node has more than one ``compatible`` string, then the first binding found |
| is used, going from the first string to the last. For example, a node with |
| ``compatible = "foo-company,bar-device", "generic-bar-device"`` would get |
| mapped to the binding for ``generic-bar-device`` if there is no binding for |
| ``foo-company,bar-device``. |
| |
| If a node appears on a bus (e.g. I2C or SPI), then the bus type is also taken |
| into account when mapping nodes to bindings. See the description of ``parent`` |
| and ``child`` in the template below. |
| |
| Below is a template that shows the format of binding files, stored in |
| :zephyr_file:`dts/binding-template.yaml`. |
| |
| .. literalinclude:: ../../../dts/binding-template.yaml |
| :language: yaml |
| |
| .. _legacy_binding_syntax: |
| |
| Legacy binding syntax |
| ===================== |
| |
| Various parts of the binding syntax were simplified and generalized for the |
| Zephyr 2.1 release. |
| |
| The binding below shows various legacy syntax. |
| |
| .. code-block:: yaml |
| |
| title: ... |
| description: ... |
| |
| inherits: |
| !include foo.yaml |
| |
| parent: |
| bus: spi |
| |
| parent-bus: spi |
| |
| properties: |
| compatible: |
| constraint: "company,device" |
| type: string-array |
| |
| frequency: |
| type: int |
| category: optional |
| |
| sub-node: |
| properties: |
| child-prop: |
| type: int |
| category: required |
| |
| # Assume this is a binding for an interrupt controller |
| "#cells": |
| - irq |
| - priority |
| - flags |
| |
| This should now be written like this: |
| |
| .. code-block:: yaml |
| |
| description: ... |
| |
| compatible: "company,device" |
| |
| include: foo.yaml |
| |
| bus: spi |
| |
| properties: |
| frequency: |
| type: int |
| required: false |
| |
| child-binding: |
| description: ... |
| |
| properties: |
| child-prop: |
| type: int |
| required: true |
| |
| interrupt-cells: |
| - irq |
| - priority |
| - cells |
| |
| The legacy syntax is still supported for backwards compatibility, but generates |
| deprecation warnings. Support will be dropped in the Zephyr 2.3 release. |
| |
| GPIO Nexus Nodes |
| **************** |
| |
| Each board has a set of General Purpose Input/Output (GPIO) |
| peripherals that can be accessed through the :ref:`GPIO<gpio>` module. |
| Many boards provide headers that allow :ref:`shields<shields>` from |
| other vendors to be mounted on their boards. Each shield identifies |
| its hardware in a devicetree overlay. |
| |
| GPIOs accessed by the shield peripherals must be identified using the |
| shield GPIO abstraction, for example from the ``arduino-r3-header`` |
| compatible. Boards that provide the header must map the header pins |
| to SOC-specific pins. This is accomplished by including a `nexus |
| node`_ that looks like the following into the board devicetree file: |
| |
| .. _nexus node: |
| https://github.com/devicetree-org/devicetree-specification/blob/4b1dac80eaca45b4babf5299452a951008a5d864/source/devicetree-basics.rst#nexus-nodes-and-specifier-mapping |
| |
| .. code-block:: none |
| |
| arduino_header: connector { |
| compatible = "arduino-header-r3"; |
| #gpio-cells = <2>; |
| gpio-map-mask = <0xffffffff 0xffffffc0>; |
| gpio-map-pass-thru = <0 0x3f>; |
| gpio-map = <0 0 &gpioa 0 0>, /* A0 */ |
| <1 0 &gpioa 1 0>, /* A1 */ |
| <2 0 &gpioa 4 0>, /* A2 */ |
| <3 0 &gpiob 0 0>, /* A3 */ |
| <4 0 &gpioc 1 0>, /* A4 */ |
| <5 0 &gpioc 0 0>, /* A5 */ |
| <6 0 &gpioa 3 0>, /* D0 */ |
| <7 0 &gpioa 2 0>, /* D1 */ |
| <8 0 &gpioa 10 0>, /* D2 */ |
| <9 0 &gpiob 3 0>, /* D3 */ |
| <10 0 &gpiob 5 0>, /* D4 */ |
| <11 0 &gpiob 4 0>, /* D5 */ |
| <12 0 &gpiob 10 0>, /* D6 */ |
| <13 0 &gpioa 8 0>, /* D7 */ |
| <14 0 &gpioa 9 0>, /* D8 */ |
| <15 0 &gpioc 7 0>, /* D9 */ |
| <16 0 &gpiob 6 0>, /* D10 */ |
| <17 0 &gpioa 7 0>, /* D11 */ |
| <18 0 &gpioa 6 0>, /* D12 */ |
| <19 0 &gpioa 5 0>, /* D13 */ |
| <20 0 &gpiob 9 0>, /* D14 */ |
| <21 0 &gpiob 8 0>; /* D15 */ |
| }; |
| |
| This specifies how Arduino pin references like ``<&arduino_header 11 |
| 0>`` are converted to SOC gpio pin references like ``<&gpiob 4 0>``. |
| |
| In Zephyr GPIO specifiers generally have two parameters (indicated by |
| ``#gpio-cells = <2>``): the pin number and a set of flags. The low 6 |
| bits of the flags correspond to features that can be configured in |
| devicetree. In some cases it's necessary to use a non-zero flag value |
| to tell the driver how a particular pin behaves, as with: |
| |
| .. code-block:: none |
| |
| drdy-gpios = <&arduino_header 11 GPIO_ACTIVE_LOW>; |
| |
| After preprocessing this becomes ``<&arduino_header 11 1>``. Normally |
| the presence of such a flag would cause the map lookup to fail, |
| because there is no map entry with a non-zero flags value. The |
| ``gpio-map-mask`` property specifies that, for lookup, all bits of the |
| pin and all but the low 6 bits of the flags are used to identify the |
| specifier. Then the ``gpio-map-pass-thru`` specifies that the low 6 |
| bits of the flags are copied over, so the SOC GPIO reference becomes |
| ``<&gpiob 4 1>`` as intended. |
| |
| See `nexus node`_ for more information about this capability. |
| |
| .. include:: flash_partitions.inc |