第 08 课:Devicetree(设备树)— Zephyr 最重要的知识之一
摘要:本课系统讲解 Zephyr 的 Devicetree(设备树)机制。你将理解 Zephyr 为何用 Devicetree 解耦应用与硬件、掌握
.dts/.dtsi/.overlay文件的作用与关系,学会通过app.overlay修改板级配置(如 LED、UART),并掌握compatible、status、aliases、chosen等核心概念。最后通过 4 个 ESP32-S3 实验,学会用DT_ALIAS()、DEVICE_DT_GET()、GPIO_DT_SPEC_GET()等宏在 C 代码中读取设备树信息,实现应用代码与具体开发板解耦。
目标:掌握 Zephyr 的 Devicetree,学会修改板级硬件配置,并能够在应用程序中读取 Devicetree 信息。
为什么要学习 Devicetree?
在 STM32Cube 或 ESP-IDF 中,我们通常这样写:
#defineLED_GPIOGPIOA#defineLED_PIN5如果换一块板子,就要修改源码。
Zephyr 不希望这样。
它希望:
程序完全不知道 LED 接在哪里。
程序只知道LED0,真正接在哪里,由 Devicetree 决定。
因此:
Application │ ▼ Devicetree │ ▼ Board Hardware这也是 Zephyr 能支持数百块开发板的重要原因。
Devicetree 的作用
它主要描述两件事情:
MCU 上有哪些硬件;
每个硬件如何连接、配置和初始化。
例如:
UART1 SPI2 GPIOA LED Button I2C Flash全部放进 DTS。程序不用再写GPIO_NUM_5,而是写led0。
Devicetree 文件有哪些?
对于 ESP32-S3:
boards/ espressif/ esp32s3_devkitc/里面通常有:
esp32s3_devkitc.dts esp32s3_devkitc_defconfig Kconfig.board应用程序可以增加:
app.overlay通常目录如下:
my_app │ ├── src │ main.c │ ├── prj.conf │ ├── CMakeLists.txt │ └── app.overlay以后99% 的修改都放在 overlay,不要直接修改官方 .dts。
为了帮助你快速区分三种文件的使用场景,下面用一张表格对比.dts、.dtsi、.overlay:
| 文件类型 | 作用 | 修改场景 | 注意事项 |
|---|---|---|---|
.dts | 描述某块具体开发板的完整设备树,是最终编译的入口 | 一般不要修改,它由板级厂商维护 | 修改后升级 SDK 会被覆盖;改动应尽量放到 overlay |
.dtsi | 存放可复用的公共设备树片段(如 SoC 定义、通用外设),被.dts通过#include引入 | 通常不需要修改,除非要定制 SoC 级默认配置 | 改动会影响所有引用它的板子,风险较大 |
.overlay | 应用级覆盖文件,在编译时叠加到板级 DTS 之上 | 99% 的应用修改都放这里:新增/修改/禁用节点、改 GPIO、改 UART 等 | 只影响当前应用,不污染官方文件;是 Zephyr 推荐的扩展方式 |
简单记忆:.dts是板子的“底图”,.dtsi是公共“零件库”,.overlay是应用自己的“贴纸”。
Overlay 是什么?
Zephyr 会先读取:
官方 Board DTS
然后读取:
app.overlayOverlay 可以:
新增节点 修改节点 禁用节点 修改 GPIO 修改 UART例如:
官方:
UART0 ↓ Overlay:UART0 波特率改成 115200
一个 LED 节点
例如:
/{leds{compatible="gpio-leds";led0:led_0{gpios=<&gpio02GPIO_ACTIVE_HIGH>;label="LED0";};};};这里可以看到:
led0就是一个 Node Label。
程序以后就是找:
led0Button
例如:
buttons{compatible="gpio-keys";button0:button_0{gpios=<&gpio09GPIO_ACTIVE_LOW>;label="SW0";};};Button 和 LED 都只是:
NodeDevicetree 的树结构
例如:
所以叫:
Device TreeNode
例如:
uart0{};就是一个 Node。
里面有很多 Property。
例如:
uart0{current-speed=<