2. 设备树语法入门:DTS文件结构、节点与属性、标签与引用
设备树(Device Tree)是一种描述硬件配置的数据结构,它通过文本文件(.dts)被编译成二进制文件(.dtb)传递给内核。本章将系统讲解DTS文件的核心语法,包括文件结构、节点与属性的定义规则,以及标签与引用的高级用法。
2.1 DTS文件结构
一个典型的DTS文件由以下几个部分组成:
- 根节点:整个设备树的起点,使用
/表示。 - 节点:描述一个具体的硬件设备或总线,可以嵌套。
- 属性:描述节点的特性,如地址、中断号、时钟频率等。
- 标签:为节点起别名,方便在其他地方引用。
- 包含文件:通过
#include引入其他.dtsi文件。
关键概念: DTS文件采用树形层级结构,根节点下挂载CPU、内存、总线、外设等节点,每个节点通过属性描述其硬件特征。
// 一个简单的DTS文件示例
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
cpu@0 {
compatible = "arm,cortex-a9";
reg = <0x0 0x100>;
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>;
};
uart0: serial@101f1000 {
compatible = "ns16550";
reg = <0x101f1000 0x1000>;
interrupts = <0x1 0x0>;
};
};
提示:
/dts-v1/; 是版本声明,表示使用设备树v1格式。所有现代DTS文件都必须以该声明开头。
2.2 节点(Node)与属性(Property)
2.2.1 节点定义
节点是设备树的基本组成单元,每个节点代表一个硬件设备或总线。节点名称格式为 node-name@unit-address,其中 unit-address 是设备在总线上的地址。
| 节点类型 | 命名规则 | 示例 |
|---|---|---|
| CPU节点 | cpu@核心编号 | cpu@0 |
| 内存节点 | memory@基地址 | memory@80000000 |
| 串口节点 | serial@基地址 | serial@101f1000 |
| I2C控制器 | i2c@基地址 | i2c@10002000 |
| GPIO控制器 | gpio@基地址 | gpio@10003000 |
2.2.2 属性定义
属性用于描述节点的硬件特征,常见的属性类型包括:
- compatible:指定设备驱动兼容性字符串,格式为
"厂商,设备型号"。 - reg:描述设备地址空间,格式为
<基地址 长度>。 - interrupts:描述中断号,格式为
<中断类型 中断号 触发方式>。 - clocks:描述时钟源,通过phandle引用时钟节点。
- status:设备状态,可选
"okay"、"disabled"、"reserved"。
// 属性定义示例
ethernet@10001000 {
compatible = "davicom,dm9000";
reg = <0x10001000 0x1000>;
interrupts = <0x2 0x4>;
clocks = <&clkc 16>;
status = "okay";
};
注意:
compatible 属性是内核匹配驱动的关键。内核会按照字符串顺序依次尝试匹配,建议将最精确的匹配放在最前面。
2.3 标签(Label)与引用(&)
标签为节点提供一个别名,方便在其他位置引用该节点。引用使用 &label 语法,常用于以下场景:
- 在根节点中引用子节点
- 在板级文件中覆盖SoC级节点的属性
- 在多个节点间建立连接关系
// 标签定义与引用示例
/dts-v1/;
/ {
clkc: clock-controller@10000000 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <24000000>;
};
uart0: serial@101f1000 {
compatible = "ns16550";
reg = <0x101f1000 0x1000>;
clocks = <&clkc>; // 引用clkc标签
};
};
// 在板级文件中覆盖uart0属性
&uart0 {
status = "okay";
clock-frequency = <115200>;
};
最佳实践: 在SoC级.dtsi文件中为所有重要节点添加标签,板级.dts文件通过
&label 引用并覆盖属性。这种分离设计提高了代码复用性。
2.4 设备树层级结构图
下图展示了一个典型嵌入式系统的设备树层级结构,包含根节点、CPU、内存、总线及外设节点:
2.5 节点与属性对比表
| 概念 | 定义 | 语法示例 | 用途 |
|---|---|---|---|
| 节点 | 硬件设备的抽象表示 | uart0: serial@101f1000 { ... }; |
描述一个具体的硬件设备 |
| 属性 | 节点的特征描述 | compatible = "ns16550"; |
定义设备的兼容性、地址、中断等 |
| 标签 | 节点的别名 | uart0: |
方便在其他位置引用节点 |
| 引用 | 通过标签引用节点 | &uart0 { ... }; |
覆盖或扩展节点属性 |
| 包含 | 引入其他文件 | #include "soc.dtsi" |
复用SoC级设备树定义 |
2.6 常见错误与避坑指南
常见错误1: 忘记声明
常见错误2: 节点名称中
常见错误3: 引用标签时使用
常见错误4:
/dts-v1/; 版本号,导致编译失败。常见错误2: 节点名称中
@ 后的地址与 reg 属性中的基地址不一致,导致内核无法正确匹配。常见错误3: 引用标签时使用
&label 但标签未定义,编译时报错“undefined label”。常见错误4:
compatible 属性字符串拼写错误,导致驱动无法加载。
调试技巧: 使用
dtc -I dts -O dtb -o output.dtb input.dts 编译DTS文件,通过 dtc -I dtb -O dts -o output.dts input.dtb 反编译查看二进制内容。编译错误信息会直接指出语法问题所在行号。
2.7 本章小结
本章学习了设备树的核心语法:
- DTS文件结构包含根节点、子节点、属性和标签
- 节点通过
node-name@unit-address命名,属性描述硬件特征 - 标签
label:和引用&label实现节点复用和覆盖 - 设备树层级结构清晰反映了硬件拓扑关系