关键词:设备树(Device Tree)、DTS、DTC、DTB、嵌入式Linux驱动开发
为什么需要设备树?
在旧版Linux内核中,硬件信息(如内存映射、外设地址、中断号等)直接硬编码在内核源码中。这导致:
-
内核臃肿,需为不同硬件编译不同版本
-
硬件变动需重新编译内核
-
代码冗余严重(一个
board-*.c
文件对应一块开发板)
设备树(Device Tree)的引入彻底解决了这一问题!它通过描述硬件拓扑结构的文本文件(.dts
),将硬件配置与内核代码分离。
设备树是什么?
1. 核心概念
-
硬件描述文件:用树形结构描述CPU、内存、总线、外设等硬件信息
-
不依赖编程语言:采用人类可读的文本格式(类似JSON)
-
独立于操作系统:由Bootloader(如U-Boot)传递给内核
2. 设备树文件类型
扩展名 |
类型 |
说明 |
|
设备树源文件 |
人类可读的文本描述 |
|
设备树头文件 |
可被多个 |
|
设备树二进制文件 |
由 |
设备树语法详解
1. 基础结构
// 示例:描述一个UART控制器
/ {
model = "MyBoard";
compatible = "myboard,v1";
uart0: serial@10000000 {
compatible = "ns16550a";
reg = <0x10000000 0x1000>; // 起始地址0x10000000, 长度4KB
interrupts = <10>; // 中断号10
clock-frequency = <1843200>;// 时钟频率
};
};
2. 关键语法元素
语法 |
作用 |
示例 |
|
根节点 |
|
|
设备节点 |
|
|
节点属性(键值对) |
|
|
节点引用标识符 |
|
|
引用其他节点 |
|
3. 常用属性解析
-
compatible
:驱动匹配的关键字"厂商,设备型号"
(如"ti,omap3-uart"
) -
reg
:设备寄存器地址和长度<起始地址 长度>
-
interrupts
:设备使用的中断号 -
status
:设备状态("okay"
,"disabled"
)
设备树如何工作?
编译与使用流程
编译:
传递: U-Boot通过bootm <kernel_addr> - <dtb_addr>
命令传递dtb给内核
内核解析: 内核启动时解析dtb,根据compatible
匹配驱动
实战:添加一个LED设备
步骤1:修改设备树文件(.dts)
/ {
leds {
compatible = "gpio-leds";
led0 {
label = "sys_led";
gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; // 使用GPIO0_15
linux,default-trigger = "heartbeat";
};
};
};
步骤2:驱动中获取设备树信息
#include <linux/of.h>
static int led_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
int led_gpio;
// 从设备树读取gpio号
led_gpio = of_get_named_gpio(np, "gpios", 0);
gpio_request(led_gpio, "sys_led");
...
}
static const struct of_device_id leds_ids[ ] = {
{ .compatible = "gpio-leds" }, // 匹配设备树中的compatible
{ }
};
MODULE_DEVICE_TABLE(of, leds_ids);
调试技巧
1. 查看解析后的设备树
# 内核启动后查看设备树
ls /proc/device-tree/
# 详细查看节点属性
cat /proc/device-tree/soc/i2c@4000000/clock-frequency
2. 反编译dtb(调试必备)
# 将dtb转回dts(方便检查)
dtc -I dtb -O dts -o recovered.dts myboard.dtb
常见问题解答(FAQ)
Q1:设备树修改后驱动不生效?
-
确认
.dtb
文件已更新到开发板 -
检查
compatible
字符串是否与驱动一致 -
使用
of_dump_status
检查节点状态
Q2:如何覆盖设备树中的配置?
在板级.dts
文件中重写节点:
// 原始配置在common.dtsi中
#include "common.dtsi"
&uart0 {
status = "disabled"; // 关闭该UART
};
Q3:设备树和ACPI有何区别?
设备树 (DT) |
ACPI |
主要用于ARM嵌入式系统 |
主要用于x86桌面/服务器 |
静态描述硬件 |
支持动态硬件配置 |
由Bootloader传递给内核 |
由BIOS/UEFI提供 |
总结
-
✅ 设备树 = 硬件的“身份证”:统一描述硬件配置
-
✅ 解耦硬件与驱动:无需为每块板子重编内核
-
✅ 开发重点:编写正确的
.dts
+ 驱动中正确解析属性
学习建议:从修改现有开发板的设备树入手,添加简单设备(如LED、按键),逐步深入复杂外设(I2C、SPI设备)。