第二讲:SCL和SDA信号时序分析——把心跳和呼吸看清楚

做I2C调试,说白了就是看两根线的时序对不对。SCL是时钟,SDA是数据,它们配合不好,设备就不说话。我刚开始修I2C总线时,总觉得时序就是几个时间参数,查手册照填就行——直到有一次,从设备死拽着SCL不放,我的逻辑分析仪愣是没看出来。

时钟拉伸,是I2C里最隐蔽的坑之一。想学会怎么揪出它,你得先把正常的SCL/SDA波形刻在脑子里。这一节,我带你从骨子里搞懂它们。

2.1 标准时序参数——I2C的“心电”指标

I2C协议定义了一组时间参数,决定了总线能跑多快、数据稳不稳。你想想看,如果SCL高电平时间太短,从设备可能来不及采样SDA;如果保持时间不够,起始条件可能被误解。下表是标准模式(100kHz)下的关键参数,我建议你记在本子上,调总线时随时回来对照。

参数符号标准模式最小值标准模式最大值说明
SCL时钟频率fSCL—100 kHz基本节奏
SCL高电平时间tHIGH4.0 μs—从设备干活时间
SCL低电平时间tLOW4.7 μs—主机等待时间
SCL上升时间tr—1000 ns受总线电容影响
SCL下降时间tf—300 ns主设备驱动能力
起始条件保持时间tHD:STA4.0 μs—SDA下降沿后SCL必须保持低
起始条件建立时间tSU:STA4.7 μs—重复起始前SCL高+1 SDA下降
数据保持时间tHD:DAT03.45 μsSCL下降后SDA保持
数据建立时间tSU:DAT250 ns—SDA先稳定,SCL再上升
停止条件建立时间tSU:STO4.0 μs—SDA上升前SCL先高
总线空闲时间tBUF4.7 μs—停止到下一次起始

我的习惯:拿到一个新I2C器件,第一件事就是把它的最小tHIGH和tLOW抄到调试笔记里。很多时钟拉伸问题,就是从设备内部处理慢了,需要主机把低电平时间拉长。你如果不知道器件要求的最低tLOW,就看不出来拉伸。

2.2 正常传输波形——SCL和SDA怎么“对话”

SCL和SDA的配合,有点像跳舞。我把一次完整的数据传输拆成几个动作:

  1. 空闲态:SCL和SDA都是高电平(上拉电阻拉高)。总线没人在占用。
  2. 起始条件:SCL为高时,SDA从高到低跳变。这个下降沿告诉所有从设备:“注意,要开始发地址了”。
  3. 数据采样:SCL低电平时,主机改变SDA;SCL高电平时,从设备读取SDA。所以SCL的上升沿才是真正的采样点。
  4. 停止条件:SCL为高时,SDA从低到高跳变。总线释放。

这里有个关键点:数据在SCL高电平时必须稳定。如果SDA在SCL高时跳变,会被当成起始或停止条件。我在项目中遇到过一个人为失误:CPU的I2C中断响应太慢,导致SDA在SCL高时被软件改写了,结果总线疯狂产生虚假起始条件。

一句话总结正常时序:SCL低时数据变,SCL高时数据读。两根线各司其职,谁也不抢谁的活儿。

2.3 时钟拉伸的本质——从设备“拽住”SCL不放

时钟拉伸只发生在SCL低电平阶段。从设备觉得自己还没准备好,就把SCL继续拉低,不让主机上升。主机发现SCL一直低,就会一直等——直到从设备松手。

为什么从设备要这么做?说实话,最常见的原因是它内部的数据处理没结束,比如:

  • 从设备正在写EEPROM,不能接收新数据;
  • 从设备ADC转换中,数据还没稳定;
  • 从设备缓冲区满了,正在倒腾数据。

从设备不是故意捣乱,它只是为了不接收它处理不了的命令。你想想看,如果它不拉低SCL,主机就会继续发数据,那数据必然丢失。

2.4 正常时序 vs 拉伸时序——波形对比

下面这张表把两种情况的SCL/SDA行为列在一起,你看完就能一眼认出拉伸。

特征正常传输时钟拉伸发生
SCL低电平时间固定,小于4.7 μs(标准模式)被延长,可能达到几十甚至几百微秒
SCL高电平时间由主机控制,等于tHIGH不变,仍由主机控制
SCL波形形状对称方波低电平期明显变宽,高电平期不变
SDA变化点仅在SCL低电平时变化在拉伸期间SDA可能不变(从设备未输出新数据)
主机行为主动产生下一个时钟等待SCL释放,一直检查SCL是否为高

避坑指南:我曾经用一台100MHz采样率的逻辑分析仪去抓一个快模式(400kHz)的时钟拉伸,结果发现低电平“略微”变宽了0.5μs,差点忽略掉。后来才意识到,拉伸可能非常短,只有几十纳秒。所以建议用至少200MHz采样率去抓,时间分辨率要小于1个SCL周期的一半。

2.5 时序关系一图看——SCL/SDA的上升沿、下降沿与拉伸区域

我把正常传输和时钟拉伸的波形画在一起,标出关键时间点和区域。你会看到拉伸就是SCL低电平被“撑开”的那一块。

SCL/SDA 正常传输与时钟拉伸波形对比 正常传输 SCL(主机驱动) SDA(主机驱动) 起始条件 采样点 采样点 t_LOW (约4.7μs) 时钟拉伸 SCL(被从设备拉低) SDA(从设备保持,等待释放) 时钟拉伸区 从设备释放SCL t_LOW 显著延长(>数十μs) 💡 如何一眼认出时钟拉伸 1. 看SCL低电平是否明显比其他脉冲长(特别是同一个SCL周期内)。 2. 如果SDA在SCL低电平时保持不变,同时SCL低电平变宽,基本就是拉伸。 3. 用逻辑分析仪测量所有SCL低电平脉宽,找异常大的值。

2.6 实战判断技巧——你该关注哪些点

抓到了波形,怎么确认是时钟拉伸,而不是其他问题?我给自己总结了一个检查清单,每次调I2C都会过一遍:

  1. 检查SCL低电平的一致性:正常传输中,所有SCL低电平时间应该差不多。如果有一个或几个明显偏长,那就是拉伸。
  2. 看拉伸时SDA是否稳定:拉伸期间SDA要么保持上一个值不变(从设备还没准备好),要么变成从设备想发送的数据(从设备用拉伸争取时间来输出字节)。如果是后一种,SDA会在拉伸期间变化一次然后保持。
  3. 识别拉伸发生在哪个时钟周期:常见的是在第9个SCL脉冲(应答位)或下一个字节的第一个时钟。如果拉伸发生在应答位之后,说明从设备还在处理上一个字节。
  4. 用统计工具分析:现在的逻辑分析仪软件一般都有“SCL低电平统计”功能。我看过不少拉伸问题,实际SCL低电平有时只是比正常值宽了几百纳秒,人眼很难发现,但统计图上一目了然。

我的经验:当年调试一个温度传感器,它只在温度转换完成后才释放SCL。我在-40℃环境下测试,转换时间变慢了,导致时钟拉伸时间从正常的1ms飙到3ms。主机AC定时器超时直接把总线复位了。后来我把主机的SCL超时时间改成了5ms,问题解决。记住:从设备手册里的转换时间,往往是典型值,极端温度和电压下会变。