1. I2C总线概述
1.1 I2C总线历史与演进
I2C(Inter-Integrated Circuit)总线由飞利浦半导体(现恩智浦半导体)于1982年推出,最初设计目的是为电视机、录像机等消费电子产品提供一种简单、低成本的双线串行总线,用于连接微控制器及其外围设备。其核心设计哲学是:用最少的信号线实现多设备间的可靠通信。
| 版本 | 发布年份 | 最大速率 | 关键特性 |
|---|---|---|---|
| I2C v1.0 | 1992 | 100 kbit/s | 标准模式(Standard-mode),7位地址 |
| I2C v2.0 | 1998 | 400 kbit/s | 快速模式(Fast-mode),10位地址扩展 |
| I2C v2.1 | 2000 | 3.4 Mbit/s | 高速模式(High-speed mode),电流提升输出级 |
| I2C v3.0 | 2007 | 1 Mbit/s | 快速模式+(Fast-mode Plus),更强驱动能力 |
| I2C v4.0 | 2012 | 5 Mbit/s | 超快速模式(Ultra Fast-mode),单向推挽 |
| I2C v5.0 | 2014 | 5 Mbit/s | 结构优化,新增命令序列 |
内核开发者视角: Linux 内核 I2C 子系统完整支持 Standard-mode、Fast-mode、Fast-mode Plus 和 High-speed mode。Ultra Fast-mode 因采用单向推挽而非开漏输出,在软件层面需要特殊处理,通常不纳入通用 I2C 控制器驱动框架。
1.2 物理层特性
I2C 总线物理层采用开漏(Open-Drain)结构,配合外部上拉电阻实现线与逻辑。这种设计使得多个设备可以安全地共享同一组信号线,且支持多主设备仲裁。
- SDA(Serial Data Line):串行数据线,双向传输地址和数据。
- SCL(Serial Clock Line):串行时钟线,由主设备驱动,从设备可拉低实现时钟拉伸(Clock Stretching)。
- 上拉电阻:典型值 4.7 kΩ(100 kHz)、2.2 kΩ(400 kHz)、1.0 kΩ(1 MHz),阻值取决于总线电容和速率。
- 总线电容:标准模式最大 400 pF,快速模式最大 400 pF,高速模式最大 100 pF。
- 逻辑电平:VIL ≤ 0.3 × VDD,VIH ≥ 0.7 × VDD。
关键物理约束: 总线上的总上拉电流受限于开漏输出级的灌电流能力(通常 3 mA ~ 20 mA)。设计 I2C 控制器驱动时,必须根据目标频率和总线电容计算上拉电阻值,否则会导致信号上升沿过缓,引发通信错误。
1.3 SDA与SCL信号线时序规范
I2C 总线上的数据采样严格同步于 SCL 时钟。SDA 只能在 SCL 低电平期间变化,在 SCL 高电平期间必须保持稳定。这一规则是 I2C 通信可靠性的基础。
| 时序参数 | 符号 | 标准模式 (100 kHz) | 快速模式 (400 kHz) | 快速模式+ (1 MHz) |
|---|---|---|---|---|
| SCL 时钟频率 | fSCL | 100 kHz | 400 kHz | 1 MHz |
| SCL 低电平时间 | tLOW | 4.7 μs | 1.3 μs | 0.5 μs |
| SCL 高电平时间 | tHIGH | 4.0 μs | 0.6 μs | 0.26 μs |
| SDA 建立时间 | tSU;DAT | 250 ns | 100 ns | 50 ns |
| SDA 保持时间 | tHD;DAT | 0 ns | 0 ns | 0 ns |
| 上升时间 | tr | 1000 ns | 300 ns | 120 ns |
| 下降时间 | tf | 300 ns | 300 ns | 120 ns |
驱动开发陷阱: 在 Linux 内核 I2C 控制器驱动中,时钟频率的配置不能仅设置 SCL 周期。必须同时保证 tLOW 和 tHIGH 分别满足规范。许多 SoC 的 I2C 控制器使用分频器从总线时钟派生 SCL,若分频系数设置不当,会导致占空比失衡,使 tHIGH 过短,从设备无法正确采样。
1.4 总线拓扑结构
I2C 总线采用多主设备总线拓扑,所有设备通过 SDA 和 SCL 两条线并联连接。每个设备都有一个唯一的地址(7位或10位),主设备通过地址选择通信对象。
- 主设备(Master):发起传输、产生时钟、产生起始和停止条件。同一时刻只能有一个主设备控制总线。
- 从设备(Slave):响应主设备的寻址,接收或发送数据。从设备可以拉低 SCL 实现时钟拉伸。
- 多主仲裁:当多个主设备同时尝试控制总线时,通过 SDA 线的线与逻辑进行仲裁,失去仲裁的主设备自动转为从模式。
- 最大设备数:理论上受限于地址空间(7位地址最多 112 个设备,10位地址最多 1008 个设备),实际受限于总线电容 400 pF 的限制。
1.5 总线通信基本流程
一次完整的 I2C 传输由以下阶段组成:
- 起始条件(START):SCL 高电平时,SDA 从高电平切换到低电平。
- 发送从设备地址:主设备发送 7 位或 10 位地址,后跟读写位(0=写,1=读)。
- 从设备应答(ACK):从设备在第 9 个 SCL 周期拉低 SDA 表示应答。
- 数据传输:每字节 8 位,后跟 1 位应答位。MSB 优先传输。
- 停止条件(STOP):SCL 高电平时,SDA 从低电平切换到高电平。
内核驱动实现要点: Linux I2C 控制器驱动通过
struct i2c_msg 描述一次传输,包含地址、标志(读写)、数据缓冲区和长度。驱动需要将 i2c_msg 转换为硬件寄存器操作序列,包括起始条件、地址发送、数据收发和停止条件的生成。时钟频率通过控制器时钟分频器或定时器寄存器配置。
// Linux 内核 I2C 消息结构体定义 (include/uapi/linux/i2c.h)
struct i2c_msg {
__u16 addr; // 从设备地址(7位或10位)
__u16 flags; // 传输标志:I2C_M_RD 表示读,0 表示写
__u16 len; // 数据缓冲区长度(字节数)
__u8 *buf; // 数据缓冲区指针
};