3. 硬件接口基础:I2C 总线协议详解

I2C(Inter-Integrated Circuit)总线是一种由 Philips 公司(现 NXP)开发的同步、多主从、串行通信总线。它仅需两根信号线——串行数据线(SDA)和串行时钟线(SCL),即可实现多个设备之间的数据交换。在网关外设驱动开发中,I2C 常用于连接传感器、EEPROM、RTC 时钟、ADC 转换器等低速外设。理解 I2C 协议的底层机制,是编写正确、健壮的 HAL 层驱动的基础。

关键特性: I2C 是同步通信(由 SCL 时钟驱动)、半双工(同一时刻只能单向传输)、多主从(总线上可挂载多个主设备与从设备)、地址寻址(每个从设备有唯一 7 位或 10 位地址)。

3.1 物理层:SCL 与 SDA 信号线

I2C 总线由两根双向开漏(Open-Drain)信号线构成,必须通过外部上拉电阻连接到 VCC(通常为 3.3V 或 5V)。

  • SCL(Serial Clock): 串行时钟线,由主设备驱动,用于同步数据传输。时钟频率决定了总线速率,标准模式为 100 kHz,快速模式为 400 kHz,高速模式可达 3.4 MHz。
  • SDA(Serial Data): 串行数据线,用于传输地址、数据和控制信号。数据在 SCL 时钟的上升沿被采样,在下降沿变化(标准模式)。

由于采用开漏结构,总线具有“线与”特性:任何设备拉低总线,总线即被拉低;只有当所有设备释放总线时,总线才会被上拉电阻拉高。这种机制是 I2C 仲裁和时钟拉伸的基础。

驱动开发要点: 在嵌入式 Linux 中,I2C 控制器驱动通过操作 SoC 内部的 I2C 适配器寄存器来控制 SCL 和 SDA 的电平。HAL 层通常不直接操作 GPIO 模拟时序,而是通过 struct i2c_adapter 和 struct i2c_algorithm 来抽象硬件差异。
I2C 总线物理连接示意图 R R VCC (3.3V / 5V) SCL SDA GND 主设备 (Master) 从设备 1 从设备 2 说明: 所有设备共享 SCL 和 SDA 线,通过唯一地址区分。上拉电阻保证总线空闲时为高电平。

3.2 起始条件与停止条件

I2C 总线的数据传输由起始条件(START)开始,由停止条件(STOP)结束。这两个条件由主设备产生,是总线状态转换的关键标志。

条件 信号时序 说明
起始条件 (S) SCL 为高电平时,SDA 从高电平切换到低电平 表示总线从空闲状态进入忙碌状态,所有从设备开始监听地址
停止条件 (P) SCL 为高电平时,SDA 从低电平切换到高电平 表示总线从忙碌状态回到空闲状态,释放总线控制权
常见错误: 在驱动开发中,如果起始条件或停止条件的时序不满足 I2C 规范(例如 SDA 在 SCL 低电平时变化),从设备可能无法正确识别总线状态,导致通信失败或总线挂死。HAL 层应确保控制器硬件正确生成这些条件。
I2C 起始条件与停止条件时序 SCL SDA 起始条件 (S) 停止条件 (P) 注意:起始和停止条件都发生在 SCL 高电平期间,SDA 的电平变化用于标志总线状态切换。

3.3 地址帧与读写位

在起始条件之后,主设备必须发送一个地址帧来指定要通信的从设备。I2C 使用 7 位地址(标准)或 10 位地址(扩展),后跟一个读写位(R/W)。

  • 7 位地址: 地址范围 0x00 ~ 0x7F,其中 0x00 为通用呼叫地址,0x04 ~ 0x77 为用户可用地址。每个从设备在硬件设计时被赋予一个固定地址(部分可配置)。
  • 读写位(R/W): 地址帧的第 8 位。0 表示主设备将要写入(发送数据到从设备),1 表示主设备将要读取(从从设备接收数据)。
  • 地址传输顺序: 先发送地址的高位(MSB),最后发送读写位。从设备在接收到匹配的地址后,会在第 9 个 SCL 周期发送应答位(ACK)。
