1. I2C 总线协议基础

1.1 I2C 总线历史与演进

I2C(Inter-Integrated Circuit)总线由 Philips 半导体(现 NXP)于 1982 年推出,最初用于电视接收机中微控制器与外设之间的低速通信。其设计目标是以最少的引脚数(仅需两根线)实现板级多设备互联。

版本 推出年份 最大速率 关键特性
Standard-mode 1982 100 kbit/s 7 位地址,基本时序
Fast-mode 1992 400 kbit/s 兼容标准模式,速率提升
Fast-mode Plus 2007 1 Mbit/s 更强驱动能力,更多从设备
High-speed mode 1998 3.4 Mbit/s 主设备间高速传输,需特殊 I/O 缓冲
Ultra Fast-mode 2012 5 Mbit/s 单向推挽,移除上拉电阻
嵌入式调优提示: 在 Linux I2C 驱动中,struct i2c_adapter 的 class 字段和 quirks 结构体用于声明适配器支持的模式与速率上限。调优 DMA 时需确认硬件是否支持 Fast-mode Plus 或 High-speed mode,否则 DMA 传输可能因时序不匹配而失败。

1.2 物理层特性

I2C 总线仅使用两条双向信号线:SDA(串行数据线)和 SCL(串行时钟线)。两条线通过上拉电阻连接到电源电压(通常为 1.8V、3.3V 或 5V)。

  • 开漏输出: 所有设备通过开漏(open-drain)或开集电极(open-collector)驱动 SDA 和 SCL。总线空闲时,两条线均为高电平。
  • 线与逻辑: 多个设备可同时驱动总线低电平,实现仲裁(arbitration)和时钟同步(clock synchronization)。
  • 上拉电阻: 阻值取决于总线电容和速率,典型值为 1 kΩ ~ 10 kΩ。高速模式需更小阻值以缩短上升时间。
  • 最大总线电容: 标准模式 400 pF,Fast-mode Plus 可达 550 pF,超过此值需使用缓冲器或中继器。
I2C 总线物理连接拓扑 主设备 (Master) 从设备 1 (Slave) 从设备 2 (Slave) SDA SCL Rp Rp VDD (1.8V / 3.3V / 5V) 所有设备通过开漏输出连接 SDA/SCL,总线空闲时两条线均为高电平 上拉电阻 Rp 决定上升时间,影响最大传输速率

1.3 SDA/SCL 信号时序

I2C 通信基于 SCL 时钟同步 SDA 数据。每个时钟脉冲传输 1 位数据。关键时序事件如下:

  • 起始条件 (START): SCL 为高电平时,SDA 从高电平切换到低电平。由主设备产生,表示总线从空闲变为忙碌。
  • 停止条件 (STOP): SCL 为高电平时,SDA 从低电平切换到高电平。由主设备产生,表示总线释放。
  • 数据有效性: SCL 高电平期间,SDA 必须保持稳定;SDA 仅在 SCL 低电平期间允许变化。
  • 应答位 (ACK/NACK): 每传输 8 位数据后,接收方在第 9 个 SCL 脉冲拉低 SDA(ACK)或保持高电平(NACK)。
I2C 起始条件、数据传输与停止条件时序 SCL SDA START STOP D7 D6 D5 D4 D3 D2 D1 D0 ACK SCL 高电平期间 SDA 必须稳定;数据在 SCL 低电平时变化
驱动开发关键点: Linux 内核中 i2c_msg 结构体的 flags 字段控制起始/停止条件的生成。DMA 调优时需注意:I2C_M_NOSTART 和 I2C_M_STOP 标志位会影响 DMA 链表的构建方式,错误设置可能导致总线协议违规。

1.4 7 位与 10 位地址模式

I2C 总线使用地址来区分不同的从设备。地址在起始条件后立即发送,占用第一个字节的高 7 位或高 10 位。

7 位地址模式

  • 地址范围:0x00 ~ 0x7F(128 个地址),其中 0x00 为通用呼叫地址,0x01 ~ 0x07 保留,实际可用约 112 个。
  • 传输格式:起始条件后发送 1 字节,高 7 位为地址,最低位为 R/W 方向位(0=写,1=读)。
  • 示例:地址 0x50(AT24C02 EEPROM)写操作时发送 0xA0(0x50 << 1 | 0)。

10 位地址模式

  • 地址范围:0x00 ~ 0x3FF(1024 个地址),与 7 位地址兼容。
  • 传输格式:起始条件后先发送 5'b11110 + 地址高 2 位 + R/W,再发送剩余 8 位地址。
  • 第一个字节的高 5 位固定为 11110,用于与 7 位地址区分。
特性 7 位地址 10 位地址
最大从设备数 112(实际可用) 1024
地址字节数 1 字节(含 R/W) 2 字节
兼容性 所有设备支持 需从设备硬件支持
Linux 内核表示 addr & 0x7F addr | I2C_TENBIT
典型应用 传感器、EEPROM、RTC 多路复用器、复杂 SoC 外设
7 位与 10 位地址传输格式对比 7 位地址: S A6 A5 A4 A3 A2 A1 A0 R/W ACK 1 字节:7 位地址 + 1 位方向 10 位地址: S 11110 A9 A8 R/W ACK A7 A6 A5 A4 ACK 2 字节:11110 + 地址高 2 位 + R/W + ACK + 地址低 8 位 + ACK 10 位地址与 7 位地址完全兼容,通过首字节高 5 位 11110 区分
常见陷阱: 在 Linux I2C 驱动中,i2c_client 的 addr 字段存储的是 7 位地址(左对齐)。如果从设备使用 10 位地址,必须在 i2c_board_info 中设置 I2C_CLIENT_TEN 标志。DMA 调优时,10 位地址的传输需要额外的字节,可能影响 DMA 描述符的预分配大小。

1.5 总线仲裁与时钟同步

I2C 总线支持多主设备环境,通过以下机制避免冲突:

  • 仲裁 (Arbitration): 多个主设备同时驱动 SDA 时,输出低电平的设备获胜。仲裁在 SDA 上进行,不损失数据。
  • 时钟同步: 多个主设备将 SCL 拉低,最长的低电平周期决定 SCL 低电平时间;最短的高电平周期决定 SCL 高电平时间。所有主设备同步到统一的时钟。
  • 丢失仲裁: 检测到 SDA 电平与自身输出不一致的主设备立即释放 SDA 和 SCL,转为从设备模式。
驱动实现要点: 在 i2c_algorithm 的 master_xfer 回调中,必须处理 -EAGAIN 返回值以支持重试。DMA 调优时,仲裁失败可能导致 DMA 传输中途终止,需在中断处理中正确重置 DMA 通道状态。