2. I2C 通信时序详解:起始条件、停止条件、数据有效性、应答信号(ACK/NACK)
I2C(Inter-Integrated Circuit)总线是一种由飞利浦公司开发的两线式串行总线,广泛应用于连接微控制器及其外围设备。理解其通信时序是驱动开发的基础。本章将深入解析 I2C 总线上的四个核心时序要素:起始条件、停止条件、数据有效性以及应答机制。
2.1 I2C 总线物理层与信号线
I2C 总线仅使用两条双向开漏信号线:
- SCL(Serial Clock Line):串行时钟线,由主设备产生,用于同步数据传输。
- SDA(Serial Data Line):串行数据线,用于在主设备和从设备之间传输地址和数据。
关键概念:由于 SCL 和 SDA 是开漏输出,总线空闲时,两条线均通过上拉电阻被拉至高电平(Vdd)。任何设备都可以通过将线拉低来发起通信或应答。
2.2 起始条件(START Condition)与停止条件(STOP Condition)
I2C 总线的数据传输由起始条件开始,由停止条件结束。这两个条件是总线状态变化的特殊序列,由主设备产生。
2.2.1 起始条件(S)
当 SCL 线处于高电平时,SDA 线从高电平切换到低电平,表示一个起始条件。此信号告诉总线上的所有从设备,主设备即将开始一次新的数据传输。
2.2.2 停止条件(P)
当 SCL 线处于高电平时,SDA 线从低电平切换到高电平,表示一个停止条件。此信号标志着本次数据传输的结束,总线恢复空闲状态。
驱动开发要点:在编写 I2C 控制器驱动时,起始和停止条件的产生通常由硬件 I2C 控制器自动完成。但在软件模拟 I2C(Bit-Bang)模式下,驱动开发者必须严格按照时序要求,通过 GPIO 精确控制 SCL 和 SDA 的电平变化。
2.3 数据有效性(Data Validity)
I2C 协议规定,在时钟线 SCL 为高电平期间,数据线 SDA 上的电平必须保持稳定。只有在 SCL 为低电平时,SDA 上的电平才允许发生变化。这意味着数据采样发生在 SCL 的上升沿或高电平期间。
- 数据采样:接收方在 SCL 的上升沿或高电平期间读取 SDA 上的电平。
- 数据变化:发送方必须在 SCL 为低电平时更新 SDA 上的数据,以确保数据在 SCL 高电平时稳定。
2.4 应答信号(ACK/NACK)
I2C 总线上的每个数据字节(8 位)后都必须跟随一个应答位。应答位由接收方产生,用于向发送方确认数据是否成功接收。
2.4.1 应答机制
- ACK(Acknowledge,应答):在第 9 个时钟周期,接收方将 SDA 线拉低,表示“已成功接收数据,请继续发送”。
- NACK(Not Acknowledge,非应答):在第 9 个时钟周期,接收方保持 SDA 线为高电平,表示“未成功接收数据”或“传输结束”。
2.4.2 应答信号的作用
| 场景 | 发送方 | 接收方 | 应答位 | 含义 |
|---|---|---|---|---|
| 主设备发送地址 | 主设备 | 从设备 | ACK | 从设备地址匹配,准备通信 |
| 主设备发送数据 | 主设备 | 从设备 | ACK | 从设备已接收数据,可以继续发送 |
| 主设备发送数据 | 主设备 | 从设备 | NACK | 从设备无法接收更多数据(如缓冲区满) |
| 主设备接收数据 | 从设备 | 主设备 | ACK | 主设备已接收数据,请继续发送 |
| 主设备接收数据 | 从设备 | 主设备 | NACK | 主设备通知从设备停止发送(传输结束) |
常见驱动 Bug:在中断驱动的 I2C 传输中,如果主设备在接收最后一个字节后未发送 NACK,从设备会继续发送数据,导致总线挂死。务必在接收完所需数据后,在第 9 个时钟周期释放 SDA(即发送 NACK)。
2.5 完整数据传输流程
一个完整的 I2C 数据传输流程如下:
- 起始条件(S):主设备产生起始条件。
- 发送从设备地址(7 位或 10 位):主设备发送从设备地址,后跟读写位(R/W)。
- 从设备应答(ACK):地址匹配的从设备发送 ACK。
- 数据传输:主设备(写模式)或从设备(读模式)发送数据字节,每字节后跟随一个应答位。
- 停止条件(P):主设备产生停止条件,结束通信。
2.6 时序参数与高速模式
I2C 总线支持多种工作模式,不同模式下的时序参数有所不同。下表列出了标准模式和快速模式的关键时序参数:
| 参数 | 符号 | 标准模式 (100 kHz) | 快速模式 (400 kHz) | 说明 |
|---|---|---|---|---|
| SCL 时钟频率 | f_SCL | 100 kHz | 400 kHz | 最大时钟频率 |
| 保持时间(起始条件) | t_HD;STA | 4.0 μs | 0.6 μs | 起始条件后 SCL 低电平保持时间 |
| 建立时间(停止条件) | t_SU;STO | 4.0 μs | 0.6 μs | 停止条件前 SCL 高电平建立时间 |
| 数据保持时间 | t_HD;DAT | 0 μs | 0 μs | SCL 低电平后 SDA 数据保持时间 |
| 数据建立时间 | t_SU;DAT | 250 ns | 100 ns | SCL 高电平前 SDA 数据建立时间 |
| SCL 低电平时间 | t_LOW | 4.7 μs | 1.3 μs | SCL 低电平最小周期 |
| SCL 高电平时间 | t_HIGH | 4.0 μs | 0.6 μs | SCL 高电平最小周期 |
驱动优化提示:在 Linux 内核中,I2C 控制器驱动通过配置时钟分频寄存器来设置 SCL 频率。对于高速传感器(如 3D 加速度计),建议使用快速模式(400 kHz)以提高数据吞吐量,但需确保总线电容和上拉电阻满足快速模式的时序要求。
2.7 本章小结
- 起始/停止条件:由主设备在 SCL 高电平时改变 SDA 电平产生,是通信的开始和结束标志。
- 数据有效性:数据在 SCL 高电平时被采样,在 SCL 低电平时变化。
- 应答信号:第 9 个时钟周期,接收方拉低 SDA 为 ACK,保持高为 NACK,是流量控制和错误检测的关键。
- 时序参数:不同工作模式(标准/快速/高速)有严格的时序要求,驱动开发时必须确保满足这些参数。