4. RK I2C 驱动调试:从适配器到设备,再到时序与故障排查
I2C 总线在嵌入式系统里太常见了。传感器、触摸屏、PMIC、EEPROM……几乎每个项目都能碰到。瑞芯微 RK 系列平台的 I2C 控制器本身不复杂,但一旦出问题,排查起来往往让人头疼。
我个人习惯把 I2C 调试分成四个层面:适配器驱动、设备驱动、时序分析、故障排查。前两个是写代码,后两个是拿仪器和逻辑分析仪找问题。今天咱们就把这四个层面串起来讲。
4.1 I2C 适配器驱动:内核帮你做了大部分事
在 RK 平台上,I2C 适配器驱动通常由芯片厂商(Rockchip)提供,内核里已经写好了。你打开 drivers/i2c/busses/i2c-rk3x.c 就能看到。
适配器驱动负责的事情很明确:
- 初始化 I2C 控制器的寄存器
- 配置时钟频率(100kHz、400kHz 等)
- 实现 master_xfer 回调函数
- 处理中断和 DMA 传输
我建议你拿到一个新板子,第一件事就是确认适配器驱动是否正常加载。方法很简单:
# 查看 I2C 总线是否注册成功
ls /dev/i2c-*
# 或者
i2cdetect -l
# 查看具体总线的设备树节点
cat /sys/bus/i2c/devices/i2c-0/name
如果 /dev/i2c-* 下面没有设备节点,说明适配器驱动没起来。这时候先别急着写设备驱动,回头检查设备树和时钟配置。
4.2 I2C 设备驱动:你的核心战场
适配器驱动是基础设施,设备驱动才是你真正要写的。以 RK3588 上挂载一个温度传感器为例,设备驱动通常长这样:
static const struct i2c_device_id temp_sensor_id[] = {
{ "tmp117", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, temp_sensor_id);
static const struct of_device_id temp_sensor_of_match[] = {
{ .compatible = "ti,tmp117" },
{ }
};
MODULE_DEVICE_TABLE(of, temp_sensor_of_match);
static struct i2c_driver temp_sensor_driver = {
.driver = {
.name = "tmp117",
.of_match_table = temp_sensor_of_match,
},
.probe = temp_sensor_probe,
.id_table = temp_sensor_id,
};
module_i2c_driver(temp_sensor_driver);
这里有几个关键点:
- compatible 字符串必须和设备树里一致,大小写都不能错
- probe 函数里要完成设备初始化、注册 hwmon 或 input 子系统
- id_table 用于非设备树方式匹配,建议也写上
我见过最坑的问题是什么?设备树里 reg 地址写错了。比如传感器地址是 0x48,你写成了 0x49,内核匹配不到设备,probe 函数根本不会调用。
4.3 I2C 时序分析与逻辑分析仪抓包
写代码只是第一步。代码写完了,设备不工作,这时候就要上逻辑分析仪了。
我个人的调试流程是这样的:
- 先看波形:用逻辑分析仪抓 SCL 和 SDA 两根线
- 检查起始条件:SCL 高电平时 SDA 从高到低跳变
- 检查地址字节:7 位地址 + R/W 位,看是否和预期一致
- 检查 ACK/NACK:第 9 个 SCL 时钟,SDA 是否被从设备拉低
- 检查数据字节:每个字节的 MSB 先发,数据是否正确
- 检查停止条件:SCL 高电平时 SDA 从低到高跳变
下面这张图展示了 I2C 一次完整传输的时序结构:
逻辑分析仪抓包时,我习惯用 Saleae 或者开源的 PulseView。采样率设到 4MHz 以上,触发条件设成 SCL 下降沿。抓到的波形直接解码,一眼就能看出问题。
4.4 常见 ACK/NACK 故障排查
ACK/NACK 问题是 I2C 调试里最常见的故障。说白了,就是从设备不回应你。
我总结了几种典型场景:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 地址阶段 NACK | 设备地址错误、设备未上电、I2C 总线被拉死 | 核对设备树 reg、测量 VDD 电压、检查 SCL/SDA 电平 |
| 数据阶段 NACK | 从设备不支持该寄存器、写保护、时序超时 | 查看 datasheet 寄存器列表、检查写保护引脚、降低频率 |
| 偶发 NACK | 总线干扰、时钟拉伸超时、电源噪声 | 加长超时时间、增加重试次数、示波器看电源纹波 |
| 一直 NACK | I2C 控制器配置错误、GPIO 复用不对 | 检查 pinctrl 配置、确认 iomux 寄存器 |
4.5 调试工具链:i2c-tools 是你的好帮手
在写设备驱动之前,我强烈建议先用 i2c-tools 验证硬件通路。这是最直接的方法:
# 扫描总线上的设备
i2cdetect -y 0
# 读取设备寄存器
i2cget -y 0 0x48 0x00 w
# 写入设备寄存器
i2cset -y 0 0x48 0x01 0x3F
# 连续转储
i2cdump -y 0 0x48
如果 i2cdetect 能扫到设备,说明硬件连接和适配器驱动都没问题。如果扫不到,先别急着写驱动,回头查硬件。
4.6 调试流程总结
最后,我把整个调试流程画成一张决策图,方便你对照排查:
这张图是我自己调试时用的路线图。你照着走一遍,90% 的 I2C 问题都能定位到。
剩下的 10% 是什么?嗯,往往是硬件设计问题——上拉电阻阻值不对、PCB 走线过长、电平不匹配。这些就需要你拿着示波器,一根一根线去量了。