2. 设备树基础:DTS语法入门、节点与属性
设备树(Device Tree)是嵌入式Linux系统中用于描述硬件拓扑结构的数据结构。在网关硬件抽象层开发中,设备树是连接SoC与外围设备(如GPIO、PWM控制器)的“硬件描述语言”。本章将系统讲解DTS语法、节点与属性的定义,以及编译流程。
核心认知:设备树不是驱动代码,而是硬件配置清单。驱动通过设备树获取寄存器地址、中断号、GPIO引脚等参数,实现与硬件解耦。
2.1 设备树源文件(DTS)语法入门
DTS文件采用树形结构,以/dts-v1/;开头声明版本。基本语法规则如下:
- 节点(Node):以
node-name@unit-address格式定义,花括号内包含属性和子节点。 - 属性(Property):键值对,值可以是字符串、32位整数数组、字节数组或字符串列表。
- 引用(Reference):使用
&label语法引用其他节点,用于覆盖或追加属性。 - 包含文件:使用
#include导入.dtsi头文件,实现SoC级与板级分离。
// 最小DTS示例
/dts-v1/;
/ {
model = "Gateway Board v1.0";
compatible = "vendor,gateway-100", "vendor,gateway";
#address-cells = <1>;
#size-cells = <1>;
cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a7";
reg = <0x0>;
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; // 512MB RAM
};
};
语法要点:分号结束每个属性,花括号表示节点范围,
@后跟地址用于区分同类型设备,#address-cells和#size-cells决定reg属性的地址长度。
2.2 节点与属性详解
设备树的核心是节点(Node)和属性(Property)。节点代表一个硬件设备或总线,属性描述该设备的配置参数。
| 概念 | 语法示例 | 说明 |
|---|---|---|
| 根节点 | / { ... }; |
设备树的顶层容器,包含所有设备节点 |
| 子节点 | uart0: serial@44e09000 { ... }; |
uart0是标签(label),serial@44e09000是节点名+地址 |
| 标签引用 | &uart0 { status = "okay"; }; |
在板级文件中追加或覆盖SoC级节点的属性 |
| 属性值类型 | prop = <0x1234 0x5678>; |
尖括号内为32位整数数组,空格分隔 |
| 字符串属性 | compatible = "vendor,device"; |
双引号包裹,用于驱动匹配 |
| 布尔属性 | status = "disabled"; |
字符串形式表示开关状态 |
2.3 标准属性详解
设备树规范定义了一组标准属性,所有设备节点都应遵循。以下是网关开发中最常用的三个标准属性:
2.3.1 compatible 属性
compatible是驱动匹配的核心属性,格式为"厂商,设备型号"。内核通过该属性查找对应的驱动。
// compatible 属性示例
pwm-controller@48300000 {
compatible = "ti,am3359-ecap", "ti,am33xx-ecap";
// 内核优先匹配第一个,失败则尝试第二个
reg = <0x48300000 0x1000>;
};
兼容性策略:将最具体的型号放在第一位,通用型号放在后面。例如
"vendor,board-v2"在前,"vendor,board"在后,确保新硬件优先匹配专用驱动。
2.3.2 reg 属性
reg描述设备在总线上的地址空间,由#address-cells和#size-cells决定格式。
| #address-cells | #size-cells | reg 格式 | 示例 |
|---|---|---|---|
| 1 | 1 | <addr size> |
reg = <0x48000000 0x1000>; |
| 2 | 1 | <hi_addr lo_addr size> |
reg = <0x0 0x48000000 0x1000>; |
| 1 | 0 | <addr> |
reg = <0x48000000>;(无大小) |
2.3.3 interrupts 属性
interrupts描述设备使用的中断资源,需要配合interrupt-parent使用。
// 中断属性完整示例
gpio-keys {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
interrupt-parent = <&gpio1>; // 指定中断控制器
button@0 {
label = "SW1";
linux,code = <KEY_ENTER>;
gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
};
};
2.4 设备树源文件编译
DTS文件必须编译为DTB(Device Tree Blob)二进制文件,才能被引导加载程序(如U-Boot)传递给内核。编译流程如下:
- 预处理:C预处理器处理
#include和宏定义,生成纯DTS文件。 - 编译:DTC(Device Tree Compiler)将DTS编译为DTB。
- 反编译:DTB可反编译为DTS,用于调试和验证。
# 编译DTS为DTB
dtc -I dts -O dtb -o output.dtb input.dts
# 反编译DTB为DTS
dtc -I dtb -O dts -o output.dts input.dtb
# 带调试信息的编译(显示行号)
dtc -I dts -O dtb -o output.dtb input.dts -@
# 检查DTB语法
dtc -I dtb -O dts input.dtb | head -50
编译技巧:使用
-@选项生成符号节点,允许在运行时通过overlay动态加载设备树片段。网关开发中常用此特性实现外设热插拔。
2.5 设备树包含与覆盖机制
实际项目中,设备树采用分层设计:SoC级.dtsi文件定义通用硬件,板级.dts文件通过#include引入并覆盖特定属性。
// am33xx.dtsi (SoC级)
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/am33xx.h>
/ {
ocp {
#address-cells = <1>;
#size-cells = <1>;
gpio0: gpio@44e07000 {
compatible = "ti,am3359-gpio";
reg = <0x44e07000 0x1000>;
interrupts = <96>;
#gpio-cells = <2>;
status = "disabled";
};
};
};
// gateway-board.dts (板级)
#include "am33xx.dtsi"
&gpio0 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&gpio0_pins>;
};
&ocp {
gpio-leds {
compatible = "gpio-leds";
led0: led-0 {
label = "gateway:green:status";
gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
};
};
};
2.6 常见错误与调试方法
| 错误类型 | 现象 | 解决方案 |
|---|---|---|
| 语法错误 | DTC报错"Error: syntax error" | 检查分号、花括号是否匹配,属性值格式是否正确 |
| 地址冲突 | 内核启动时"Failed to request resource" | 检查reg地址是否与其他设备重叠 |
| 中断号错误 | 驱动probe成功但中断不触发 | 确认interrupt-parent指向正确的中断控制器 |
| compatible不匹配 | 驱动未加载,/sys/bus/platform/devices下无设备 | 核对驱动of_match_table中的字符串是否完全一致 |
| 属性未生效 | 驱动读取属性返回默认值 | 使用dtc -I fs -O dts /proc/device-tree查看实际生效的设备树 |
调试命令集:
# 查看内核实际使用的设备树
dtc -I fs -O dts /proc/device-tree | less
# 检查特定节点属性
cat /proc/device-tree/gpio@44e07000/compatible
# 查看设备树内存占用
cat /proc/device-tree/memory/reg | xxd -p
# 验证DTB文件完整性
dtc -I dtb -O dts -o /dev/null input.dtb
2.7 本章小结
设备树是嵌入式Linux硬件抽象的核心机制。通过本章学习,应掌握:
- DTS语法基础:节点定义、属性赋值、标签引用
- 三大标准属性:compatible(驱动匹配)、reg(地址空间)、interrupts(中断资源)
- 编译流程:DTS → DTC → DTB,以及反编译调试方法
- 分层设计:.dtsi与.dts的包含与覆盖机制