2. I2C协议详解:起始条件、停止条件、数据有效性、字节格式与应答机制(ACK/NACK)
I2C(Inter-Integrated Circuit)总线协议由Philips(现NXP)设计,是一种同步、多主从、串行通信总线。理解其底层信号时序是驱动开发与调试的基础。本章从物理层信号出发,逐项解析I2C协议的五个核心要素:起始条件、停止条件、数据有效性、字节格式以及应答机制。
2.1 总线基本结构与空闲状态
I2C总线仅使用两条双向开漏线:SCL(串行时钟线)和SDA(串行数据线)。总线空闲时,SCL和SDA均通过上拉电阻保持高电平。
关键概念:开漏结构允许多个设备共享总线,通过线与逻辑实现仲裁。任何设备拉低SDA或SCL时,总线即被拉低。
2.2 起始条件(START Condition)
起始条件标志着一次I2C传输的开始。在SCL保持高电平期间,SDA从高电平切换到低电平。此信号由主设备产生,此后总线进入忙状态。
- 时序要求:SDA下降沿必须在SCL高电平期间完成。
- 唯一性:起始条件是一个特殊信号,不会被误认为数据位。
- 重复起始(Repeated START, Sr):在未产生停止条件前,主设备可再次发送起始条件,用于改变传输方向或切换从设备。
2.3 停止条件(STOP Condition)
停止条件标志着一次I2C传输的结束。在SCL保持高电平期间,SDA从低电平切换到高电平。停止条件后,总线恢复空闲状态。
| 条件类型 | SCL状态 | SDA跳变 | 总线状态 |
|---|---|---|---|
| 起始条件(S) | 高电平 | 高 → 低 | 忙 |
| 停止条件(P) | 高电平 | 低 → 高 | 空闲 |
| 重复起始(Sr) | 高电平 | 高 → 低 | 忙(无停止) |
调试陷阱:在驱动调试中,停止条件缺失是常见错误。如果主设备在传输完成后未发送停止条件,从设备可能一直等待后续数据,导致总线挂死。此时应检查I2C控制器的STOP位是否在传输结束时正确置位。
2.4 数据有效性(Data Validity)
I2C协议规定,数据采样在SCL的上升沿进行。为保证数据稳定,SDA上的数据必须在SCL低电平时改变,在SCL高电平时保持稳定。
- 数据变化:仅在SCL为低电平时允许SDA变化。
- 数据采样:在SCL的上升沿(低→高跳变)采样SDA电平。
- 保持时间:SDA在SCL上升沿前后需满足建立时间(tSU)和保持时间(tHD)要求。
2.5 字节格式与数据传输
I2C协议以字节(8位)为基本传输单位。每个字节后必须跟随一个应答位(ACK/NACK)。数据传输时,高位(MSB)在前,低位(LSB)在后。
字节传输结构:起始条件 → 8位数据(MSB→LSB)→ 应答位 → 下一个字节或停止条件。
一个完整的I2C数据帧通常包含:
- 从设备地址(7位或10位):前7位为地址,第8位为读/写位(R/W)。
- 寄存器地址(可选):用于指定从设备内部寄存器。
- 数据字节:一个或多个数据字节,每个字节后跟应答位。
- 停止条件:结束传输。
2.6 应答机制(ACK/NACK)
应答机制是I2C协议可靠性的核心。每个字节传输完成后,接收方必须在第9个SCL周期释放SDA(拉低表示ACK,保持高表示NACK)。
| 应答类型 | SDA状态(第9个SCL周期) | 含义 | 典型场景 |
|---|---|---|---|
| ACK(应答) | 低电平(接收方拉低) | 接收成功,可以继续发送下一字节 | 正常数据传输、地址匹配 |
| NACK(非应答) | 高电平(接收方释放或主设备拉高) | 接收失败或传输结束 | 从设备忙、地址未匹配、读操作结束 |
调试技巧:在Linux I2C驱动中,通过
i2c_msg的flags字段控制应答行为。对于读操作,主设备在最后一个数据字节后发送NACK,以通知从设备停止发送。检查i2c_smbus_read_byte()等函数的返回值,可以判断是否收到NACK。