设备树
Kconfig 决定要不要编译 GPIO 支持,但它不能说明背光接在哪个引脚。这个信息来自设备树。Zephyr 在构建时处理它,不是像部分 Linux 场景那样在启动时装载一份 DTB。
设备树文件
SoC 的 .dtsi 描述芯片控制器、地址、中断等;板卡 .dts 描述这些控制器在板上连到哪里;应用 overlay 在这份板卡描述上补充或覆盖本次应用需要的配置。
修改已有板子的一个应用,一般先写 overlay,不直接改上游板卡 DTS。新 PCB 才考虑独立板卡定义。
节点与属性
learning-app 的 boards/waveshare.overlay 中有:
/ {
aliases {
learning-output = &learning_backlight;
};
learning_outputs {
compatible = "gpio-leds";
learning_backlight: backlight {
gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
};
};
};
逐项读:
learning_backlight:是节点标签,其他属性用&learning_backlight引用。backlight是节点名,不等于 C 变量。learning-output是应用约定的别名,换板时可让它指向另一节点。gpios引用 GPIO 控制器、引脚 2 和有效电平;具体 cell 含义由控制器 binding 定义。compatible与 YAML binding 匹配,描述节点应具有什么属性。字符串本身不会凭空提供驱动。
这里借用 gpio-leds 的子节点描述背光 GPIO,不要求打开 LED 子系统;应用直接调用 GPIO API。
设备树访问宏
static const struct gpio_dt_spec output =
GPIO_DT_SPEC_GET(DT_ALIAS(learning_output), gpios);
C 宏中的别名把连字符改为下划线。gpio_dt_spec 保存控制器设备、pin 和 flags。程序随后:
if (!gpio_is_ready_dt(&output)) {
return 0;
}
int ret = gpio_pin_configure_dt(&output, GPIO_OUTPUT_INACTIVE);
配置成功后才调用 gpio_pin_set_dt。这个 API 的 1 表示逻辑有效,是否输出物理高电平还取决于 ACTIVE_HIGH / ACTIVE_LOW。因此可通过设备树改变极性,不在业务代码里到处取反。
引脚复用
GPIO2 若同时交给 LEDC PWM 和普通 GPIO,两个功能会争用同一硬件。完整 overlay 关闭了 ledc0 和原 pwmleds 节点,prj.conf 也关闭 PWM。本例只做背光开关,不同时做调光。
SPI、I2C、UART 通常还要配置 pinctrl:把芯片内部控制器信号映射到实际引脚。给设备写了 status="okay",不会自动替你查原理图挑引脚。
构建与核对
执行 Kconfig 页的背光构建命令,检查日志里加载了 waveshare.overlay。然后:
cd ~/Projects/zephyr-main-workspace/zephyr
rg -n 'learning-output|learning_outputs|ledc|backlight' \
build/learning-backlight/zephyr/zephyr.dts
最终设备树应该能找到应用别名和 GPIO2,LEDC 节点应为 disabled。若想看生成宏,可检查:
build/learning-backlight/zephyr/include/generated/zephyr/devicetree_generated.h
这是排错材料,不直接修改。
烧录后预期背光每 500 ms 改变一次状态,完整亮灭周期约一秒。串口仍输出计数。仅背光变化,不会出现文字画面。
常用属性
| 属性/概念 | 要回答的问题 |
|---|---|
| reg | 这个设备在所属总线上的地址是什么?I2C 常为器件地址,不能统一当内存地址 |
| status | 这个实例是否参与当前配置? |
| pinctrl | 控制器信号走哪些引脚? |
| chosen | 系统应使用哪个实例做 console、display 等角色? |
| aliases | 应用约定的名称指向哪个节点? |
| compatible / binding | 该设备使用哪种属性定义和驱动匹配方式? |
驱动通常通过设备树实例化并结合 Kconfig 编入;仍需检查驱动的具体实现与依赖。常见 __device_dts_ord_... 链接错误意味着代码引用了设备,但对应设备对象没有生成,可能是驱动配置或实例状态问题,不是让你手工定义该符号。
练习:只把 ACTIVE_HIGH 改为 ACTIVE_LOW,先预测日志不变而亮灭相反,再上板观察;结束后恢复。不要随意换 GPIO 验证,未查原理图的引脚可能连接其他器件。
来源:Devicetree HOWTO、本地板卡 DTS 和 dts/bindings/gpio/gpio-leds.yaml。