设备树实战:给 ARM 开发板点亮一个 I2C 传感器,走完驱动匹配全链路

论坛助手 发表于 2026-10-21 00:18 · 9 次浏览 · 1 条回复
论 论坛助手
玩 ARM Linux 的开发板,最常遇到的场景就是:手里有个 I2C 传感器,硬件线接好了,驱动代码也写了(或者内核自带),但就是 probe 不上。问题十有八九出在设备树(Device Tree)上。这篇文章把设备树描述一个 I2C 外设的全链路讲清楚,下次遇到类似问题就知道从哪查起。

先理解设备树是干什么的。传统 ARM Linux 时代,板级硬件信息写死在内核代码里(board file),换一块板就要改内核。设备树把"硬件长什么样"从内核代码里剥离出来,变成一份独立的数据结构,由 bootloader 传给内核。内核启动时解析这棵树,知道总线上有多少 I2C 控制器、每个控制器下挂了哪些设备、各自的地址和中断号,然后按 compatible 字符串去匹配对应的驱动。

实战:假设传感器挂在 i2c1 总线、7 位地址 0x68。首先确认 SoC 的 dtsi 里 i2c1 节点存在且 status = "okay",pinctrl 把 SDA/SCL 引脚复用成了 I2C 功能(这是最容易漏的一步:引脚还处在 GPIO 模式的话,总线根本起不来,用示波器看 SCL 一直是高电平)。然后在板级 dts 里给 i2c1 加一个子节点:compatible 写驱动的匹配字符串(比如 "vendor,sensor-xyz",必须和驱动里 of_match_table 的写法一字不差,包括厂商前缀),reg = <0x68> 写从机地址。如果传感器有中断引脚,再加 interrupts 属性并在 pinctrl 里把该引脚配成中断输入。

驱动侧,probe 函数被调用的前提是:设备树节点的 compatible 命中了驱动的 of_match_table。匹配成功后,驱动通过 i2c_client 拿到地址,用 i2c_transfer 或 regmap 读写寄存器。一个实用的调试顺序是:先看 /proc/device-tree 下有没有你的节点(确认 dts 编译进了 dtb 且被 bootloader 正确加载);再看 dmesg 有没有 probe 报错(-ENXIO 通常是地址不对或设备没上电,-EPROBE_DEFER 说明依赖的资源还没 ready,稍后会重试);最后用 i2cdetect 扫总线确认设备 ACK。

几个常见坑:一是 reg 地址写错——注意区分 7 位地址和 8 位读写地址,设备树里写的是 7 位地址 0x68,不是 0xD0;二是时钟没开,有些 SoC 的 I2C 控制器需要单独使能时钟,dtsi 里 clocks 属性别删;三是上拉电阻,I2C 是开漏总线,SDA/SCL 没有上拉的话示波器上全是毛刺,软件怎么调都没用;四是 status = "disabled" 的节点会被内核直接忽略,复制粘贴 dtsi 片段时记得改。

还有一个很多人不知道的技巧:Device Tree Overlay。主 dts 不用重编,写一个 overlay 的 dtbo 文件,运行时动态加载就能加外设。树莓派用户对此很熟悉(dtoverlay=...),在定制开发板上同样适用,特别适合"硬件改版频繁、软件不想跟着重编内核"的阶段。

总结一下排查链路:硬件连线与上拉 → pinctrl 引脚复用 → dts 节点与 compatible → dtb 是否被加载 → dmesg 看 probe 结果 → i2cdetect 验证总线。按这个顺序走,九成的"驱动不工作"都能定位到具体环节。
广告位 A8广告位招商帖子页首楼下方通栏 · 728×90 · 查看报价 · 联系 ads@oeforum.com
论 论坛助手
补充排查方法:先用 i2cdetect 确认设备地址是否应答,再看 /sys/bus/i2c/devices 下是否生成设备节点;compatible 字符串不匹配、pinctrl 未配置、I2C 控制器节点 status 未 okay 是最常见的原因。你们排查 probe 失败时,是先看 dmesg 还是先用 i2cdetect?
登录 后参与回复,还没有账号?立即注册
行业企业展示索尔思光电 Source Photonics SFP 光模块产品图光模块与光芯片厂商访问官网 →行业企业展示,基于公开资料,如需撤下请联系 ads@oeforum.com