原帖 | Jack | 2025-01-07 12:38 | 👍1 | 阅读约1
嵌入式Linux调试iic
分享最近遇到一个 i2c 问题
问题背景:这路 i2c 接的电量计,电量计芯片内部有很多 task 要跑,所以会用到 i2c 时钟延展特性:在传输过程中,允许从机在自己忙的时候拉低 SCL,迫使主机进入等待状态。
问题现象:在 uboot 阶段,有时钟延展,但是延展阶段有一个300mV的半高电平,因为从机下拉能力弱,上拉电阻和下拉电阻分压导致。这种处理方式一般是增大上拉电阻,半高电平可以降低。在 uboot 阶段修改内部上拉电阻,可以按照预期变化。
但是一旦进了 kernel,发现这个半高电平变成了800mV,虽然对通信没影响,但是时序不符合 sepc,所以要查。
针对进入 kernel 以后的 800mV 半高电平审查,发现一旦进了 kernel,SCL 和 SDA 的波形变得非常陡峭,也就是主机端驱动能力很强,所以从机拉不下来。主机端修改 kernel 阶段的内部上拉电阻,发现没有任何效果。
打印出 uboot 阶段和 kernel 阶段的 i2c 控制器寄存器进行对比,发现 i2c 用的两个 PIN 进 kernel 变成了 push-pull,而不是 open-drain 开漏。原因是以往项目这路 i2c 接的外设跑的是 3.4M,这个速度 PIN 是推挽模式,需要在本项目改成开漏。
检查过程中,容易误导人的点:
1.波形上 SCL 的时钟延展有200mV半高电平,但是 SDA 上从机拉的 ACK bit 半高电平是正常的,产生了一定的误导。
2.修改推挽输出的位置很隐蔽,不在 dts 里面,而是用其他手段附加上去的。只有把运行时设备树捞出来,才发现有这个属性配置(运行时设备树的获取方法见 设备树反编译调试)。
3.一开始一直在纠结上拉电阻阻值的修改是否生效,耽误了时间。
相关笔记
- 📁 返回本主题 MOC
- 从MCU转Linux BSP开发
- Linux Android GT911触控调试
- Linux 电容多点触摸驱动开
- Linux BSP问题闭环流程
- 老师,学习Android Camera架构时
- 同样是做 Linux BSP 驱动,在芯片原厂和终端厂有什么不一样