Troubleshooting devicetree
Here are some tips for fixing misbehaving devicetree related code.
See Devicetree HOWTOs for other “HOWTO” style information.
Try again with a pristine build directory
Important
Try this first, before doing anything else.
See Pristine Builds for examples, or just delete the build directory completely and retry.
This is general advice which is especially applicable to debugging devicetree issues, because the outputs are created during the CMake configuration phase, and are not always regenerated when one of their inputs changes.
Make sure <devicetree.h> is included
Unlike Kconfig symbols, the devicetree.h
header must be included
explicitly.
Many Zephyr header files rely on information from devicetree, so including some
other API may transitively include devicetree.h
, but that’s not
guaranteed.
Make sure you’re using the right names
Remember that:
In C/C++, devicetree names must be lowercased and special characters must be converted to underscores. Zephyr’s generated devicetree header has DTS names converted in this way into the C tokens used by the preprocessor-based
<devicetree.h>
API.In overlays, use devicetree node and property names the same way they would appear in any DTS file. Zephyr overlays are just DTS fragments.
For example, if you’re trying to get the clock-frequency
property of a
node with path /soc/i2c@12340000
in a C/C++ file:
/*
* foo.c: lowercase-and-underscores names
*/
/* Don't do this: */
#define MY_CLOCK_FREQ DT_PROP(DT_PATH(soc, i2c@1234000), clock-frequency)
/* ^ ^
* @ should be _ - should be _ */
/* Do this instead: */
#define MY_CLOCK_FREQ DT_PROP(DT_PATH(soc, i2c_1234000), clock_frequency)
/* ^ ^ */
And if you’re trying to set that property in a devicetree overlay:
/*
* foo.overlay: DTS names with special characters, etc.
*/
/* Don't do this; you'll get devicetree errors. */
&{/soc/i2c_12340000/} {
clock_frequency = <115200>;
};
/* Do this instead. Overlays are just DTS fragments. */
&{/soc/i2c@12340000/} {
clock-frequency = <115200>;
};
Look at the preprocessor output
To save preprocessor output when using GCC-based toolchains, add
-save-temps=obj
to the EXTRA_CFLAGS
CMake variable. For example, to
build Hello World with west with this option set, use:
west build -b BOARD samples/hello_world -- -DEXTRA_CFLAGS=-save-temps=obj
This will create a preprocessor output file named foo.c.i
in the build
directory for each source file foo.c
.
You can then search for the file in the build directory to see what your
devicetree macros expanded to. For example, on macOS and Linux, using find
to find main.c.i
:
$ find build -name main.c.i
build/CMakeFiles/app.dir/src/main.c.i
It’s usually easiest to run a style formatter on the results before opening
them. For example, to use clang-format
to reformat the file in place:
clang-format -i build/CMakeFiles/app.dir/src/main.c.i
You can then open the file in your favorite editor to view the final C results after preprocessing.
Validate properties
If you’re getting a compile error reading a node property, check your node identifier and property. For example, if you get a build error on a line that looks like this:
int baud_rate = DT_PROP(DT_NODELABEL(my_serial), current_speed);
Try checking the node by adding this to the file and recompiling:
#if !DT_NODE_EXISTS(DT_NODELABEL(my_serial))
#error "whoops"
#endif
If you see the “whoops” error message when you rebuild, the node identifier isn’t referring to a valid node. Get your devicetree and generated header and debug from there.
Some hints for what to check next if you don’t see the “whoops” error message:
does the property exist?
does the node have a matching binding?
does the binding define the property?
Check for missing bindings
See Devicetree bindings for information about bindings, and Bindings index for information on bindings built into Zephyr.
If the build fails to Find a devicetree binding for a node, then either the
node’s compatible
property is not defined, or its value has no matching
binding. If the property is set, check for typos in its name. In a devicetree
source file, compatible
should look like "vnd,some-device"
–
Make sure you’re using the right names.
If your binding file is not under zephyr/dts
, you may need to set
DTS_ROOT; see Where bindings are located.
Errors with DT_INST_() APIs
If you’re using an API like DT_INST_PROP()
, you must define
DT_DRV_COMPAT
to the lowercase-and-underscores version of the compatible
you are interested in. See Option 1: create devices using instance numbers.