3. 起始与停止条件:START与STOP信号的时序要求、波形识别与常见误触发分析
I2C 通信的起点和终点,就是 START 和 STOP 信号。这两个信号看似简单,但很多时序问题都出在这里。我调试过的板子里,至少有三分之一的不通,根源就是 START/STOP 没处理好。
3.1 信号的物理定义
先看最基础的定义。I2C 总线空闲时,SCL 和 SDA 都是高电平(通过上拉电阻拉高)。
- START 条件:SCL 为高电平时,SDA 从高电平切换到低电平。
- STOP 条件:SCL 为高电平时,SDA 从低电平切换到高电平。
说白了,就是 SCL 在高电平期间,SDA 跳变的那一下,决定了是开始还是结束。
关键记忆点:SCL 高电平期间,SDA 不能随意变化。只有在 SCL 低电平期间,SDA 才能改变数据。START 和 STOP 是唯一的例外。
3.2 时序参数要求
标准模式(100kHz)和快速模式(400kHz)的时序要求不同。我整理了一张表,方便你对照。
| 参数 | 符号 | 标准模式 (100kHz) | 快速模式 (400kHz) | 说明 |
|---|---|---|---|---|
| START 保持时间 | tHD;STA | 4.0 μs | 0.6 μs | SCL 下降沿之前,SDA 低电平需保持的时间 |
| START 建立时间 | tSU;STA | 4.7 μs | 0.6 μs | 重复 START 时,SCL 上升沿之后 SDA 低电平需保持的时间 |
| STOP 建立时间 | tSU;STO | 4.0 μs | 0.6 μs | STOP 条件前,SCL 高电平需保持的时间 |
| 总线空闲时间 | tBUF | 4.7 μs | 1.3 μs | STOP 到下一个 START 之间的最小空闲时间 |
我的习惯:做设计时,我一般会留 20% 的余量。比如标准模式,tHD;STA 我会做到 5 μs 以上。别卡着下限,温度一变、电压一抖,就容易出问题。
3.3 波形识别
用示波器抓波形时,怎么一眼看出 START 和 STOP?
- START 波形特征:SDA 先于 SCL 下降。你会在示波器上看到 SDA 先掉下去,SCL 还高高挂着,然后 SCL 才开始拉低。
- STOP 波形特征:SCL 先升到高电平,然后 SDA 从低电平升上去。注意,SDA 上升的时候,SCL 必须是高电平。
- 重复 START (Sr):在数据传输过程中,不发送 STOP,直接再发一个 START。波形上就是 SDA 在 SCL 高电平时又拉低了一次。
我记得有一次,一个同事抓到的波形怎么看都不对。SDA 和 SCL 几乎同时变化。后来发现是示波器的探头补偿没调好,导致信号边沿失真。嗯,这里要注意,探头补偿很重要。
3.4 常见误触发分析
误触发,就是总线没想发 START/STOP,但信号线上却出现了类似 START/STOP 的跳变。这是 I2C 故障里最头疼的一类。
3.4.1 噪声干扰导致误触发
总线上的毛刺,如果正好出现在 SCL 高电平期间,并且幅度足够大,就可能被从机误判为 START 或 STOP。
- 现象:通信时断时续,或者从机莫名其妙复位。
- 原因:电源噪声、地弹、或者相邻信号线的串扰。
- 解决:增加上拉电阻的阻值(但不能太大,否则上升沿变缓),或者在 SDA/SCL 上加小电容(10pF~100pF)滤波。
我曾经踩过的坑:有一块板子,I2C 总线走线太长,而且和一根高频时钟线平行走了 5cm。结果每次时钟线跳变,I2C 上就出现一个毛刺,正好在 SCL 高电平期间。后来把 I2C 走线改成包地处理,问题才解决。
3.4.2 上升沿过缓导致误触发
如果上拉电阻太大,或者总线电容太大,SDA 的上升沿会变得很缓。这时候,从机可能把缓慢的上升沿误判为多个跳变。
- 现象:从机检测到多个 START 条件。
- 原因:RC 时间常数太大,信号上升时间超过了从机的输入阈值窗口。
- 解决:计算总线的最大电容,选择合适的上拉电阻。一般 400kHz 时,上拉电阻选 2.2kΩ~4.7kΩ 比较稳妥。
3.4.3 从机复位导致误触发
从机在工作过程中突然复位,它的 I2C 接口会回到默认状态。如果此时 SDA 正好是低电平,从机复位后看到 SCL 高电平、SDA 低电平,就可能认为是一个 START 条件。
- 现象:主机发送数据后,从机没有响应,或者响应错误。
- 原因:从机电源不稳、看门狗复位、或者软件跑飞。
- 解决:确保从机电源稳定,复位引脚加去抖电容。主机侧可以增加超时重试机制。
3.5 波形调试实战
这里我画了一张流程图,帮你理清调试 START/STOP 问题的思路。
3.6 避坑指南
最后,分享几个我实际项目中遇到的坑。
- 坑一:重复 START 的保持时间。有些从机对重复 START 的 tHD;STA 要求更严格。我遇到过一款传感器,标准模式没问题,快速模式就偶尔丢包。后来发现是重复 START 的保持时间差了 0.1 μs。
- 坑二:STOP 后的总线空闲时间。有些主机在 STOP 后立刻发 START,没有留 tBUF。从机还没来得及释放总线,就会导致仲裁丢失。
- 坑三:多主机的 START 竞争。两个主机同时发 START,谁先拉低 SDA 谁就赢。输的那一方要退出。如果软件没处理好重试逻辑,总线就会死锁。
我的建议:写 I2C 驱动时,在发送 START 和 STOP 之后,加一个小的延时(比如 1 μs)。虽然会降低一点吞吐量,但能换来极高的稳定性。尤其是在产品初期,这个习惯能帮你省下大量调试时间。