2. I²C通信协议详解:起始条件、停止条件、数据有效性、应答机制
各位同学,今天我们来啃I²C协议最核心的骨头。说实话,很多工程师调了几年I²C,遇到波形异常还是只会抓瞎——说白了就是协议底层没吃透。这一节我带你从波形图到寄存器,把起始、停止、数据有效性、ACK/NACK这四个基本动作彻底搞明白。
2.1 起始条件(S)与停止条件(P)
先看最基础的两个信号。I²C总线空闲时,SCL和SDA都是高电平(由上拉电阻拉高)。什么时候算一次传输开始?什么时候算结束?协议规定得很清楚。
起始条件(S):SCL为高电平时,SDA从高电平切换到低电平。
停止条件(P):SCL为高电平时,SDA从低电平切换到高电平。
我刚开始做驱动时,总觉得这个定义太简单,直到有一次在瑞芯微RK3568上调试一个温湿度传感器,示波器抓到的起始条件总是不对——原来是GPIO的 slew rate 设置太慢,SDA下降沿不够陡,主设备根本不认。嗯,硬件细节往往就卡在这种地方。
这里有个关键点:起始和停止条件只能由主设备产生。从设备永远不能主动拉低SDA来发起传输。你想想看,如果从设备也能随便拉总线,那不乱套了?
我的习惯:调试时先用示波器看SDA和SCL的静态电平。如果空闲时SDA不是高电平,先查上拉电阻和GPIO配置,别急着调软件。
2.2 数据有效性:SCL高电平时采样
数据怎么传?协议规定:SDA上的数据必须在SCL低电平时变化,在SCL高电平时被采样。换句话说,SCL高电平期间,SDA必须保持稳定。
为什么这么设计?说白了就是为了抗干扰。SCL高电平时采样,如果SDA有毛刺,只要不在采样窗口内,就不会被误判。我在一个项目中遇到过总线长度超过30厘米的情况,SCL高电平期间的SDA抖动特别大,最后不得不降低速率到50kHz才稳定——这就是数据有效性的物理限制。
我曾经踩过的坑:在RK3588上配置I²C时钟时,忘了检查SCL高电平的最小保持时间。结果传感器在高温下偶尔丢数据,查了两天才发现是SCL高电平太窄,从设备来不及采样。记住:数据有效性不仅看SDA,还要看SCL的占空比。
数据位的传输顺序是MSB first(最高位在前)。每个字节8位,之后必须跟一个应答位。下面这个表总结了数据有效性的核心规则:
| 信号 | SCL低电平 | SCL高电平 |
|---|---|---|
| SDA | 允许变化(数据更新) | 必须稳定(数据采样) |
| SCL | 从设备准备接收/发送 | 主设备采样SDA |
2.3 应答机制:ACK与NACK
每个字节传完后,接收方必须给一个应答。这是I²C协议里最容易被忽视、也最容易出问题的地方。
ACK(应答):在第9个SCL时钟周期,接收方将SDA拉低。
NACK(非应答):在第9个SCL时钟周期,接收方保持SDA为高电平。
谁发应答?分两种情况:
- 主设备发送数据给从设备:从设备发ACK/NACK。如果从设备忙不过来或地址不对,就发NACK。
- 主设备读取从设备数据:主设备在每字节后发ACK,表示“我还要继续读”;最后一个字节发NACK,表示“够了,停止”。
我记得有一次调试一个音频编解码芯片,读寄存器总是返回0xFF。示波器一看,从设备明明发了数据,但主设备在应答位把SDA拉低了——我配置成了主设备发ACK,但读操作时主设备应该发NACK来结束传输。这种细节,手册上写得很清楚,但实际写代码时太容易搞反了。
核心原则:谁接收数据,谁发应答。主设备发送时,从设备应答;主设备接收时,主设备应答。
2.4 完整传输时序:从起始到停止
把上面几个概念串起来,一次完整的I²C传输是这样的:
- 主设备发送起始条件(S)
- 主设备发送7位从设备地址 + 1位读写位(R/W)
- 从设备发ACK(如果地址匹配)
- 主设备发送寄存器地址/数据(每字节后跟ACK)
- 如果是读操作,主设备切换为接收模式,从设备发送数据
- 主设备发送停止条件(P)
下面这张图把整个流程画清楚了:
2.5 常见问题与调试技巧
最后分享几个我在瑞芯微平台上实际遇到过的坑:
问题1:起始条件后无ACK
现象:发送从设备地址后,SDA在第9个时钟没有被拉低。
原因:地址错误、从设备未上电、总线被其他设备占用。
我的做法:先量从设备VDD,再量SDA/SCL波形,确认地址对不对。RK平台上经常有人把7位地址左移一位当8位发,结果地址对不上。
问题2:停止条件后总线仍被拉低
现象:停止条件发出后,SDA一直低电平。
原因:从设备没有释放SDA总线,或者主设备GPIO配置成了开漏输出但没拉高。
我曾经在RK3566上遇到过,原因是I²C控制器在发送停止条件时,SDA释放时序不对,最后在dts里加了 i2c-scl-falling-time-ns 参数才解决。