HAL 层映射: 在 Linux 内核中,struct i2c_msg 结构体包含 addr(从设备地址)、flags(读写标志)、len(数据长度)和 buf(数据缓冲区)。驱动开发者通过填充此结构体来发起 I2C 传输。
I2C 7 位地址帧结构 A6 A5 A4 A3 A2 A1 A0 R/W 7 位从设备地址 (MSB 优先) 读写位 示例: 若从设备地址为 0x48 (A6..A0 = 1001000),主设备写入时发送 0x90 (10010000),读取时发送 0x91 (10010001)。

3.4 数据帧与字节传输

当地址帧被从设备确认后,主设备开始传输数据帧。每个数据帧包含 8 位数据(一个字节),后跟一个应答位。数据传输遵循以下规则:

  • 字节顺序: 每个字节的 MSB(最高位)先传输,LSB(最低位)最后传输。
  • 数据长度: 每次传输的字节数没有限制,但受限于从设备的缓冲区大小和总线速率。
  • 传输方向: 在写入操作中,主设备发送数据,从设备接收;在读取操作中,主设备接收数据,从设备发送。
  • 时钟同步: 每个字节传输需要 9 个 SCL 时钟周期(8 位数据 + 1 位应答)。
性能考量: 在网关应用中,I2C 速率通常为 100 kHz 或 400 kHz。对于大数据量传输(如固件升级),建议使用 SPI 或更高带宽的接口。I2C 更适合小数据量的控制类通信。
I2C 数据帧传输时序 SCL SDA D7 D6 D5 D4 D3 D2 D1 D0 ACK 8 位数据 (MSB 优先) 应答 每个字节传输需要 9 个 SCL 周期:8 个数据位 + 1 个应答位。数据在 SCL 上升沿被采样。 从设备通过在第 9 个周期拉低 SDA 表示 ACK,释放 SDA 表示 NACK。

3.5 应答机制(ACK/NACK)

应答机制是 I2C 协议可靠性的核心。每个字节(地址帧或数据帧)传输完成后,接收方必须在第 9 个 SCL 时钟周期内产生应答信号。

应答类型 SDA 状态(第 9 周期) 含义 典型场景
ACK(应答) 低电平(接收方拉低 SDA) 接收成功,可以继续发送下一字节 从设备确认地址匹配;从设备确认数据写入成功
NACK(非应答) 高电平(接收方释放 SDA) 接收失败或传输结束 主设备在读取操作最后发送 NACK 表示停止读取;从设备忙或地址不匹配
驱动调试要点: 如果 I2C 通信中收到 NACK,常见原因包括:从设备地址错误、从设备未上电或复位、总线被其他设备占用、时钟拉伸超时。在 HAL 层驱动中,应检查 i2c_transfer() 的返回值,并实现重试或错误恢复机制。

3.6 完整 I2C 通信流程

一个完整的 I2C 写操作或读操作遵循以下流程。以主设备向从设备写入 2 个字节为例:

  1. 起始条件: 主设备在 SCL 高电平时将 SDA 从高拉低。
  2. 发送地址帧: 主设备发送 7 位从设备地址 + 写位(0)。
  3. 等待 ACK: 从设备在地址匹配后拉低 SDA 作为应答。
  4. 发送数据字节 1: 主设备发送 8 位数据,从设备在第 9 周期发送 ACK。
  5. 发送数据字节 2: 主设备发送第二个字节,从设备发送 ACK。
  6. 停止条件: 主设备在 SCL 高电平时将 SDA 从低拉高,释放总线。

读取操作类似,但在地址帧中读写位为 1,且主设备在接收完最后一个字节后发送 NACK 以通知从设备停止发送。

起始条件 (S) 发送地址 + 写位 等待 ACK 发送数据字节 1 停止条件 (P) ← 上一章 📖 返回目录 下一章 →