1. 课程导入

在嵌入式 Linux 开发中,设备树(Device Tree,简称 DT)已经成为 ARM、RISC-V、PowerPC 等架构描述硬件资源的标准机制。它把“板级硬件信息”从内核源码中剥离出来,用一份可读、可编译、可复用的文本描述硬件拓扑,让同一份内核镜像能够适配不同主板。本课程围绕“设备树驱动适配工程”展开,目标不是停留在会写几个节点,而是建立从硬件描述、内核解析、驱动匹配到调试验证的完整工程能力。

学习本课程后,你应当能够:读懂 SoC 厂商提供的 .dts/.dtsi 文件;根据原理图编写和修改设备树节点;理解 compatible、reg、interrupts、clocks、pinctrl 等核心属性的语义;掌握 platform driver、i2c driver、spi driver 与设备树的匹配流程;能够定位“驱动不 probe”“资源申请失败”“引脚复用冲突”等典型问题,并形成可复用的适配与验证方法。

一、核心概念:设备树到底描述了什么

设备树本质上是一棵由节点(node)和属性(property)组成的层次化数据结构。根节点 / 下通常包含 chosen、memory、cpus、soc 等子节点;soc 内部再挂载 i2c、spi、uart、gpio、ethernet 等控制器节点,外设则作为这些控制器的子节点出现。内核启动时,bootloader 把编译后的 DTB 传给内核,内核的 OF(Open Firmware)子系统将其展开为 device_node,再进一步生成 platform_device 等设备对象,最终与驱动中的 of_match_table 完成匹配。

需要特别区分三个层次:DTS 是源码,DTB 是二进制,设备树是运行时内核中的数据结构。很多初学者把“改 dts”等同于“改驱动”,实际上设备树负责“告诉内核有什么硬件、资源在哪里”,驱动负责“怎么操作这个硬件”,二者通过 compatible 字符串和资源接口解耦。

二、整体知识框架与实战路线图

本课程的知识框架可以概括为“一条主线、四个层次、两类调试”。一条主线是“硬件描述 → 内核解析 → 驱动匹配 → 功能验证”;四个层次分别是语法层、资源层、驱动层和板级适配层;两类调试是静态检查(dtc 编译、schema 校验)和动态调试(probe 日志、sysfs、debugfs、示波器/逻辑分析仪)。

设备树驱动适配工程:知识框架与实战路线 ① 语法层 dts/dtsi/dtb 节点、属性、标签、引用 ② 资源层 reg / interrupts / clocks pinctrl / gpio / dma ③ 驱动层 of_match_table probe / remove / 资源获取 ④ 板级适配层 原理图 → dts 修改 多板复用、overlay 硬件描述 原理图 / 手册 内核解析 OF 子系统展开 驱动匹配 compatible 匹配 功能验证 读写 / 中断 / 性能 静态检查 dtc 编译、dtbs_check、schema 校验 节点路径、phandle、reg 范围核对 动态调试 probe 日志、/sys/firmware/devicetree debugfs、逻辑分析仪、示波器 贯穿全课程的关键属性与接口 compatible · reg · interrupts / interrupt-parent · clocks / clock-names · pinctrl-0/1 · gpios · dmas · status · aliases · chosen 驱动侧:of_match_table · of_property_read_* · platform_get_resource · devm_* 资源管理

从路线图可以看出,学习顺序建议为:先掌握 DTS 语法和编译工具链,再理解内核如何把节点变成设备,然后进入具体总线驱动(platform、i2c、spi)的匹配与资源获取,最后通过真实板级案例完成从原理图到功能验证的闭环。每一层都要配合调试手段,否则很容易陷入“改了不生效、错了不知道”的状态。

三、典型场景:从原理图到驱动 probe 的完整链路

假设我们要在一块基于 i.MX6ULL 的板子上适配一颗挂在 I2C1 上的温湿度传感器 SHT30。工程动作大致如下:

  1. 查阅原理图,确认 SHT30 的 I2C 地址为 0x44,SCL/SDA 分别复用为 I2C1_SCL 和 I2C1_SDA,供电由 3V3 提供。
  2. 在板级 dts 中确认 &i2c1 节点已使能,并补充 pinctrl 与时钟。
  3. 在 &i2c1 下新增子节点,填写 compatible、reg 等属性。
  4. 确认内核中已有对应驱动,且其 of_match_table 包含相同 compatible。
  5. 编译 DTB、更新启动镜像,观察 dmesg 中是否出现 probe 成功日志。
  6. 通过 /sys/bus/i2c/devices/ 和传感器字符设备节点验证数据读取。
&i2c1 {
    status = "okay";
    clock-frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c1>;

    sht30: sensor@44 {
        compatible = "sensirion,sht30";
        reg = <0x44>;
        status = "okay";
    };
};

这段代码虽短,却覆盖了资源层和驱动层的核心:status 控制节点是否生效,reg 决定 I2C 从地址,compatible 决定匹配哪个驱动。任何一个写错,都会导致 probe 失败或设备不可用。

四、常见误区与复盘要点

误区 现象 正确做法
只改 dts 不看驱动 compatible 驱动不 probe,无日志 核对驱动 of_match_table 与 dts 字符串完全一致
忽略 pinctrl 与时钟 寄存器读写失败、总线无波形 先确认引脚复用和时钟使能,再查设备地址
把 status 写成 disabled 节点存在但设备不生成 确认目标节点 status = "okay"
reg 地址与原理图不符 I2C 通信超时或读回 0xFF 用 i2cdetect 扫描总线,确认从地址
只依赖 printk 不看设备树运行时状态 排查效率低 查看 /sys/firmware/devicetree/base 与 debugfs
建议每完成一个外设适配,都做一次“三查”:查 dts 节点路径与属性、查驱动匹配表、查运行时日志与 sysfs。把这三步固化成习惯,后续复杂板级适配会轻松很多。
设备树不是“写对就万事大吉”。它只描述硬件,不保证驱动逻辑正确。遇到问题时,要同时从硬件连接、设备树描述、驱动实现、内核配置四个方向排查,避免只盯着一处反复修改。

本课程后续将沿着这条路线逐步展开:从 DTS 语法与编译、OF 子系统原理,到 platform/I2C/SPI 驱动匹配,再到中断、时钟、pinctrl、GPIO 等资源获取,最后通过多个真实板级案例完成综合适配训练。掌握这套框架后,你面对一块新板子时,就能有条不紊地完成从原理图到驱动可用的全过程。