一句话,DTS是设备树源码,设备树的作用就是把「板级硬件信息」从内核代码剥离出来。/proc/device-tree是内核启动解析完 DTB 之后,把设备树整个树形结构,虚拟成文件系统。下面系统讲解:
一、DTS是什么?
1.1 核心定义
DTS = Device Tree Source(设备树源码)
DTB = Device Tree Blob(设备树二进制,编译后给内核加载)
DTSI = 设备树公共头文件,类似 C 语言
.h,被多个 DTS 引用
1.2 解决的历史痛点
老式 Linux:所有硬件引脚、寄存器、中断、时钟、GPIO、外设,全部硬写在内核驱动代码里。
缺点:换一块板子、改一个 GPIO,就要改内核源码、重新编译内核。
1.3 设备树作用
把「板级硬件信息」从内核代码剥离出来,单独写到 DTS 配置文件里:
- 哪个 GPIO 做按键 / LED
- 外设寄存器地址、中断号
- 电源、时钟、Pinctrl 引脚复用
- I2C/SPI/UART 挂载设备
- 硬件上下拉、电平极性
一句话:驱动管逻辑,DTS 管硬件接线。
二、DTS核心语法
2.1 基础结构
leds {
compatible = "gpio-leds"; //内核会绑定到
gpio-leds驱动status_led {
label = "status-led"; //用户空间看到的名字
gpios = <&gpio1 5 0>; //本质用 gpio1 的第 5 号引脚控制 LED
default-state = "on"; //上电默认状态(on || off || keep)
};
};
2.2 DTS中的一些关键属性
①compatible(最重要,没有之一),内核会用它去找驱动里的,匹配成功 → 执行 probe
②status(开关),"okay"->启用,"disabled"->禁用。很多"设备不工作"其实是忘记启用。
③reg(地址),驱动会用它做:ioremap、寄存器访问
④interrupts(中断),告诉驱动这个设备用哪个中断
⑤gpios,用 GPIO 控制设备,比如LED、reset脚、中断脚
⑥#address-cells / #size-cells,决定
reg怎么解析,address-cells(地址占几个 cell),size-cells(长度占几个 cell)
2.3 引脚控制:pinctrl
pinctrl用来解决引脚复用,同一个物理引脚,可以是 GPIO、UART、I2C、PWM、SPI。
DTS 通过
pinctrl节点定义引脚模式:
- 输入 / 输出
- 上拉 / 下拉 / 浮空
- 驱动能力
- 复用功能选择
2.4 别名&引用
&gpio、&i2c1这种是引用已有控制器节点,不用重复定义。这个在工作中如果用到dts的overlay机制应该会很常见。
三、DTS 编译流程
- 源码:
arch/arm/boot/dts/xxx.dts+ 依赖.dtsi- 编译工具:
dtc(设备树编译器)- 编译产物:
xxx.dtb二进制文件- 启动流程:
U-Boot 加载 DTB 到内存 → 启动 Linux 内核 → 内核解析 DTB → 创建设备、匹配驱动
四、/proc/device-tree
4.1 是什么?
内核启动解析完 DTB 之后,把设备树整个树形结构,虚拟成文件系统,挂载在:/proc/device-tree/
- 纯只读虚拟文件,断电消失
- 每一个 DTS 节点 = 一个文件夹
- 每一个 DTS 属性 = 一个文件
- 方便用户空间查看、调试、验证 DTS 配置是否生效
4.2 目录结构对应关系
DTS 里写了:
bash
/ {
model = "test-board";
gpio-keys {
compatible = "gpio-keys";
};
};
在系统里对应:
bash
/proc/device-tree/model
/proc/device-tree/gpio-keys/
/proc/device-tree/gpio-keys/compatible
五、日常开发排错实操技巧
- 改完 DTS 必看:
/proc/device-tree有没有对应节点- 驱动加载失败:优先
cat compatible核对字符串是否一致- GPIO / 按键不生效:看 DTS pinctrl 是否正确、看
/proc/device-tree引脚属性- 不想改内核:只改 DTS + 重新编译 dtb,快速调试硬件