2. I2C协议详解:起始条件、停止条件、数据有效性、字节格式与应答机制(ACK/NACK)

I2C(Inter-Integrated Circuit)总线协议由Philips(现NXP)公司设计,是一种同步、多主、半双工的串行通信协议。它仅使用两条双向开漏线——串行数据线(SDA)和串行时钟线(SCL)——即可实现设备间的数据交换。本章节将深入剖析I2C协议的核心时序与数据单元,为后续驱动开发与中断安全编程奠定基础。

2.1 总线空闲状态与电气特性

在深入时序细节之前,必须明确总线的空闲状态。由于SDA和SCL均为开漏(Open-Drain)结构,通过上拉电阻连接至电源电压(Vdd)。

  • 空闲状态:当总线无设备驱动时,SDA和SCL均被上拉至高电平(逻辑1)。
  • 线-与特性:任何设备将线拉低(逻辑0)时,总线电平即被拉低。这一特性是实现多主仲裁和时钟同步的物理基础。
驱动提示:在嵌入式系统中,上拉电阻的阻值选择(通常为4.7kΩ或10kΩ)直接影响总线上升时间和最大通信速率。高速模式(400kHz以上)通常需要更小的上拉电阻。

2.2 起始条件(START Condition)与停止条件(STOP Condition)

I2C总线上每一次数据传输都以起始条件开始,以停止条件结束。这两个条件是唯一允许SDA在SCL高电平期间发生变化的时刻。

条件 时序定义 SCL状态 SDA状态 作用
起始条件(S) SCL为高电平时,SDA从高电平切换到低电平 高 高 → 低 宣告总线占用,开始一次新的传输
停止条件(P) SCL为高电平时,SDA从低电平切换到高电平 高 低 → 高 释放总线,结束本次传输
重复起始条件(Sr) 在未产生停止条件前,再次产生起始条件 高 高 → 低 改变传输方向或切换从机,不释放总线
关键点:起始和停止条件必须由主机(Master)产生。重复起始条件(Sr)常用于复合操作,例如在写寄存器地址后立即读取数据,无需停止总线,可避免其他主机介入。
I2C 起始条件与停止条件时序图 I2C 起始条件与停止条件时序图 t SCL SDA 起始条件 (S) SDA下降沿,SCL高 停止条件 (P) SDA上升沿,SCL高 数据传输期间,SDA在SCL低电平时变化

2.3 数据有效性(Data Validity)

I2C协议对数据线上的电平变化有严格的时间约束,以确保数据在时钟高电平期间被可靠采样。

  • 数据稳定期:在SCL时钟的高电平期间,SDA上的数据必须保持稳定(不变)。
  • 数据变化期:只有在SCL为低电平时,SDA上的数据才允许发生改变(0→1或1→0)。
常见错误:初学者在软件模拟I2C时,容易在SCL高电平期间改变SDA状态(除起始/停止条件外),这会导致从机采样到错误数据或产生协议错误。务必在SCL低电平时更新SDA输出。

2.4 字节格式与数据传输

I2C总线上的数据以字节(8位)为单位进行传输,且遵循高位在前(MSB First)的顺序。

字段 位数 说明
从机地址 7位 或 10位 标识目标从机设备。7位地址模式下,地址范围为0x00~0x7F。
读/写位(R/W) 1位 0表示主机写(发送数据),1表示主机读(接收数据)。
数据字节 8位 × N 实际传输的数据负载,数量不限,直到停止条件或重复起始条件。
应答位(ACK/NACK) 1位 每个字节后由接收方产生,用于确认字节接收成功。

一个完整的I2C数据帧结构如下:

| 起始条件 | 从机地址(7位) | R/W位 | ACK | 数据字节(8位) | ACK | ... | 数据字节(8位) | ACK/NACK | 停止条件 |
I2C 字节传输帧结构图 I2C 字节传输帧结构(7位地址模式) S 起始 从机地址 (7位) MSB → LSB R/W 0/1 ACK 数据字节 (8位) MSB → LSB ACK … P 停止

2.5 应答机制(ACK/NACK)

应答机制是I2C协议可靠性的核心。每成功传输一个字节(8位数据),接收方必须在第9个SCL时钟周期内产生一个应答位。

2.5.1 应答位产生规则

  • ACK(应答,低电平):接收方在第9个时钟周期将SDA拉低,表示“我已成功接收到上一个字节,请继续发送下一个字节”。
  • NACK(非应答,高电平):接收方在第9个时钟周期保持SDA为高电平(释放SDA),表示“我无法接收更多数据”或“我未识别到该地址”。

2.5.2 不同场景下的应答行为

场景 发送方 接收方 应答行为
主机发送地址+写位 主机 从机 从机匹配地址则产生ACK,否则NACK
主机发送数据字节 主机 从机 从机成功接收则ACK;若从机忙或缓冲区满则NACK
主机接收数据字节 从机 主机 主机若想继续接收则ACK;若想停止接收则NACK(随后发送停止条件)
驱动编程要点:在Linux内核I2C驱动中,i2c_msg结构体的flags字段用于控制应答行为。例如,在读取最后一个字节时,主机必须发送NACK,否则从机会继续发送数据导致总线挂死。内核中的I2C_M_IGNORE_NAK和I2C_M_STOP等标志位提供了精细控制。
I2C 应答机制流程图 I2C 应答机制流程图(主机发送数据场景) 主机发送8位数据 主机释放SDA(输入模式) 从机在第9个时钟拉低SDA? (检测SDA电平) ACK:继续发送下一字节 NACK:主机发送停止条件

2.6 协议时序总结与对比

下表汇总了I2C协议中关键时序参数(以标准模式100kHz为例),帮助驱动开发者理解硬件时序约束。

参数 符号 最小值 最大值 说明
SCL时钟频率 fSCL 0 100 kHz 标准模式;快速模式可达400kHz
起始条件保持时间 tHD;STA 4.0 μs - SCL低电平后,SDA下降沿的保持时间
SCL低电平周期 tLOW 4.7 μs - SCL低电平最小持续时间
SCL高电平周期 tHIGH 4.0 μs - SCL高电平最小持续时间
数据建立时间 tSU;DAT 250 ns - SCL上升沿前,SDA数据必须稳定的时间
数据保持时间 tHD;DAT 0 3.45 μs SCL下降沿后,SDA数据保持的时间
停止条件建立时间 tSU;STO 4.0 μs - SCL高电平后,SDA上升沿的建立时间
软件模拟建议:在GPIO模拟I2C时,应使用微秒级延时函数(如udelay())来满足上述时序要求。对于Linux内核中的i2c-gpio驱动,这些时序由udelay和ndelay在i2c_algo_bit_data结构中配置。

2.7 本章小结

  • I2C总线通过起始条件(S)和停止条件(P)界定一次传输的边界。
  • 数据在SCL高电平时被采样,在SCL低电平时允许变化。
  • 每个字节(8位)后紧跟一个应答位(ACK/NACK),由接收方控制。
  • ACK表示继续传输,NACK表示终止传输或地址未匹配。
  • 理解这些基础时序是编写正确、健壮的I2C驱动(无论是主机还是从机模式)的前提。