| .. _dt-from-c: |
| |
| Devicetree access from C/C++ |
| ############################ |
| |
| This guide describes Zephyr's ``<devicetree.h>`` API for reading the devicetree |
| from C source files. It assumes you're familiar with the concepts in |
| :ref:`devicetree-intro` and :ref:`dt-bindings`. See :ref:`devicetree_api` for |
| API reference documentation. |
| |
| .. _dt-node-identifiers: |
| |
| Node identifiers |
| **************** |
| |
| To get information about a particular devicetree node, you need a *node |
| identifier* for it. This is a just a C macro that refers to the node. |
| There are four types, each of which is created with a different macro: |
| |
| Path identifiers |
| These use the node's full path in the devicetree, starting from the |
| root node. They are mostly useful if you happen to know the exact node |
| you're looking for. Create these with :c:func:`DT_PATH()`. |
| |
| Node label identifiers |
| Unique names which can be given to each node where it is |
| defined. These are often used when the SoC :file:`.dtsi` gives nodes |
| names that match the SoC datasheet, like ``i2c_1``, ``spi_2``, etc. |
| Create these with :c:func:`DT_NODELABEL()`. |
| |
| Alias identifiers |
| These are created for properties of the special ``/aliases`` node. They are |
| useful for supporting applications (like :ref:`blinky <blinky-sample>`, |
| which uses the ``led0`` alias) that need to refer to *some* device of a |
| particular type ("the board's user LED") but don't care which exact one is |
| used. Create these with :c:func:`DT_ALIAS()`. |
| |
| Instance identifiers |
| These are used primarily by device drivers, as they're a way to refer to |
| nodes based on their matching compatible. Create these with |
| :c:func:`DT_INST()`, but be careful doing so. |
| |
| .. _dt-node-main-ex: |
| |
| Here's a DTS fragment for some imaginary hardware we'll return to throughout |
| this file for examples: |
| |
| .. literalinclude:: main-example.dts |
| :language: DTS |
| :start-after: start-after-here |
| |
| Here are node identifiers of each type for the ``i2c@40002000`` node: |
| |
| - ``DT_PATH(soc, i2c_40002000)`` |
| - ``DT_NODELABEL(i2c1)`` |
| - ``DT_ALIAS(sensor_controller)`` |
| - ``DT_INST(x, vnd_soc_i2c)`` for some unknown number ``x``. See the |
| :c:func:`DT_INST()` documentation for details. |
| |
| These identifiers are precisely equivalent: they refer to the same node, and |
| are otherwise interchangeable in the following examples. |
| |
| .. important:: |
| |
| Non-alphanumeric characters like dash (``-``) and the at sign (``@``) in |
| devicetree names are converted to underscores (``_``). The names in a DTS |
| are also converted to lowercase. |
| |
| .. _node-ids-are-not-values: |
| |
| Node identifiers are not values |
| ******************************* |
| |
| There is no way to store one in a variable. You cannot write: |
| |
| .. code-block:: c |
| |
| /* These will give you compiler errors: */ |
| |
| void *i2c_0 = DT_INST(0, vnd_soc_i2c); |
| unsigned int i2c_1 = DT_INST(1, vnd_soc_i2c); |
| long my_i2c = DT_NODELABEL(i2c1); |
| |
| If you want something short to save typing, use C macros: |
| |
| .. code-block:: c |
| |
| /* Use something like this instead: */ |
| |
| #define MY_I2C DT_NODELABEL(i2c1) |
| |
| #define INST(i) DT_INST(i, vnd_soc_i2c) |
| #define I2C_0 INST(0) |
| #define I2C_1 INST(1) |
| |
| .. _not-all-dt-nodes: |
| |
| Not all nodes are usable |
| ************************ |
| |
| Just because :ref:`zephyr.dts <dt-outputs>` has a node doesn't mean you can use |
| it from a C or C++ source file. The node has to have a matching binding, and |
| its ``status`` property must be ``"okay"`` (instead of, say, ``"disabled"``). |
| Use :c:func:`DT_HAS_NODE` to check if a node identifier is valid for use. The |
| value is 1 if yes, and 0 if no. |
| |
| Here are some examples from the :ref:`above devicetree <dt-node-main-ex>`: |
| |
| .. code-block:: c |
| |
| DT_HAS_NODE(DT_PATH(soc, i2c_40002000)) /* 1: node has binding and is enabled */ |
| DT_HAS_NODE(DT_ALIAS(sensor_controller)) /* 1: that's an alias for the same node */ |
| DT_HAS_NODE(DT_NODELABEL(i2c1)) /* 1: that's also the same node */ |
| |
| DT_HAS_NODE(DT_PATH(i2c_40002000)) /* 0: there's no such node */ |
| DT_HAS_NODE(DT_PATH(soc)) /* 0: the /soc node has no binding */ |
| |
| Property access |
| *************** |
| |
| The right API to use to read property values depends on the node and property. |
| |
| - :ref:`dt-checking-property-exists` |
| - :ref:`simple-properties` |
| - :ref:`reg-properties` |
| - :ref:`interrupts-properties` |
| - :ref:`phandle-properties` |
| |
| .. _dt-checking-property-exists: |
| |
| Checking properties and values |
| ============================== |
| |
| You can use :c:func:`DT_NODE_HAS_PROP()` to check if a node has a property. For |
| the :ref:`example devicetree <dt-node-main-ex>` above: |
| |
| .. code-block:: c |
| |
| DT_NODE_HAS_PROP(DT_NODELABEL(i2c1), clock_frequency) /* expands to 1 */ |
| DT_NODE_HAS_PROP(DT_NODELABEL(i2c1), not_a_property) /* expands to 0 */ |
| |
| .. _simple-properties: |
| |
| Simple properties |
| ================= |
| |
| Use ``DT_PROP(node_id, property)`` to read basic integer, boolean, string, |
| numeric array, and string array properties. |
| |
| For example, to read the ``clock-frequency`` property's value in the |
| :ref:`above example <dt-node-main-ex>`: |
| |
| .. code-block:: c |
| |
| DT_PROP(DT_PATH(soc, i2c_40002000), clock_frequency) /* This is 100000, */ |
| DT_PROP(DT_NODELABEL(i2c1), clock_frequency) /* and so is this, */ |
| DT_PROP(DT_ALIAS(sensor_controller), clock_frequency) /* and this. */ |
| |
| .. important:: |
| |
| The DTS property ``clock-frequency`` is spelled ``clock_frequency`` in C. |
| That is, properties also need special characters converted to underscores. |
| Their names are also forced to lowercase. |
| |
| Properties with ``string`` and ``boolean`` types work the exact same way. The |
| ``DT_PROP()`` macro expands to a string literal in the case of strings, and the |
| number 0 or 1 in the case of booleans. For example: |
| |
| .. code-block:: c |
| |
| #define I2C1 DT_NODELABEL(i2c1) |
| |
| DT_PROP(I2C1, status) /* expands to the string literal "okay" */ |
| |
| Properties with type ``array``, ``uint8-array``, and ``string-array`` work |
| similarly, except ``DT_PROP()`` expands to an array initializer in these cases. |
| Here is an example devicetree fragment: |
| |
| .. code-block:: DTS |
| |
| foo: foo@1234 { |
| a = <1000 2000 3000>; /* array */ |
| b = [aa bb cc dd]; /* uint8-array */ |
| c = "bar", "baz"; /* string-array */ |
| }; |
| |
| Its properties can be accessed like this: |
| |
| .. code-block:: c |
| |
| #define FOO DT_NODELABEL(foo) |
| |
| int a[] = DT_PROP(FOO, a); /* {1000, 2000, 3000} */ |
| unsigned char b[] = DT_PROP(FOO, b); /* {0xaa, 0xbb, 0xcc, 0xdd} */ |
| char* c[] = DT_PROP(FOO, c); /* {"foo", "bar"} */ |
| |
| You can use :c:func:`DT_PROP_LEN()` to get logical array lengths in number of |
| elements. |
| |
| .. code-block:: c |
| |
| size_t a_len = DT_PROP_LEN(FOO, a); /* 3 */ |
| size_t b_len = DT_PROP_LEN(FOO, b); /* 4 */ |
| size_t c_len = DT_PROP_LEN(FOO, c); /* 2 */ |
| |
| ``DT_PROP_LEN()`` cannot be used with the special ``reg`` or ``interrupts`` |
| properties. These have alternative macros which are described next. |
| |
| .. _reg-properties: |
| |
| reg properties |
| ============== |
| |
| See :ref:`dt-important-props` for an introduction to ``reg``. |
| |
| Given a node identifier ``node_id``, ``DT_NUM_REGS(node_id)`` is the |
| total number of register blocks in the node's ``reg`` property. |
| |
| You **cannot** read register block addresses and lengths with ``DT_PROP(node, |
| reg)``. Instead, if a node only has one register block, use |
| :c:func:`DT_REG_ADDR` or :c:func:`DT_REG_SIZE`: |
| |
| - ``DT_REG_ADDR(node_id)``: the given node's register block address |
| - ``DT_REG_SIZE(node_id)``: its size |
| |
| Use :c:func:`DT_REG_ADDR_BY_IDX` or :c:func:`DT_REG_SIZE_BY_IDX` instead if the |
| node has multiple register blocks: |
| |
| - ``DT_REG_ADDR_BY_IDX(node_id, idx)``: address of register block at index |
| ``idx`` |
| - ``DT_REG_SIZE_BY_IDX(node_id, idx)``: size of block at index ``idx`` |
| |
| The ``idx`` argument to these must be an integer literal or a macro that |
| expands to one without requiring any arithmetic. In particular, ``idx`` cannot |
| be a variable. This won't work: |
| |
| .. code-block:: c |
| |
| /* This will cause a compiler error. */ |
| |
| for (size_t i = 0; i < DT_NUM_REGS(node_id); i++) { |
| size_t addr = DT_REG_ADDR_BY_IDX(node_id, i); |
| } |
| |
| .. _interrupts-properties: |
| |
| interrupts properties |
| ===================== |
| |
| See :ref:`dt-important-props` for a brief introduction to ``interrupts``. |
| |
| Given a node identifier ``node_id``, ``DT_NUM_IRQS(node_id)`` is the total |
| number of interrupt specifiers in the node's ``interrupts`` property. |
| |
| The most general purpose API macro for accessing these is |
| :c:func:`DT_IRQ_BY_IDX`: |
| |
| .. code-block:: c |
| |
| DT_IRQ_BY_IDX(node_id, idx, val) |
| |
| Here, ``idx`` is the logical index into the ``interrupts`` array, i.e. it is |
| the index of an individual interrupt specifier in the property. The ``val`` |
| argument is the name of a cell within the interrupt specifier. To use this |
| macro, check the bindings file for the node you are interested in to find the |
| ``val`` names. |
| |
| Most Zephyr devicetree bindings have a cell named ``irq``, which is the |
| interrupt number. You can use :c:func:`DT_IRQN` as a convenient way to get a |
| processed view of this value. |
| |
| .. warning:: |
| |
| Here, "processed" reflects Zephyr's devicetree :ref:`dt-scripts`, which |
| change the ``irq`` number in :ref:`zephyr.dts <devicetree-in-out-files>` to |
| handle hardware constraints on some SoCs and in accordance with Zephyr's |
| multilevel interrupt numbering. |
| |
| This is currently not very well documented, and you'll need to read the |
| scripts source code and existing drivers for more details if you are writing |
| a device driver. |
| |
| .. _phandle-properties: |
| |
| phandle properties |
| ================== |
| |
| Property values can refer to other nodes using the ``&another-node`` phandle |
| syntax introduced in :ref:`dt-writing-property-values`. Properties which |
| contain phandles have type ``phandle``, ``phandles``, or ``phandle-array`` in |
| their bindings. We'll call these "phandle properties" for short. |
| |
| You can convert a phandle to a node identifier using :c:func:`DT_PHANDLE`, |
| :c:func:`DT_PHANDLE_BY_IDX`, or :c:func:`DT_PHANDLE_BY_NAME`, depending on the |
| type of property you are working with. |
| |
| One common use case for phandle properties is referring to other hardware in |
| the tree. In this case, you usually want to convert the devicetree-level |
| phandle to a Zephyr driver-level :ref:`struct device <device_model_api>`. |
| See :ref:`dt-get-device` for ways to do that. |
| |
| Another common use case is accessing specifier values in a phandle array. The |
| general purpose APIs for this are :c:func:`DT_PHA_BY_IDX` and :c:func:`DT_PHA`. |
| There are also hardware-specific shorthands like :c:func:`DT_GPIO_LABEL_BY_IDX`, |
| :c:func:`DT_GPIO_LABEL`, :c:func:`DT_GPIO_PIN_BY_IDX`, :c:func:`DT_GPIO_PIN`, |
| :c:func:`DT_GPIO_FLAGS_BY_IDX`, and :c:func:`DT_GPIO_FLAGS`. |
| |
| See :c:func:`DT_PHA_HAS_CELL_AT_IDX` and :c:func:`DT_PROP_HAS_IDX` for ways to |
| check if a specifier value is present. |
| |
| .. _other-devicetree-apis: |
| |
| Other APIs |
| ********** |
| |
| Here are pointers to some other available APIs. |
| |
| - :c:func:`DT_CHOSEN`, :c:func:`DT_HAS_CHOSEN`: for properties |
| of the special ``/chosen`` node |
| - :c:func:`DT_HAS_COMPAT`: test if a compatible has a binding and at least one |
| enabled node |
| - :c:func:`DT_BUS`: get a node's bus controller, if there is one |
| - :c:func:`DT_ENUM_IDX`: for properties whose values are among a fixed list of |
| choices |
| |
| Flash partitions |
| **************** |
| |
| These currently must be managed via the legacy API. See |
| :ref:`legacy_flash_partitions`. |
| |
| Device driver conveniences |
| ************************** |
| |
| Special purpose macros are available for writing device drivers, which usually |
| rely on :ref:`instance identifiers <dt-node-identifiers>`. |
| |
| To use these, you must define ``DT_DRV_COMPAT`` to the ``compat`` value your |
| driver implements support for. This ``compat`` value is what you would pass to |
| :c:func:`DT_INST`. |
| |
| If you do that, you can access the properties of individual instances of your |
| compatible with less typing, like this: |
| |
| .. code-block:: c |
| |
| #include <devicetree.h> |
| |
| #define DT_DRV_COMPAT my_driver_compat |
| |
| /* This is same thing as DT_INST(0, my_driver_compat): */ |
| DT_DRV_INST(0) |
| |
| /* |
| * This is the same thing as |
| * DT_PROP(DT_INST(0, my_driver_compat), clock_frequency) |
| */ |
| DT_INST_PROP(0, clock_frequency) |
| |
| See :ref:`devicetree-inst-apis` for a generic API reference. |
| |
| Hardware specific APIs |
| ********************** |
| |
| Convenience macros built on top of the above APIs are also defined to help |
| readability for hardware specific code. See :ref:`devicetree-hw-api` for |
| details. |
| |
| Generated macros |
| **************** |
| |
| While the :file:`devicetree.h` API is not generated, it does rely on a |
| generated C header which is put into every application build directory: |
| :ref:`devicetree_unfixed.h <dt-outputs>`. This file contains macros with |
| devicetree data. |
| |
| These macros have tricky naming conventions which the `devicetree_api` API |
| abstracts away. They should be considered an implementation detail, but it's |
| useful to understand them since they will frequently be seen in compiler error |
| messages. |
| |
| This section contains an Augmented Backus-Naur Form grammar for these |
| generated macros, with examples and more details in comments. See `RFC 7405`_ |
| (which extends `RFC 5234`_) for a syntax specification. |
| |
| .. literalinclude:: macros.bnf |
| :language: abnf |
| |
| .. _RFC 7405: https://tools.ietf.org/html/rfc7405 |
| .. _RFC 5234: https://tools.ietf.org/html/rfc5234 |