1、设备树入门:什么是设备树?为什么需要设备树?设备树在Linux系统中的角色
各位同学,咱们今天聊聊设备树。
说实话,我刚入行那会儿,Linux内核里还没有设备树这东西。那时候写驱动,板级信息全写在 arch/arm/mach-xxx 下面,一个板子一个文件,改个GPIO都得重新编译内核。后来我接手一个项目,要同时支持三块不同配置的开发板,那叫一个痛苦。嗯,设备树就是来解决这个问题的。
什么是设备树?
设备树(Device Tree),说白了就是一个描述硬件信息的文本文件。
它用树形结构来描述:
- CPU 有几个核
- 内存地址范围
- 外设挂在哪个总线上
- 中断号、GPIO号、时钟频率
- 等等等等
你想想看,以前这些信息是硬编码在C代码里的。换一块板子,就得改代码、重新编译。有了设备树,硬件描述和内核代码就分开了。内核只需要解析设备树,就能知道当前跑在什么硬件上。
核心思想:设备树 = 硬件配置的「说明书」。内核读说明书,不猜硬件。
设备树的文件后缀是 .dts(Device Tree Source),编译后变成 .dtb(Device Tree Blob),内核启动时加载它。
为什么需要设备树?
我总结三个最直接的原因:
- 解耦硬件与驱动 —— 驱动代码不再关心板级差异。同一个驱动,换个设备树就能适配不同板子。
- 减少内核分支 —— 以前每个开发板都要维护一个
board-xxx.c,内核里塞了几百个这样的文件。设备树一出,这些文件全砍了。 - 启动时动态适配 —— bootloader 可以修改设备树,比如调整内存大小、关闭某个外设。内核不用重新编译。
我记得有一次,客户临时要求换一颗Flash芯片,引脚完全兼容,但容量不同。我改了一下设备树里的 reg 属性,重新打包 .dtb,十分钟搞定。要是以前,得改 board-xxx.c,重新编译内核,再烧录,至少半天。
小提示:设备树不是Linux独有的。U-Boot、FreeBSD、甚至一些RTOS也支持设备树。学会它,一通百通。
设备树在Linux系统中的角色
咱们来看一张图,你就明白了。
流程其实很简单:
- 硬件是客观存在的,设备树是它的「翻译官」。
- 内核启动时,读取设备树,知道有哪些设备、怎么访问。
- 驱动根据设备树里的信息,去初始化对应的硬件。
举个例子。你写一个LED驱动,以前你得知道LED接在哪个GPIO上,写死在代码里。现在呢?设备树里写:
leds {
compatible = "mycompany,myled";
led-gpios = &gpio1 3 GPIO_ACTIVE_HIGH;
};
驱动里只需要读 led-gpios 这个属性,就能拿到GPIO号。板子变了,改设备树就行,驱动代码不用动。
注意:设备树不是万能的。它只描述硬件「有什么」、「在哪」,不描述「怎么用」。怎么用,还是驱动的事。
设备树的核心概念(快速扫一眼)
| 概念 | 说明 | 我的一点经验 |
|---|---|---|
| 节点(node) | 一个硬件设备或总线 | 每个节点就是一个「设备对象」 |
| 属性(property) | 描述节点的信息 | 比如地址、中断号、时钟频率 |
| compatible | 驱动匹配的关键字 | 驱动靠它找到对应的设备 |
| reg | 寄存器地址和长度 | 告诉驱动「去哪读写」 |
| interrupts | 中断号 | 中断控制器和中断号配对 |
你可能会问:「这么多概念,怎么记?」
我的建议是:先别死记。后面几章我们会手把手写一个完整的设备树,从零到一。你跟着写一遍,自然就记住了。
避坑指南:我曾经犯过一个低级错误——设备树里写错了 reg 的地址范围,结果驱动读写时访问了非法内存,系统直接死机。排查了半天才发现是设备树的问题。所以,写设备树一定要仔细核对硬件手册的地址。
小结
设备树不是什么高深的东西。它就是一份硬件配置清单,让内核知道「我在什么板子上跑」。
你想想看,没有设备树的时候,每换一块板子就要改内核代码、重新编译。有了设备树,改个文本文件就行。这就是它的价值。
嗯,这一章先讲到这里。下一章我们开始动手写第一个 .dts 文件,到时候你就知道设备树到底长什么样了。