当前位置: 首页 > news >正文

【Linux驱动开发】第11天:设备树(Device Tree)超详细全解:从诞生背景到工作原理

一、设备树的诞生背景:传统驱动的致命痛点

在设备树出现之前(Linux 3.0之前),Linux内核采用硬编码的方式描述所有硬件信息。这意味着:

  • 每一个开发板的寄存器地址、中断号、GPIO号,都直接写死在驱动代码里
  • 换一个开发板,哪怕只是GPIO号变了,也要修改驱动代码重新编译
  • 为了支持不同的开发板,内核里充斥着大量重复的、针对特定硬件的代码

最直观的例子:ARM内核的"灾难"

ARM架构有上百种不同的芯片、上千种不同的开发板。在设备树出现之前:

  • 每一个开发板都需要在内核里添加一份自己的硬件描述代码
  • 内核代码量爆炸式增长,变得无比臃肿
  • 维护成本极高,每一个新开发板都需要内核开发者手动添加支持
  • 一个内核镜像只能支持一个开发板,无法做到"一个镜像跑遍所有开发板"

设备树的诞生

2011年,Linux 3.1内核正式引入设备树机制,彻底解决了这个问题

设备树的核心思想非常简单:

把硬件描述信息从内核代码中完全抽离出来,用一个独立的、通用的文件来描述硬件。内核只需要一份通用的驱动代码,通过读取这个文件来识别不同的硬件。


二、设备树的核心定义

设备树(Device Tree,简称DT)是一种描述硬件资源的数据结构,它用树形结构来描述一个计算机系统的所有硬件设备,包括:

  • CPU
  • 内存
  • 总线控制器(I2C、SPI、USB等)
  • 外设(LED、按键、传感器、显示屏等)
  • 中断、时钟、电源等硬件资源

设备树的本质

设备树本质上是一个硬件的"清单",它告诉内核:

这个板子上有哪些硬件?它们的地址在哪里?它们用了哪个中断?它们的工作频率是多少?

注意:设备树不是驱动!它只描述"硬件是什么",不描述"怎么操作硬件"。操作硬件的逻辑仍然在驱动代码里。


三、设备树的三大核心组件:DTS、DTB、DTC

设备树体系由三个核心部分组成,三者分工明确,缺一不可。

1. DTS:设备树源文件(Device Tree Source)

  • 文件后缀.dts(主文件)、.dtsi(头文件)
  • 文件类型:纯文本文件,人类可读可编辑
  • 作用:用C语言风格的语法,描述硬件的所有信息
  • 编辑方式:任何文本编辑器都可以编辑
什么是.dtsi文件?

