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

I2C(Inter-Integrated Circuit)总线协议由Philips(现NXP)设计,是一种同步、多主从、串行通信总线。它仅需两根线——串行数据线(SDA)和串行时钟线(SCL)——即可实现设备间的数据交换。理解其底层时序是驱动开发和设备树配置的基础。

核心要点: I2C协议的所有操作都围绕“起始条件”、“停止条件”、“数据有效性”、“字节格式”和“应答机制”这五个基本元素展开。掌握它们,就等于掌握了I2C通信的“语法”。

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

总线空闲时,SDA和SCL均为高电平。数据的传输由主控制器(Master)发起,并以起始条件开始,以停止条件结束。

  • 起始条件(S): 当SCL为高电平时,SDA从高电平切换到低电平。此信号表示总线从空闲状态进入忙碌状态,并开始一次新的传输。
  • 停止条件(P): 当SCL为高电平时,SDA从低电平切换到高电平。此信号表示当前传输结束,总线恢复空闲状态。
驱动开发提示: 在Linux内核I2C子系统(i2c-core)中,起始和停止条件的生成由底层适配器驱动(如i2c-imx、i2c-omap)的硬件控制器自动完成。驱动开发者通常只需调用i2c_transfer()接口,无需手动操作GPIO模拟时序,除非使用GPIO模拟I2C(即i2c-gpio)。
I2C 起始条件与停止条件时序图 I2C 起始条件 (S) 与 停止条件 (P) 时序 SCL SCL 高电平 (采样窗口) SDA 起始条件 (S) SDA ↓ 停止条件 (P) SDA ↑ 数据位 ACK SDA 在 SCL 高电平时被采样

2.2 数据有效性(Data Validity)

I2C协议规定,数据线SDA上的电平必须在时钟线SCL为高电平时保持稳定,以确保数据被正确采样。

  • 数据稳定: 在SCL高电平期间,SDA上的数据必须保持不变。
  • 数据变化: SDA的状态变化(从高到低或从低到高)只允许在SCL低电平期间进行。
SCL状态 SDA允许行为 说明
高电平 保持稳定 接收器在此窗口内采样SDA电平,决定当前位是0还是1。
低电平 允许变化 发送器在此窗口内改变SDA电平,为下一个数据位做准备。
时序参数关键点: 数据建立时间(tSU;DAT)和数据保持时间(tHD;DAT)是设备树中需要配置的重要时序参数。它们定义了SDA相对于SCL边沿的稳定时间窗口,直接影响通信的可靠性。

2.3 字节格式(Byte Format)与数据传输

I2C总线上的数据以字节(8位)为单位进行传输。每个字节后必须跟随一个应答位(ACK/NACK),因此一个完整的数据帧实际上是9位。

  • 位序: 数据从最高有效位(MSB)开始传输,到最低有效位(LSB)结束。
  • 帧结构: 起始条件 → 8位数据(MSB→LSB) → 应答位(ACK/NACK) → 下一个字节或停止条件。
I2C 字节格式与帧结构 I2C 字节格式 (9位帧) S D7 D6 D5 D4 D3 D2 D1 D0 ACK P 传输方向 (MSB → LSB)

2.4 应答机制(ACK/NACK)

应答机制是I2C协议保证数据可靠传输的核心。每传输完一个字节(8位),接收器必须在第9个时钟周期内拉低SDA线,以表示“应答”(ACK)。如果接收器未拉低SDA(即SDA保持高电平),则视为“非应答”(NACK)。

  • ACK(应答): 接收器成功接收到一个字节后,在第9个时钟周期将SDA拉低。主控制器检测到SDA为低电平后,继续发送下一个字节或发起停止条件。
  • NACK(非应答): 接收器无法接收更多数据、数据错误或设备地址不匹配时,在第9个时钟周期保持SDA为高电平。主控制器检测到NACK后,通常会发起停止条件终止传输。
场景 发送方 接收方行为 SDA电平(第9时钟) 结果
地址匹配 主控制器 从设备确认地址 低电平 (ACK) 继续数据传输
数据写入成功 主控制器 从设备确认收到数据 低电平 (ACK) 主控制器发送下一字节或停止
数据读取完成 从设备 主控制器确认收到数据 低电平 (ACK) 从设备继续发送下一字节
设备忙/错误 主控制器 从设备无法处理 高电平 (NACK) 主控制器发送停止条件
最后字节读取 从设备 主控制器不再需要数据 高电平 (NACK) 从设备释放总线,主控制器发停止
驱动调试经验: 在Linux内核中,I2C传输失败最常见的原因之一就是NACK。当你在dmesg中看到类似i2c_transfer: NACK from device的错误时,通常意味着:
1. 设备地址错误(7位或10位地址不匹配)。
2. 设备未上电或处于复位状态。
3. 总线被其他设备拉死(SDA或SCL被锁死)。
4. 时序参数(如时钟频率过快)不满足从设备要求。
I2C 应答机制 (ACK/NACK) 流程图 I2C 应答机制决策流程 发送8位数据 接收器就绪? 是 (ACK) SDA 被拉低 否 (NACK) SDA 保持高 继续传输 发送停止条件

2.5 协议总结与驱动开发映射

将上述协议元素映射到Linux I2C驱动开发中,有助于理解内核抽象层的工作原理。

协议元素 硬件行为 Linux内核抽象 驱动开发者操作
起始条件 (S) SDA在SCL高电平时下降 struct i2c_msg 的开始 由适配器驱动自动处理
停止条件 (P) SDA在SCL高电平时上升 i2c_transfer() 返回 由适配器驱动自动处理
数据有效性 SDA在SCL高电平时稳定 时序参数 tSU;DAT, tHD;DAT 在设备树中配置 i2c-sda-hold-time-ns 等
字节格式 MSB优先,8位+ACK i2c_msg.len 和 i2c_msg.buf 填充缓冲区,指定长度
应答机制 第9时钟SDA电平 i2c_msg.flags 中的 I2C_M_IGNORE_NAK 检查返回值,处理NACK错误