3. I2C通信流程:起始条件、停止条件、数据有效性归纳总结
好了,咱们聊聊I2C最基础的那些事儿。很多做嵌入式的人,调了一两年I2C,遇到锁死还是傻眼。说白了,就是没把通信流程的底层逻辑吃透。我个人习惯,拿到一个新芯片的数据手册,第一件事不是看寄存器,而是先画它的通信流程图——起始条件在哪、停止条件在哪、数据什么时候才算有效。这步搞明白了,后面调驱动就是填空。
3.1 起始条件(Start Condition)
起始条件长什么样?记住一句话:SCL为高电平时,SDA从高跳变到低。就这一个边沿,总线上的所有从机就知道:主人要开工了。
为什么这样设计?因为SCL高电平期间,SDA上的数据是锁定的(我们马上会讲数据有效性),所以此时跳变不会被误解为数据位。嗯,这里要注意,很多锁死故障就是起始条件没发干净导致的。
delay_us确保SCL稳定在高电平。
起始条件的关键参数:
- SDA低电平保持时间:至少大于SCL低电平周期?不,标准规定
tHD:STA最小是4.7μs(100kHz模式)。我建议你按最坏情况留余量。 - 重复起始条件(Repeated Start):有时候你不想放弃总线,可以再发一次起始条件,代替停止条件。这个操作在复合读写时很常用,但也是锁死的重灾区——重复起始没发好,从机会以为你要停了。
3.2 停止条件(Stop Condition)
停止条件是起始条件的镜像:SCL为高电平时,SDA从低跳变到高。一旦出现这个边沿,所有从机都知道本次通信结束了,释放总线,准备迎接下一次。
你想想看,如果停止条件没发完整,从机一直以为总线还在占用状态,那它就不会释放SDA。这就造成了最经典的锁死场景:SDA被从机一直拉低,主机没办法再发起起始条件。
停止条件的时间参数同样重要:
| 参数 | 100kHz模式 | 400kHz模式 | 说明 |
|---|---|---|---|
| tSU:STO | 4.0μs | 0.6μs | 停止条件建立时间(SCL高后,SDA变为高前) |
| tBUF | 4.7μs | 1.3μs | 停止到下一次起始的最小空闲时间 |
我曾经在一个项目里遇到奇怪现象:同一批板子,有的能工作有的不能。后来发现是停止条件的tBUF留短了,主机连续操作时,从机还没来得及复位,新的起始条件就来了。结果呢?从机认错数据,产生总线冲突,最后锁死。
3.3 数据有效性(Data Validity)
这是很多工程师容易忽略的点。I2C有个硬性规定:SCL高电平时,SDA必须保持稳定;数据采样就在SCL的上升沿、或者高电平期间。只有在SCL低电平时,SDA才能变化。
说白了,你传输一个字节的8个位,每个位都是在SCL高电平时被采样的。如果SDA在SCL高电平期间抖了一下,哪怕就几纳秒的毛刺,接收方就会采样到一个错误值,严重时会导致地址错配、ACK混乱、然后锁死。
数据有效性的流程可以总结如下:
- SCL低电平 → 发送器改变SDA电平(允许变化)
- SCL上升沿 → 接收器采样SDA(必须稳定)
- SCL高电平保持 → 继续保持SDA不变(避免第二个边沿采样)
- SCL下降沿 → 准备下一个位
注意,ACK位也遵循相同的规则:主机在第9个SCL时钟释放SDA(拉高),从机如果准备应答,会在SCL高电平时拉低SDA。如果从机不拉低(NACK),SDA保持高电平——此时主机可以发停止或重复起始。
3.4 三要素归纳对比
我把它们放在一起对比,方便你记忆:
| 要素 | SCL电平 | SDA动作 | 发生时刻 | 故障后果(常见) |
|---|---|---|---|---|
| 起始条件 | 高 | 下降沿 | 通信开始前 | SDA被持续拉低,锁死 |
| 停止条件 | 高 | 上升沿 | 通信结束时 | 从机不释放总线,锁死 |
| 数据有效性 | 高(采样) | 必须不变 | 每个时钟高电平期间 | 数据错位、ACK混乱、锁死 |
3.5 通信流程全景图
下面我用一张SVG图,把起始、数据传送、停止的完整动线画出来。图中深色节点代表关键步骤,箭头指示流程方向,右侧说明框补充了每个节点的时序条件。
这个图很好地概括了整个流程:起始条件发起后,主机逐字节发送地址和读写位,每个字节后从机必须给出ACK,然后继续数据传输,最后主机发出停止条件结束会话。如果中途需要重新开始(比如从写切换为读),就重复起始条件,不走停止。
在实际调试中,我习惯用逻辑分析仪同时观察SCL和SDA,重点检查起始和停止条件是否满足“SCL高、SDA跳变”的时序。只要是锁死故障,十有八九是这俩条件没发对,或者数据有效性被违反——比如SCL高时SDA发生了不该有的毛刺。把这些基础功练扎实了,后面讲锁死故障的解码技巧,你才能上手就用。