.dtsi是设备树头文件,相当于C语言的.h头文件,用于存放多个DTS文件共享的公共硬件信息

  • 比如同一个芯片的所有开发板,芯片内部的外设(CPU、内存、UART、I2C控制器等)是完全相同的
  • 这些公共信息可以放在一个.dtsi文件中(如stm32mp157.dtsi
  • 每个开发板自己的.dts文件只需要#include这个.dtsi,然后添加自己独有的硬件信息(如LED、按键、外接传感器等)
  • 大大提高了代码复用性,减少了重复代码

2. DTC:设备树编译器(Device Tree Compiler)

  • 文件类型:可执行程序
  • 作用:将人类可读的DTS文本文件,编译成内核能够识别和解析的二进制DTB文件
  • 同时也可以将DTB二进制文件反编译成DTS文本文件,用于调试

3. DTB:设备树二进制文件(Device Tree Blob)

  • 文件后缀.dtb
  • 文件类型:二进制文件,人类不可读
  • 作用:内核启动时加载并解析的最终文件
  • 特点:体积小、解析速度快,适合嵌入式系统使用

三者的关系和编译流程

开发者编写DTS源文件

#include 公共.dtsi头文件

DTC编译器编译

生成DTB二进制文件

烧录到开发板

bootloader加载DTB到内存

内核解析DTB,识别硬件


四、设备树的树形结构

设备树采用树形结构来描述硬件,和计算机的文件系统结构非常相似。

4.1 基本结构

/ (根节点) ├── cpu@0 (CPU节点) ├── memory@80000000 (内存节点) ├── soc@0 (片上系统节点) │ ├── uart@12340000 (串口节点) │ ├── i2c@12341000 (I2C控制器节点) │ │ ├── sensor@48 (I2C传感器节点) │ │ └── eeprom@50 (I2C EEPROM节点) │ └── gpio@12342000 (GPIO控制器节点) └── led@12343000 (LED节点)

4.2 核心概念:节点(Node)

  • 每个硬件设备对应设备树中的一个节点
  • 节点格式:节点名@地址 { ... };
    • 节点名:描述设备的类型,如cpumemoryuartled
    • @地址:设备的寄存器基地址,用于区分同类型的不同设备(如uart@12340000uart@12341000是两个不同的串口)

4.3 核心概念:属性(Property)

  • 每个节点包含多个属性,用于描述设备的具体信息
  • 属性格式:属性名 = 属性值;
  • 属性值可以是字符串、32位无符号整数、整数数组、字节数组等

4.4 最常用的核心属性(驱动开发每天都会用到)

属性名作用示例
compatible最重要的属性,用于和驱动匹配,格式为"厂商,设备名"compatible = "st,stm32-uart";
reg描述设备的寄存器地址范围,格式为<基地址 长度>reg = <0x12340000 0x1000>;
interrupts描述设备使用的中断号interrupts = <5>;
status描述设备状态,okay表示启用,disabled表示禁用status = "okay";
model设备的人类可读名称model = "STM32MP157 Development Board";

五、设备树的完整工作流程

设备树从编写到最终驱动硬件,会经历以下6个完整阶段。

阶段1:编写设备树源文件

开发者根据开发板的硬件原理图,编写DTS文件,描述所有硬件信息。

阶段2:编译生成DTB文件

使用DTC编译器将DTS文件编译成DTB二进制文件。

阶段3:bootloader加载DTB

系统启动时,bootloader(如U-Boot)会:

  1. 将内核镜像(zImage)加载到内存
  2. 将DTB文件加载到内存的另一个位置
  3. 启动内核,并将DTB的内存地址传递给内核

阶段4:内核解析DTB

内核启动时,根据bootloader传递的地址,解析DTB文件:

  1. 遍历DTB中的所有节点
  2. 为每个节点创建一个对应的platform_device结构体
  3. platform_device注册到platform总线

阶段5:总线匹配设备和驱动

platform总线会:

  1. 遍历所有已注册的platform_driver
  2. 比较设备的compatible属性和驱动的of_device_id
  3. 如果字符串完全一致,则匹配成功

阶段6:调用驱动的probe函数

匹配成功后,总线自动调用驱动的probe函数:

  1. 驱动从platform_device中获取硬件信息(地址、中断号等)
  2. 初始化硬件
  3. 注册字符设备/块设备/网络设备
  4. 创建设备文件,对外提供服务

六、设备树的核心优势

对比传统硬编码驱动,设备树具有以下不可替代的优势:

1. 硬件描述与驱动代码完全分离

  • 驱动代码通用,不需要针对特定开发板修改
  • 一个驱动可以支持所有符合compatible属性的设备
  • 新增硬件只需要修改设备树,不需要修改驱动代码

2. 一个内核镜像支持多个开发板

  • 内核镜像不再包含任何特定硬件的信息
  • 同一个内核镜像可以在所有支持设备树的开发板上运行
  • 只需要更换不同的DTB文件即可

3. 大大降低内核维护成本

  • 内核不再需要包含大量针对特定开发板的硬编码代码
  • 内核代码量大幅减少,更加简洁和通用
  • 新开发板的支持变得非常简单,只需要添加一个DTS文件

4. 支持热插拔

  • 设备树可以动态描述热插拔设备的信息
  • 设备插入时,内核动态解析设备树节点,创建设备并匹配驱动
  • 设备拔出时,自动调用驱动的remove函数释放资源

七、常见误区澄清

❌ 误区1:设备树可以代替驱动

错误。设备树只描述"硬件是什么",不描述"怎么操作硬件"。操作硬件的逻辑仍然在驱动代码里。没有驱动,设备树只是一个没用的文本文件。

❌ 误区2:设备树是ARM架构特有的

错误。设备树最早用于PowerPC架构,现在已经被所有主流架构采用,包括ARM、x86、RISC-V、MIPS等。

❌ 误区3:设备树只能描述片上外设

错误。设备树可以描述系统中的所有硬件,包括CPU、内存、总线控制器、外接设备、甚至电源和时钟。

❌ 误区4:设备树的compatible属性可以随便写

错误compatible属性必须严格按照"厂商,设备名"的格式编写,并且必须和驱动中的of_device_id表完全一致,否则无法匹配。


八、总结

设备树是现代Linux驱动开发的基础,它的核心价值在于实现了硬件描述与驱动代码的彻底分离,解决了传统硬编码驱动的所有致命痛点。

对于驱动开发者来说,你只需要记住:

  1. 设备树是硬件的清单,告诉内核有什么硬件
  2. 驱动是硬件的操作手册,告诉内核怎么操作硬件
  3. compatible属性是两者之间的配对暗号,暗号对上了,驱动才能工作

面试必背考点

  1. 什么是设备树?它解决了什么问题?
  2. DTS、DTB、DTC分别是什么?三者的关系是什么?
  3. 什么是.dtsi文件?它的作用是什么?
  4. 设备树的基本结构是什么?什么是节点和属性?
  5. compatible属性的作用是什么?格式是什么?
  6. 内核解析设备树的完整流程是什么?
  7. bootloader在设备树启动过程中起到什么作用?
  8. 设备树和platform驱动是怎么配合工作的?
http://www.jsqmd.com/news/862072/

相关文章:

  • 如何构建更接近真实交通的自动驾驶仿真世界:数字孪生、风险重构与物理感知全栈实践
  • 编译和链接+预处理
  • 从塑料感→博物馆级质感,Midjourney材质进阶全路径:Chaos=0.3+Texture Boost+--style raw三重锁频技术,限时公开
  • ElevenLabs高棉文语音私有化部署终极方案(含Docker+Khmer IPA音素映射表),仅限前200位技术负责人获取
  • 为什么这款文档转换工具能同时实现高效与精准?揭秘Marker的核心优势
  • 2026.5.12【芯片设计面试经验分享】上海车载芯片设计公司
  • 079.自监督学习预训练:在无标签数据上预训练YOLO骨干网络
  • ElevenLabs挪威文语音API调用全链路拆解,从HTTP头配置到SSML韵律标记实战,零基础30分钟上线商用级语音
  • rk3588/rk3576使用rkllm推理大模型,提供OpenAI服务
  • VCG Mesh平滑整形
  • AI赋能光伏电站智能运维:边缘计算网关如何成为运维中枢?
  • AI 的持续学习:从会话中提取可复用知识
  • 一文搞懂 Linux 驱动并发与竞争(学习笔记)
  • 2026年工业胶粘材料国产化趋势白皮书:PI 金手指胶带的高温性能与应用突破
  • 深入拆解 MySQL InnoDB 隔离级别:从 MVCC 到临键锁
  • Go语言内存管理:从tcmalloc到GC优化
  • 2026年AI写作辅助网站实测排行,哪款真正适合写论文?
  • AI 术语通俗词典:LSTM
  • 注释与常用快捷键
  • Harness Engineering:智能体异常处理机制
  • 080.领域自适应:当你的YOLO在新车间“水土不服”时
  • 算法28,前缀和,寻找数组中的中心下标
  • C语言06(操作符)
  • VxWorks网络通信模块:网络协议栈解析(第五部分)
  • 鸿蒙备考题库页面构建:错题本、小组榜单与备考提示模块详解
  • QQ家园迷你屋单机版下载:复刻05年经典网页社区,像素风直接拉满
  • ComfyUI全面掌握-知识点详解——ComfyUI 开发与扩展基础(开发指南+环境搭建)
  • 海量分布式储能节点云边协同架构:边缘网关异步心跳注册与状态上报Python实战
  • 输出函数print
  • 内存管理