2. I2C 总线协议详解:起始条件、停止条件、数据有效性、应答机制、完整数据传输时序

I2C(Inter-Integrated Circuit)总线是一种由 Philips(现 NXP)公司开发的两线式串行通信协议,广泛应用于嵌入式系统中连接微控制器与各种外设(如传感器、EEPROM、ADC/DAC、RTC 等)。本章将深入剖析 I2C 总线协议的核心要素,包括信号定义、时序要求、数据帧格式以及完整的传输流程,为后续编写 Linux 内核 I2C 设备驱动奠定坚实的硬件协议基础。

2.1 I2C 总线物理层与电气特性

I2C 总线仅使用两条双向信号线:

  • SCL(Serial Clock Line):串行时钟线,由主设备(Master)驱动,用于同步数据传输。
  • SDA(Serial Data Line):串行数据线,用于在主设备和从设备(Slave)之间双向传输数据。

两条线均通过上拉电阻连接到电源电压(VDD)。当总线空闲时,SCL 和 SDA 均为高电平。设备输出级为开漏(Open-Drain)结构,允许多个设备共享总线,通过“线与”逻辑实现仲裁和时钟拉伸。

关键参数:标准模式(Standard-mode)最高 100 kbit/s,快速模式(Fast-mode)最高 400 kbit/s,高速模式(High-speed mode)最高 3.4 Mbit/s。驱动开发中需根据从设备数据手册配置 I2C 控制器时钟频率。

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

I2C 总线上每一次通信都以起始条件开始,以停止条件结束。这两个条件是总线状态变化的特殊序列,由主设备产生。

条件 信号序列 说明
起始条件(S) SCL 为高电平时,SDA 从高电平切换到低电平 通知所有从设备:总线被占用,准备开始传输
停止条件(P) SCL 为高电平时,SDA 从低电平切换到高电平 通知所有从设备:传输结束,总线释放为空闲状态
重复起始条件(Sr) 在未产生停止条件前,再次产生起始条件 用于改变数据传输方向或切换从设备,无需释放总线
驱动开发要点:在 Linux 内核 I2C 核心层中,i2c_msg 结构体的 flags 字段通过 I2C_M_STOP 和 I2C_M_NOSTART 控制停止条件和重复起始条件的生成。理解硬件时序是正确配置这些标志的前提。
I2C 起始条件与停止条件时序 I2C 起始条件与停止条件时序图 SCL SDA 起始条件 (S) SDA 下降沿,SCL 高 停止条件 (P) SDA 上升沿,SCL 高 数据传输区域(SCL 低电平时改变 SDA,高电平时采样)

2.3 数据有效性(Data Validity)

I2C 总线上数据的有效性由 SCL 时钟信号严格定义:

  • 数据变化:SDA 线上的数据必须在 SCL 为低电平时发生变化。
  • 数据采样:SDA 线上的数据必须在 SCL 为高电平时被接收方采样读取。

每个时钟脉冲传输 1 位数据。在 SCL 高电平期间,SDA 必须保持稳定,否则会被误判为起始条件或停止条件。

常见错误:在 SCL 高电平期间改变 SDA 状态是协议违规,会导致通信混乱。驱动中的 GPIO 模拟 I2C 实现必须严格遵循此时序,使用 udelay 或 ndelay 确保时序窗口。
I2C 数据有效性时序 I2C 数据有效性:SCL 低电平变数据,高电平读数据 SCL SDA 允许变化 采样 允许变化 采样 允许变化

2.4 应答机制(ACK/NACK)

I2C 总线采用强制性的应答机制来确保数据传输的可靠性。每传输完 1 个字节(8 位数据),接收方必须在第 9 个时钟周期内产生应答信号。

应答类型 第 9 位 SDA 状态 含义 典型场景
ACK(应答) 低电平 接收方已成功接收字节,准备接收下一字节 正常数据传输、从设备地址匹配
NACK(非应答) 高电平 接收方无法接收或处理数据 从设备忙、地址未匹配、读操作结束
驱动中的应答处理:在 Linux I2C 驱动中,主设备发送地址后检测 ACK/NACK 决定是否继续;读操作时,主设备在最后一个字节发送 NACK 并产生停止条件,通知从设备停止发送。内核 i2c_transfer 返回值可反映应答状态。
I2C 应答机制时序 I2C 应答机制:第 9 个 SCL 时钟周期 SCL SDA 位 7 (MSB) 位 0 (LSB) 位 0 (LSB) ACK 从设备在第 9 个 SCL 脉冲将 SDA 拉低

2.5 完整数据传输时序

一次完整的 I2C 数据传输由以下步骤组成:

  1. 起始条件(S):主设备产生起始条件,占用总线。
  2. 发送从设备地址(7 位或 10 位):主设备发送从设备地址,高位在前。
  3. 发送读/写位(R/W):第 8 位为 0 表示写操作,为 1 表示读操作。
  4. 从设备应答(ACK):地址匹配的从设备在第 9 个时钟周期拉低 SDA 作为应答。
  5. 数据传输:根据 R/W 位,主设备发送数据(写)或接收数据(读),每字节后跟随 ACK/NACK。
  6. 停止条件(P):主设备产生停止条件,释放总线。

以下是一个典型的写操作帧格式:

| S | 从设备地址 (7位) | R/W=0 | ACK | 数据字节 1 | ACK | 数据字节 2 | ACK | ... | 数据字节 N | ACK | P |

读操作帧格式:

| S | 从设备地址 (7位) | R/W=1 | ACK | 数据字节 1 | ACK | 数据字节 2 | ACK | ... | 数据字节 N | NACK | P |
重复起始条件(Sr)应用:在复合操作(如先写寄存器地址再读数据)中,主设备在写操作后不产生停止条件,而是直接产生重复起始条件,然后发送读操作地址。这种“组合事务”在 Linux 内核中通过 i2c_msg 数组和 I2C_M_NOSTART 标志实现。
I2C 完整写操作数据传输时序 I2C 完整写操作数据传输帧格式 S 从设备地址 (7位) W ACK 数据字节 1 ACK 数据字节 2 ACK ... 数据字节 N ACK P 主设备产生起始条件 → 发送地址和写位 → 从设备 ACK → 发送数据字节 → 每字节后 ACK → 停止条件 读操作时,最后一个字节主设备发送 NACK 后产生停止条件

2.6 协议关键点总结

协议要素 关键规则 驱动开发影响
起始/停止条件 SCL 高电平时 SDA 的下降沿/上升沿 GPIO 模拟时需精确控制时序;硬件控制器自动处理
数据有效性 SCL 低电平变数据,高电平采样 确保 SCL 高电平期间 SDA 稳定,避免误触发
应答机制 每字节后第 9 个 SCL 时钟,接收方控制 SDA 检测 ACK/NACK 决定重试或报错;读操作最后发 NACK
地址与方向 7 位地址 + R/W 位组成第一个字节 内核中通过 addr 和 flags 设置
重复起始条件 不产生停止条件直接再次起始 用于组合事务,避免总线被其他主设备抢占
调试提示:使用逻辑分析仪抓取 SCL 和 SDA 波形是调试 I2C 驱动最有效的手段。重点关注起始条件、地址字节后的 ACK 位、以及停止条件是否完整。NACK 通常指示从设备不存在、地址错误或从设备忙。