设备树(DTS)硬件描述与覆盖机制

设备树(Device Tree,DTS)及其覆盖机制(Overlay)是嵌入式Linux系统中管理硬件配置的核心技术。

1. 设备树基础

(1) 设备树的作用

  • 硬件抽象:将硬件配置(地址、中断、外设连接)从内核代码中解耦,提高可移植性。
  • 动态适配:同一内核镜像支持不同硬件平台,通过加载不同的设备树二进制文件(DTB)实现。

(2) 设备树组成

  • 节点(Node):表示硬件设备或总线,以树形结构组织。
  • 属性(Property):键值对,描述设备的寄存器地址、中断号、时钟频率等。
  • 兼容性(Compatible):关键属性,用于驱动匹配(如 compatible = "ti,omap3-i2c")。

(3) 设备树语法示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 根节点
/ {
compatible = "vendor,board"; // 板级兼容性
#address-cells = <1>; // 子节点地址用1个cell表示
#size-cells = <1>; // 子节点大小用1个cell表示

// I2C控制器节点
i2c0: i2c@ffec0000 {
compatible = "snps,designware-i2c";
reg = <0xffec0000 0x1000>; // 寄存器地址和长度
interrupts = <15 IRQ_TYPE_LEVEL_HIGH>; // 中断号及触发类型
#address-cells = <1>;
#size-cells = <0>;

// I2C设备子节点(如EEPROM)
eeprom@50 {
compatible = "atmel,24c256";
reg = <0x50>; // I2C从机地址
pagesize = <64>;
};
};
};

2. 关键机制解析

(1) 地址与大小表示

  • #address-cells#size-cells
    定义子节点 reg 属性中地址和长度的cell数量(1 cell = 32位)。
    例如:reg = <0xffec0000 0x1000> 表示起始地址 0xffec0000,长度 0x1000

(2) 中断处理

  • interrupt-parent:指定中断控制器节点(通过 phandle 引用)。

  • interrupts:中断号和触发方式。

    1
    2
    3
    4
    5
    gpio_keys {
    compatible = "gpio-keys";
    interrupt-parent = <&gpio0>; // 引用gpio0节点的phandle
    interrupts = <5 IRQ_TYPE_EDGE_RISING>; // GPIO5,上升沿触发
    };

(3) 引用与标签(Labels)

  • &label:引用其他节点(如 &gpio0 指向标签为 gpio0 的节点)。
  • phandle:节点唯一标识符,由编译器自动生成或手动指定。

3. 设备树覆盖(Overlay)

(1) 覆盖的作用

  • 动态修改设备树:在运行时添加、修改或删除节点,无需重新编译整个DTB。
  • 应用场景:模块化硬件扩展(如树莓派HAT)、热插拔设备配置。

(2) 覆盖文件示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/dts-v1/;
/plugin/; // 声明为覆盖文件

// 覆盖目标节点(基础设备树中的i2c1)
&i2c1 {
#address-cells = <1>;
#size-cells = <0>;
status = "okay"; // 启用i2c1控制器

// 添加新的I2C设备
touchscreen@38 {
compatible = "edt,edt-ft5406";
reg = <0x38>;
interrupt-parent = <&gpio>;
interrupts = <17 IRQ_TYPE_EDGE_FALLING>;
};
};

(3) 覆盖应用流程

  1. 编译覆盖文件

    1
    dtc -@ -I dts -O dtb -o overlay.dtbo overlay.dts

    -@ 选项生成符号表,支持标签引用。

  2. 加载覆盖

    • U-Boot:使用 fdt apply 命令。

    • Linux运行时:通过ConfigFS(需内核启用CONFIG_OF_OVERLAY):

      1
      2
      mkdir /sys/kernel/config/device-tree/overlays/custom
      cat overlay.dtbo > /sys/kernel/config/device-tree/overlays/custom/dtbo

(4) 覆盖冲突处理

  • 节点冲突:同名节点会合并属性,若存在不可合并属性则覆盖。
  • 状态管理:通过 status 属性启用/禁用设备(如 status = "disabled";)。

4. 调试与分析工具

(1) 反编译DTB

1
dtc -I dtb -O dts -o extracted.dts system.dtb

(2) 查看运行时设备树

1
2
3
4
5
# 列出所有节点
ls /sys/firmware/devicetree/base/

# 查看节点属性(需转换为ASCII)
hexdump -C /sys/firmware/devicetree/base/i2c0/reg

(3) 内核日志

  • 启用 CONFIG_DEBUG_DEVICE_TREE,查看设备树解析日志。

5. 典型问题与解决

Q1:驱动未正确匹配

  • 检查点:
    • compatible 属性是否与驱动中的of_match_table一致。
    • 使用 of_find_compatible_node() 确认节点是否存在。

Q2:地址映射错误

  • 验证方法
    检查 reg 属性是否与硬件手册一致,确认父节点的 ranges 映射正确。

Q3:覆盖加载失败

  • 调试步骤:
    1. 检查覆盖文件语法:dtc -I dtb -O dts -f overlay.dtbo
    2. 确认基础设备树中存在目标节点路径。
    3. 查看内核日志:dmesg | grep of_overlay

6. 总结对比

特性 基础设备树(DTS) 设备树覆盖(Overlay)
修改方式 静态编译,需重新生成DTB 动态加载,实时生效
适用场景 固定硬件配置 模块化扩展、后期硬件调整
复杂度 完整描述所有硬件 仅描述变更部分
调试难度 需重新烧录DTB 可快速迭代,通过日志排查

通过合理使用设备树及其覆盖机制,开发者能够高效管理复杂硬件配置,适应嵌入式系统灵活多变的需求。