1. 课程导入

在嵌入式 Linux 与 SoC 开发中,设备树(Device Tree)早已不是“可选项”,而是连接硬件描述与内核驱动的关键契约。外设 Bring-up 工程则决定了这块板子能否从“能启动”走到“能工作”。本课程围绕这两条主线展开,目标是让你具备从硬件手册、原理图到设备树节点、驱动匹配、外设验证的完整闭环能力。

一、学习目标:从“看懂”到“改通”

本课程不满足于让你背诵设备树语法,而是要求你能够独立完成以下任务:

  • 读懂 SoC 参考手册中的地址映射、中断号、时钟与复位资源,并转化为设备树节点。
  • 掌握 compatible、reg、interrupts、clocks、pinctrl 等核心属性的语义与匹配机制。
  • 能够使用 dtc、fdtdump、/proc/device-tree 等工具定位设备树问题。
  • 完成 I2C、SPI、GPIO、UART 等常见外设的 Bring-up,并输出可复现的验证日志。
  • 建立“硬件—设备树—驱动—用户空间”四层联调思维,减少盲目试错。

核心判断标准:当外设不工作时,你能在 30 分钟内判断问题出在硬件供电、引脚复用、设备树节点、驱动匹配还是用户空间配置,而不是反复重启板子。

二、核心概念:设备树不是“配置文件”,而是硬件描述契约

设备树本质上是一棵由节点和属性组成的层次化数据结构,由 bootloader 传递给内核。内核在启动时解析设备树,生成 device_node,再与驱动中的 of_device_id 表进行匹配,最终触发 probe。理解这条链路,是 Bring-up 工程的基础。

几个必须厘清的概念:

  • DTS/DTB:源文件与编译后的二进制,前者可读,后者被 bootloader 加载。
  • compatible:驱动匹配的“钥匙”,格式通常为 "vendor,device"。
  • reg:描述寄存器地址范围,包含地址和长度。
  • interrupt-parent 与 interrupts:描述中断控制器与中断号。
  • pinctrl:描述引脚复用与电气属性,是 Bring-up 中最容易出错的环节。
  • status:"okay" 或 "disabled",控制节点是否生效。

下面这张图展示了从硬件资源到用户空间设备的完整信号与数据流,也是本课程后续所有章节的骨架:

设备树与外设 Bring-up 全链路 硬件资源 SoC 手册 / 原理图 地址 / 中断 / 时钟 设备树 DTS compatible / reg pinctrl / status DTB 二进制 dtc 编译 bootloader 加载 内核解析 device_node of_match 匹配 驱动 probe platform_driver i2c/spi/gpio 驱动 设备实例 /dev/i2c-1 /sys/class/gpio 用户空间验证 i2cdetect / gpiod echo / cat / dmesg Bring-up 反馈:日志 / 示波器 / 寄存器回读 → 修正 DTS 与硬件配置 硬件描述 设备树源 编译加载 内核匹配 驱动 probe 设备节点 用户验证

三、整体框架:四层联调模型

Bring-up 工程最忌讳“跳层排查”。建议始终按以下四层顺序推进:

层级 关注对象 典型工具/文件 常见问题
硬件层 供电、时钟、复位、引脚 万用表、示波器、原理图 电压不足、时钟未使能、引脚复用错误
设备树层 节点、属性、status DTS、dtc、fdtdump reg 地址错误、中断号不匹配、pinctrl 缺失
驱动层 compatible 匹配、probe 顺序 dmesg、/sys/bus 驱动未编译、匹配失败、依赖资源未就绪
用户层 设备节点、权限、数据读写 i2cdetect、gpiod、echo/cat 节点未生成、权限不足、时序不满足

四、实战路线图:从点亮一颗 LED 到完整外设链路

课程将以一条“最小可行 Bring-up 链”贯穿始终,逐步扩展:

  1. 阶段一:环境与工具链。搭建交叉编译环境,掌握 dtc 反编译与 fdtdump 查看 DTB。
  2. 阶段二:GPIO 与 pinctrl。从点亮 LED 开始,理解引脚复用、电气属性与 gpio-leds 节点。
  3. 阶段三:I2C 外设。挂载传感器,完成地址扫描、寄存器读写与驱动匹配。
  4. 阶段四:SPI 与中断。引入中断触发、DMA 与高速数据采集。
  5. 阶段五:综合排障。用真实故障案例训练“四层定位法”。

建议:每完成一个外设,都保留一份 dmesg 日志、一份 DTS diff 和一份用户空间验证命令。这三样东西是后续排障的“证据链”。

五、常见误区与复盘

初学者最容易犯的错误,往往不是技术难度,而是顺序和习惯问题:

  • 误区一:先改驱动,后看设备树。实际上 80% 的 Bring-up 问题出在设备树或硬件配置。
  • 误区二:忽略 status 属性。节点写了但 status = "disabled",内核根本不会创建设备。
  • 误区三:pinctrl 只写 group,不写 function。引脚复用未生效,外设自然无信号。
  • 误区四:不保存基线。改坏 DTS 后无法回退,建议每次修改前备份并记录 diff。

排障口诀:先供电,再时钟;先引脚,再节点;先匹配,再读写。任何一步跳过,都会让后续调试成本成倍增加。

下面是一段典型的 Bring-up 验证命令序列,建议在每次外设调试时按顺序执行:

# 1. 查看设备树节点是否生效
ls /proc/device-tree/ | grep i2c

# 2. 查看内核匹配日志
dmesg | grep -i "i2c\|probe\|failed"

# 3. 扫描 I2C 总线上的设备
i2cdetect -y 1

# 4. 读取寄存器验证通信
i2cget -y 1 0x48 0x00

# 5. 查看 GPIO 状态
gpiodetect
gpioinfo

本课程的核心不是记住多少属性名,而是建立一套可复用的 Bring-up 方法论:硬件确认 → 设备树描述 → 内核匹配 → 用户验证 → 反馈修正。当你把这套闭环跑通,面对任何新板子、新外设,都能快速定位问题边界,而不是在黑暗中反复试错。