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