1.. _dt-howtos: 2 3Devicetree HOWTOs 4################# 5 6This page has step-by-step advice for getting things done with devicetree. 7 8.. tip:: See :ref:`dt-trouble` for troubleshooting advice. 9 10.. _get-devicetree-outputs: 11 12Get your devicetree and generated header 13**************************************** 14 15A board's devicetree (:ref:`BOARD.dts <devicetree-in-out-files>`) pulls in 16common node definitions via ``#include`` preprocessor directives. This at least 17includes the SoC's ``.dtsi``. One way to figure out the devicetree's contents 18is by opening these files, e.g. by looking in 19``dts/<ARCH>/<vendor>/<soc>.dtsi``, but this can be time consuming. 20 21If you just want to see the "final" devicetree for your board, build an 22application and open the :file:`zephyr.dts` file in the build directory. 23 24.. tip:: 25 26 You can build :zephyr:code-sample:`hello_world` to see the "base" devicetree for your board 27 without any additional changes from :ref:`overlay files <dt-input-files>`. 28 29For example, using the :zephyr:board:`qemu_cortex_m3` board to build 30:zephyr:code-sample:`hello_world`: 31 32.. code-block:: sh 33 34 # --cmake-only here just forces CMake to run, skipping the 35 # build process to save time. 36 west build -b qemu_cortex_m3 samples/hello_world --cmake-only 37 38You can change ``qemu_cortex_m3`` to match your board. 39 40CMake prints the input and output file locations like this: 41 42.. code-block:: none 43 44 -- Found BOARD.dts: .../zephyr/boards/arm/qemu_cortex_m3/qemu_cortex_m3.dts 45 -- Generated zephyr.dts: .../zephyr/build/zephyr/zephyr.dts 46 -- Generated devicetree_generated.h: .../zephyr/build/zephyr/include/generated/zephyr/devicetree_generated.h 47 48The :file:`zephyr.dts` file is the final devicetree in DTS format. 49 50The :file:`devicetree_generated.h` file is the corresponding generated header. 51 52See :ref:`devicetree-in-out-files` for details about these files. 53 54.. _dt-get-device: 55 56Get a struct device from a devicetree node 57****************************************** 58 59When writing Zephyr applications, you'll often want to get a driver-level 60:ref:`struct device <device_model_api>` corresponding to a devicetree node. 61 62For example, with this devicetree fragment, you might want the struct device 63for ``serial@40002000``: 64 65.. code-block:: devicetree 66 67 / { 68 soc { 69 serial0: serial@40002000 { 70 status = "okay"; 71 current-speed = <115200>; 72 /* ... */ 73 }; 74 }; 75 76 aliases { 77 my-serial = &serial0; 78 }; 79 80 chosen { 81 zephyr,console = &serial0; 82 }; 83 }; 84 85Start by making a :ref:`node identifier <dt-node-identifiers>` for the device 86you are interested in. There are different ways to do this; pick whichever one 87works best for your requirements. Here are some examples: 88 89.. code-block:: c 90 91 /* Option 1: by node label */ 92 #define MY_SERIAL DT_NODELABEL(serial0) 93 94 /* Option 2: by alias */ 95 #define MY_SERIAL DT_ALIAS(my_serial) 96 97 /* Option 3: by chosen node */ 98 #define MY_SERIAL DT_CHOSEN(zephyr_console) 99 100 /* Option 4: by path */ 101 #define MY_SERIAL DT_PATH(soc, serial_40002000) 102 103Once you have a node identifier there are two ways to proceed. One way to get a 104device is to use :c:macro:`DEVICE_DT_GET`: 105 106.. code-block:: c 107 108 const struct device *const uart_dev = DEVICE_DT_GET(MY_SERIAL); 109 110 if (!device_is_ready(uart_dev)) { 111 /* Not ready, do not use */ 112 return -ENODEV; 113 } 114 115There are variants of :c:macro:`DEVICE_DT_GET` such as 116:c:macro:`DEVICE_DT_GET_OR_NULL`, :c:macro:`DEVICE_DT_GET_ONE` or 117:c:macro:`DEVICE_DT_GET_ANY`. This idiom fetches the device pointer at 118build-time, which means there is no runtime penalty. This method is useful if 119you want to store the device pointer as configuration data. But because the 120device may not be initialized, or may have failed to initialize, you must verify 121that the device is ready to be used before passing it to any API functions. 122(This check is done for you by :c:func:`device_get_binding`.) 123 124In some situations the device cannot be known at build-time, e.g., if it depends 125on user input like in a shell application. In this case you can get the 126``struct device`` by combining :c:func:`device_get_binding` with the device 127name: 128 129.. code-block:: c 130 131 const char *dev_name = /* TODO: insert device name from user */; 132 const struct device *uart_dev = device_get_binding(dev_name); 133 134You can then use ``uart_dev`` with :ref:`uart_api` API functions like 135:c:func:`uart_configure`. Similar code will work for other device types; just 136make sure you use the correct API for the device. 137 138If you're having trouble, see :ref:`dt-trouble`. The first thing to check is 139that the node has ``status = "okay"``, like this: 140 141.. code-block:: c 142 143 #define MY_SERIAL DT_NODELABEL(my_serial) 144 145 #if DT_NODE_HAS_STATUS(MY_SERIAL, okay) 146 const struct device *const uart_dev = DEVICE_DT_GET(MY_SERIAL); 147 #else 148 #error "Node is disabled" 149 #endif 150 151If you see the ``#error`` output, make sure to enable the node in your 152devicetree. In some situations your code will compile but it will fail to link 153with a message similar to: 154 155.. code-block:: none 156 157 ...undefined reference to `__device_dts_ord_N' 158 collect2: error: ld returned 1 exit status 159 160This likely means there's a Kconfig issue preventing the device driver from 161being built, resulting in a reference that does not exist. If your code compiles 162successfully, the last thing to check is if the device is ready, like this: 163 164.. code-block:: c 165 166 if (!device_is_ready(uart_dev)) { 167 printk("Device not ready\n"); 168 } 169 170If you find that the device is not ready, it likely means that the device's 171initialization function failed. Enabling logging or debugging driver code may 172help in such situations. Note that you can also use :c:func:`device_get_binding` 173to obtain a reference at runtime. If it returns ``NULL`` it can either mean that 174device's driver failed to initialize or that it does not exist. 175 176.. _dts-find-binding: 177 178Find a devicetree binding 179************************* 180 181:ref:`dt-bindings` are YAML files which declare what you can do with the nodes 182they describe, so it's critical to be able to find them for the nodes you are 183using. 184 185If you don't have them already, :ref:`get-devicetree-outputs`. To find a node's 186binding, open the generated header file, which starts with a list of nodes in a 187block comment: 188 189.. code-block:: c 190 191 /* 192 * [...] 193 * Nodes in dependency order (ordinal and path): 194 * 0 / 195 * 1 /aliases 196 * 2 /chosen 197 * 3 /flash@0 198 * 4 /memory@20000000 199 * (etc.) 200 * [...] 201 */ 202 203Make note of the path to the node you want to find, like ``/flash@0``. Search 204for the node's output in the file, which starts with something like this if the 205node has a matching binding: 206 207.. code-block:: c 208 209 /* 210 * Devicetree node: 211 * /flash@0 212 * 213 * Binding (compatible = soc-nv-flash): 214 * $ZEPHYR_BASE/dts/bindings/mtd/soc-nv-flash.yaml 215 * [...] 216 */ 217 218See :ref:`missing-dt-binding` for troubleshooting. 219 220.. _set-devicetree-overlays: 221 222Set devicetree overlays 223*********************** 224 225Devicetree overlays are explained in :ref:`devicetree-intro`. The CMake 226variable :makevar:`DTC_OVERLAY_FILE` contains a space- or semicolon-separated 227list of overlay files to use. If :makevar:`DTC_OVERLAY_FILE` specifies multiple 228files, they are included in that order by the C preprocessor. A file in a 229Zephyr module can be referred to by escaping the Zephyr module dir variable 230like ``\${ZEPHYR_<module>_MODULE_DIR}/<path-to>/dts.overlay`` 231when setting the DTC_OVERLAY_FILE variable. 232 233You can set :makevar:`DTC_OVERLAY_FILE` to contain exactly the files you want 234to use. Here is an :ref:`example <west-building-dtc-overlay-file>` using 235``west build``. 236 237If you don't set :makevar:`DTC_OVERLAY_FILE`, the build system will follow 238these steps, looking for files in your application configuration directory to 239use as devicetree overlays: 240 241#. If the file :file:`socs/<SOC>_<BOARD_QUALIFIERS>.overlay` exists, it will be used. 242#. If the file :file:`boards/<BOARD>.overlay` exists, it will be used in addition to the above. 243#. If the current board has :ref:`multiple revisions <porting_board_revisions>` 244 and :file:`boards/<BOARD>_<revision>.overlay` exists, it will be used in addition to the above. 245#. If one or more files have been found in the previous steps, the build system 246 stops looking and just uses those files. 247#. Otherwise, if :file:`<BOARD>.overlay` exists, it will be used, and the build 248 system will stop looking for more files. 249#. Otherwise, if :file:`app.overlay` exists, it will be used. 250 251Extra devicetree overlays may be provided using ``EXTRA_DTC_OVERLAY_FILE`` which 252will still allow the build system to automatically use devicetree overlays 253described in the above steps. 254 255The build system appends overlays specified in ``EXTRA_DTC_OVERLAY_FILE`` 256to the overlays in ``DTC_OVERLAY_FILE`` when processing devicetree overlays. 257This means that changes made via ``EXTRA_DTC_OVERLAY_FILE`` have higher 258precedence than those made via ``DTC_OVERLAY_FILE``. 259 260All configuration files will be taken from the application's configuration 261directory except for files with an absolute path that are given with the 262``DTC_OVERLAY_FILE`` or ``EXTRA_DTC_OVERLAY_FILE`` argument. 263 264See :ref:`Application Configuration Directory <application-configuration-directory>` 265on how the application configuration directory is defined. 266 267Using :ref:`shields` will also add devicetree overlay files. 268 269The :makevar:`DTC_OVERLAY_FILE` value is stored in the CMake cache and used 270in successive builds. 271 272The :ref:`build system <build_overview>` prints all the devicetree overlays it 273finds in the configuration phase, like this: 274 275.. code-block:: none 276 277 -- Found devicetree overlay: .../some/file.overlay 278 279.. _use-dt-overlays: 280 281Use devicetree overlays 282*********************** 283 284See :ref:`set-devicetree-overlays` for how to add an overlay to the build. 285 286Overlays can override node property values in multiple ways. 287For example, if your BOARD.dts contains this node: 288 289.. code-block:: devicetree 290 291 / { 292 soc { 293 serial0: serial@40002000 { 294 status = "okay"; 295 current-speed = <115200>; 296 /* ... */ 297 }; 298 }; 299 }; 300 301These are equivalent ways to override the ``current-speed`` value in an 302overlay: 303 304.. Disable syntax highlighting as this construct does not seem supported by pygments 305.. code-block:: none 306 307 /* Option 1 */ 308 &serial0 { 309 current-speed = <9600>; 310 }; 311 312 /* Option 2 */ 313 &{/soc/serial@40002000} { 314 current-speed = <9600>; 315 }; 316 317We'll use the ``&serial0`` style for the rest of these examples. 318 319You can add aliases to your devicetree using overlays: an alias is just a 320property of the ``/aliases`` node. For example: 321 322.. code-block:: devicetree 323 324 / { 325 aliases { 326 my-serial = &serial0; 327 }; 328 }; 329 330Chosen nodes work the same way. For example: 331 332.. code-block:: devicetree 333 334 / { 335 chosen { 336 zephyr,console = &serial0; 337 }; 338 }; 339 340To delete a property (in addition to deleting properties in general, this is 341how to set a boolean property to false if it's true in BOARD.dts): 342 343.. code-block:: devicetree 344 345 &serial0 { 346 /delete-property/ some-unwanted-property; 347 }; 348 349You can add subnodes using overlays. For example, to configure a SPI or I2C 350child device on an existing bus node, do something like this: 351 352.. code-block:: devicetree 353 354 /* SPI device example */ 355 &spi1 { 356 my_spi_device: temp-sensor@0 { 357 compatible = "..."; 358 label = "TEMP_SENSOR_0"; 359 /* reg is the chip select number, if needed; 360 * If present, it must match the node's unit address. */ 361 reg = <0>; 362 363 /* Configure other SPI device properties as needed. 364 * Find your device's DT binding for details. */ 365 spi-max-frequency = <4000000>; 366 }; 367 }; 368 369 /* I2C device example */ 370 &i2c2 { 371 my_i2c_device: touchscreen@76 { 372 compatible = "..."; 373 label = "TOUCHSCREEN"; 374 /* reg is the I2C device address. 375 * It must match the node's unit address. */ 376 reg = <76>; 377 378 /* Configure other I2C device properties as needed. 379 * Find your device's DT binding for details. */ 380 }; 381 }; 382 383Other bus devices can be configured similarly: 384 385- create the device as a subnode of the parent bus 386- set its properties according to its binding 387 388Assuming you have a suitable device driver associated with the 389``my_spi_device`` and ``my_i2c_device`` compatibles, you should now be able to 390enable the driver via Kconfig and :ref:`get the struct device <dt-get-device>` 391for your newly added bus node, then use it with that driver API. 392 393.. _dt-create-devices: 394 395Write device drivers using devicetree APIs 396****************************************** 397 398"Devicetree-aware" :ref:`device drivers <device_model_api>` should create a 399``struct device`` for each ``status = "okay"`` devicetree node with a 400particular :ref:`compatible <dt-important-props>` (or related set of 401compatibles) supported by the driver. 402 403Writing a devicetree-aware driver begins by defining a :ref:`devicetree binding 404<dt-bindings>` for the devices supported by the driver. Use existing bindings 405from similar drivers as a starting point. A skeletal binding to get started 406needs nothing more than this: 407 408.. code-block:: yaml 409 410 description: <Human-readable description of your binding> 411 compatible: "foo-company,bar-device" 412 include: base.yaml 413 414See :ref:`dts-find-binding` for more advice on locating existing bindings. 415 416After writing your binding, your driver C file can then use the devicetree API 417to find ``status = "okay"`` nodes with the desired compatible, and instantiate 418a ``struct device`` for each one. There are two options for instantiating each 419``struct device``: using instance numbers, and using node labels. 420 421In either case: 422 423- Each ``struct device``\ 's name should be set to its devicetree node's 424 ``label`` property. This allows the driver's users to :ref:`dt-get-device` in 425 the usual way. 426 427- Each device's initial configuration should use values from devicetree 428 properties whenever practical. This allows users to configure the driver 429 using :ref:`devicetree overlays <use-dt-overlays>`. 430 431Examples for how to do this follow. They assume you've already implemented the 432device-specific configuration and data structures and API functions, like this: 433 434.. code-block:: c 435 436 /* my_driver.c */ 437 #include <zephyr/drivers/some_api.h> 438 439 /* Define data (RAM) and configuration (ROM) structures: */ 440 struct my_dev_data { 441 /* per-device values to store in RAM */ 442 }; 443 struct my_dev_cfg { 444 uint32_t freq; /* Just an example: initial clock frequency in Hz */ 445 /* other configuration to store in ROM */ 446 }; 447 448 /* Implement driver API functions (drivers/some_api.h callbacks): */ 449 static int my_driver_api_func1(const struct device *dev, uint32_t *foo) { /* ... */ } 450 static int my_driver_api_func2(const struct device *dev, uint64_t bar) { /* ... */ } 451 static struct some_api my_api_funcs = { 452 .func1 = my_driver_api_func1, 453 .func2 = my_driver_api_func2, 454 }; 455 456.. _dt-create-devices-inst: 457 458Option 1: create devices using instance numbers 459=============================================== 460 461Use this option, which uses :ref:`devicetree-inst-apis`, if possible. However, 462they only work when devicetree nodes for your driver's ``compatible`` are all 463equivalent, and you do not need to be able to distinguish between them. 464 465To use instance-based APIs, begin by defining ``DT_DRV_COMPAT`` to the 466lowercase-and-underscores version of the compatible that the device driver 467supports. For example, if your driver's compatible is ``"vnd,my-device"`` in 468devicetree, you would define ``DT_DRV_COMPAT`` to ``vnd_my_device`` in your 469driver C file: 470 471.. code-block:: c 472 473 /* 474 * Put this near the top of the file. After the includes is a good place. 475 * (Note that you can therefore run "git grep DT_DRV_COMPAT drivers" in 476 * the zephyr Git repository to look for example drivers using this style). 477 */ 478 #define DT_DRV_COMPAT vnd_my_device 479 480.. important:: 481 482 As shown, the DT_DRV_COMPAT macro should have neither quotes nor special 483 characters. Remove quotes and convert special characters to underscores 484 when creating ``DT_DRV_COMPAT`` from the compatible property. 485 486Finally, define an instantiation macro, which creates each ``struct device`` 487using instance numbers. Do this after defining ``my_api_funcs``. 488 489.. code-block:: c 490 491 /* 492 * This instantiation macro is named "CREATE_MY_DEVICE". 493 * Its "inst" argument is an arbitrary instance number. 494 * 495 * Put this near the end of the file, e.g. after defining "my_api_funcs". 496 */ 497 #define CREATE_MY_DEVICE(inst) \ 498 static struct my_dev_data my_data_##inst = { \ 499 /* initialize RAM values as needed, e.g.: */ \ 500 .freq = DT_INST_PROP(inst, clock_frequency), \ 501 }; \ 502 static const struct my_dev_cfg my_cfg_##inst = { \ 503 /* initialize ROM values as needed. */ \ 504 }; \ 505 DEVICE_DT_INST_DEFINE(inst, \ 506 my_dev_init_function, \ 507 NULL, \ 508 &my_data_##inst, \ 509 &my_cfg_##inst, \ 510 MY_DEV_INIT_LEVEL, MY_DEV_INIT_PRIORITY, \ 511 &my_api_funcs); 512 513Notice the use of APIs like :c:macro:`DT_INST_PROP` and 514:c:macro:`DEVICE_DT_INST_DEFINE` to access devicetree node data. These 515APIs retrieve data from the devicetree for instance number ``inst`` of 516the node with compatible determined by ``DT_DRV_COMPAT``. 517 518Finally, pass the instantiation macro to :c:macro:`DT_INST_FOREACH_STATUS_OKAY`: 519 520.. code-block:: c 521 522 /* Call the device creation macro for each instance: */ 523 DT_INST_FOREACH_STATUS_OKAY(CREATE_MY_DEVICE) 524 525``DT_INST_FOREACH_STATUS_OKAY`` expands to code which calls 526``CREATE_MY_DEVICE`` once for each enabled node with the compatible determined 527by ``DT_DRV_COMPAT``. It does not append a semicolon to the end of the 528expansion of ``CREATE_MY_DEVICE``, so the macro's expansion must end in a 529semicolon or function definition to support multiple devices. 530 531Option 2: create devices using node labels 532========================================== 533 534Some device drivers cannot use instance numbers. One example is an SoC 535peripheral driver which relies on vendor HAL APIs specialized for individual IP 536blocks to implement Zephyr driver callbacks. Cases like this should use 537:c:macro:`DT_NODELABEL` to refer to individual nodes in the devicetree 538representing the supported peripherals on the SoC. The devicetree.h 539:ref:`devicetree-generic-apis` can then be used to access node data. 540 541For this to work, your :ref:`SoC's dtsi file <dt-input-files>` must define node 542labels like ``mydevice0``, ``mydevice1``, etc. appropriately for the IP blocks 543your driver supports. The resulting devicetree usually looks something like 544this: 545 546.. code-block:: devicetree 547 548 / { 549 soc { 550 mydevice0: dev@0 { 551 compatible = "vnd,my-device"; 552 }; 553 mydevice1: dev@1 { 554 compatible = "vnd,my-device"; 555 }; 556 }; 557 }; 558 559The driver can use the ``mydevice0`` and ``mydevice1`` node labels in the 560devicetree to operate on specific device nodes: 561 562.. code-block:: c 563 564 /* 565 * This is a convenience macro for creating a node identifier for 566 * the relevant devices. An example use is MYDEV(0) to refer to 567 * the node with label "mydevice0". 568 */ 569 #define MYDEV(idx) DT_NODELABEL(mydevice ## idx) 570 571 /* 572 * Define your instantiation macro; "idx" is a number like 0 for mydevice0 573 * or 1 for mydevice1. It uses MYDEV() to create the node label from the 574 * index. 575 */ 576 #define CREATE_MY_DEVICE(idx) \ 577 static struct my_dev_data my_data_##idx = { \ 578 /* initialize RAM values as needed, e.g.: */ \ 579 .freq = DT_PROP(MYDEV(idx), clock_frequency), \ 580 }; \ 581 static const struct my_dev_cfg my_cfg_##idx = { /* ... */ }; \ 582 DEVICE_DT_DEFINE(MYDEV(idx), \ 583 my_dev_init_function, \ 584 NULL, \ 585 &my_data_##idx, \ 586 &my_cfg_##idx, \ 587 MY_DEV_INIT_LEVEL, MY_DEV_INIT_PRIORITY, \ 588 &my_api_funcs) 589 590Notice the use of APIs like :c:macro:`DT_PROP` and 591:c:macro:`DEVICE_DT_DEFINE` to access devicetree node data. 592 593Finally, manually detect each enabled devicetree node and use 594``CREATE_MY_DEVICE`` to instantiate each ``struct device``: 595 596.. code-block:: c 597 598 #if DT_NODE_HAS_STATUS(DT_NODELABEL(mydevice0), okay) 599 CREATE_MY_DEVICE(0) 600 #endif 601 602 #if DT_NODE_HAS_STATUS(DT_NODELABEL(mydevice1), okay) 603 CREATE_MY_DEVICE(1) 604 #endif 605 606Since this style does not use ``DT_INST_FOREACH_STATUS_OKAY()``, the driver 607author is responsible for calling ``CREATE_MY_DEVICE()`` for every possible 608node, e.g. using knowledge about the peripherals available on supported SoCs. 609 610.. _dt-drivers-that-depend: 611 612Device drivers that depend on other devices 613******************************************* 614 615At times, one ``struct device`` depends on another ``struct device`` and 616requires a pointer to it. For example, a sensor device might need a pointer to 617its SPI bus controller device. Some advice: 618 619- Write your devicetree binding in a way that permits use of 620 :ref:`devicetree-hw-api` from devicetree.h if possible. 621- In particular, for bus devices, your driver's binding should include a 622 file like :zephyr_file:`dts/bindings/spi/spi-device.yaml` which provides 623 common definitions for devices addressable via a specific bus. This enables 624 use of APIs like :c:macro:`DT_BUS` to obtain a node identifier for the bus 625 node. You can then :ref:`dt-get-device` for the bus in the usual way. 626 627Search existing bindings and device drivers for examples. 628 629.. _dt-apps-that-depend: 630 631Applications that depend on board-specific devices 632************************************************** 633 634One way to allow application code to run unmodified on multiple boards is by 635supporting a devicetree alias to specify the hardware specific portions, as is 636done in the :zephyr:code-sample:`blinky` sample. The application can then be configured in 637:ref:`BOARD.dts <devicetree-in-out-files>` files or via :ref:`devicetree 638overlays <use-dt-overlays>`. 639