I2C通信DMA传输与CPU负载故障定位实战 - 第1节

1.1 I2C 总线物理层——两根线怎么搞定一切?

I2C 总线,说白了就是两根线:SCL(时钟线)和SDA(数据线)。很多刚入行的工程师会问:就两根线,能传数据还能挂多个设备?

嗯,这里的关键在于——这两根线都是开漏输出,外部必须接上拉电阻。我刚开始做硬件时,就吃过这个亏。板子调了两天,I2C 死活不通,最后发现是上拉电阻焊错了封装,4.7kΩ 焊成了 47Ω。你想想看,47Ω 能把总线拉成什么样?SCL 波形都快成一条直线了。

核心要点:I2C 总线是“线与”结构。任何设备都可以拉低总线,但只有主机才能控制时钟。

上拉电阻怎么选?

我个人习惯,标准模式(100kHz)用 4.7kΩ,快速模式(400kHz)用 2.2kΩ。但这不是死规矩,得看总线电容。

总线电容 推荐上拉电阻(100kHz) 推荐上拉电阻(400kHz)
≤ 100pF 4.7kΩ 2.2kΩ
100pF ~ 200pF 3.3kΩ 1.5kΩ
200pF ~ 400pF 2.2kΩ 1.0kΩ
避坑指南:我曾经在一个项目里,总线上挂了 8 个从设备,线长超过 30cm。用 4.7kΩ 上拉,400kHz 模式下 SCL 上升沿直接超过 300ns,从设备根本不认。后来换成 1.5kΩ,问题解决。记住:总线电容越大,上拉电阻就要越小。

1.2 起始条件与停止条件——通信的“握手”与“再见”

I2C 通信的开始和结束,不是靠电平高低,而是靠时序组合。这一点和 SPI 完全不同,SPI 靠片选信号,I2C 靠的是 SDA 和 SCL 的配合。

起始条件(START Condition)

SCL 为高电平时,SDA 从高电平跳变到低电平。这就是起始条件。

我见过不少新手,写代码时先拉低 SCL,再拉低 SDA。这其实是错的。起始条件的核心是:SCL 高电平时,SDA 发生下降沿。顺序不能乱。

停止条件(STOP Condition)

SCL 为高电平时,SDA 从低电平跳变到高电平。这就是停止条件。

为什么要有这两个条件?说白了,就是为了让总线上的所有设备都知道:“我要开始说话了”和“我说完了”。没有这两个条件,从设备根本不知道什么时候该听、什么时候该睡。

调试技巧:用逻辑分析仪抓 I2C 波形时,先看起始条件和停止条件对不对。如果这两个条件都错了,后面的数据解析全是白费。我每次调 I2C,第一件事就是看 START 和 STOP 的时序。

1.3 数据有效性——什么时候读数据?

I2C 的数据有效性规则很简单:SCL 高电平时,SDA 上的数据必须稳定。数据变化只能在 SCL 低电平时发生。

你想想看,如果 SCL 高电平时 SDA 还在跳变,那从设备该在哪个时刻采样?所以这个规则是 I2C 通信的基石。

我记得有一次调试一个温湿度传感器,读出来的数据总是跳变。用示波器一看,SDA 在 SCL 高电平时有毛刺。查了半天,发现是 PCB 走线太长,信号反射造成的。加了个 33pF 的小电容滤波,问题解决。

数据有效性规则:
  • SCL = 高电平 → SDA 数据必须稳定(从设备在此采样)
  • SCL = 低电平 → SDA 数据可以变化(主机在此更新数据)

1.4 应答机制——从设备说“收到”还是“没收到”

I2C 的应答机制,是它比 SPI 更可靠的原因之一。每次主机发送完 8 位数据后,会释放 SDA,然后产生第 9 个 SCL 时钟。从设备如果拉低 SDA,表示ACK(应答);如果保持高电平,表示NACK(非应答)。

ACK 和 NACK 的含义

信号 SDA 状态(第 9 个 SCL) 含义
ACK 低电平 从设备已收到数据,可以继续发送
NACK 高电平 从设备未准备好、数据错误或传输结束

为什么会收到 NACK?常见原因有:

  • 从设备地址不对(地址不匹配)
  • 从设备正忙(比如还在处理上一条指令)
  • 主机发送了不支持的寄存器地址
  • 从设备接收缓冲区已满
避坑指南:我曾经在一个项目中,I2C 读操作总是卡在第一个字节后收到 NACK。查了三天,最后发现是从设备的读操作需要先发送寄存器地址,然后重新发送起始条件才能读数据。我漏掉了那个“重复起始条件”。记住:I2C 读操作不是直接读,而是“写地址 → 重复起始 → 读数据”的流程。

1.5 本章知识体系总览

下面这张图,把 I2C 协议基础的核心逻辑串起来了。从物理层到应答机制,每一步都是环环相扣的。

I2C 协议基础核心逻辑 物理层 SCL + SDA 开漏输出 上拉电阻 4.7kΩ/2.2kΩ 起始条件 SCL高→SDA下降沿 数据有效性 SCL高时SDA稳定 应答机制 第9个SCL时钟 ACK(低) / NACK(高) 停止条件 SCL高→SDA上升沿 💡 调试要点: 1. 先看起始条件:SCL高时SDA下降沿是否干净? 2. 再看数据有效性:SCL高时SDA有没有毛刺? 3. 最后看应答:第9个SCL时钟SDA是否被拉低? 4. 停止条件:SCL高时SDA上升沿是否完整?

这张图把 I2C 协议基础的五个核心模块串起来了。从物理层的两根线开始,到起始条件、数据有效性、应答机制,最后以停止条件结束。每个环节出问题,通信就会失败。

我的调试习惯:拿到一块新板子,先测 I2C 总线空闲状态——SCL 和 SDA 都应该是高电平。如果有一根线是低电平,说明有设备在占用总线,或者上拉电阻没焊好。这个检查只要 10 秒钟,但能省下半天排查时间。