2. I2C数据传输机制:7位与10位地址模式、读写操作流程、ACK/NACK应答机制

I2C(Inter-Integrated Circuit)总线协议的核心在于其精确定义的数据传输机制。理解7位与10位地址模式、完整的读写操作流程以及ACK/NACK应答机制,是编写可靠I2C驱动的基础。本章将深入剖析这些底层细节,为后续的设备树配置与驱动适配打下坚实的理论基础。

2.1 7位与10位地址模式

I2C总线上的每个从机设备都有一个唯一的地址。标准模式使用7位地址,理论上支持112个节点(保留16个地址)。为了扩展地址空间,协议定义了10位地址模式,兼容7位地址总线。

2.1.1 7位地址格式

在7位地址模式下,主机发送的第一个字节(起始条件后)包含7位从机地址和1位读写标志位(R/W)。

关键点: 7位地址范围是 0x00 ~ 0x7F,其中 0x00 为通用呼叫地址,0x01~0x03 为保留地址,0x04~0x77 为可用地址,0x78~0x7F 为保留地址(10位地址扩展用)。
位序 功能 说明
Bit 7 ~ Bit 1 从机地址 (A6 ~ A0) 7位从机地址,高位在前
Bit 0 R/W 标志 0 = 写操作 (主机发送数据到从机);1 = 读操作 (主机从从机读取数据)

2.1.2 10位地址格式

10位地址模式使用两个字节来传输地址。第一个字节的前5位固定为 11110,后2位为10位地址的高2位 (A9 ~ A8),第8位为R/W标志。第二个字节为10位地址的低8位 (A7 ~ A0)。

工程提示: 在Linux内核中,10位地址模式需要显式设置 I2C_M_TEN 标志位。设备树中通常使用 reg = <0x30>; 表示7位地址,而10位地址需要特殊处理,例如 reg = <0x0030>; 或使用 reg = <0x30 0x10>; 等变体,具体取决于控制器驱动实现。
7位与10位地址格式对比 7位地址帧: S 7位地址 (A6~A0) R/W ACK 10位地址帧: S 11110 + A9~A8 R/W ACK 低8位地址 (A7~A0) ACK 起始条件 (S) 地址字节 控制位 应答位 10位地址头 10位地址尾

2.2 读写操作流程

I2C的读写操作遵循严格的时序。一次完整的传输以起始条件 (S) 开始,以停止条件 (P) 结束。数据在时钟线 (SCL) 高电平期间采样,在低电平期间变化。

2.2.1 写操作流程

  1. 主机发送起始条件 (S):SCL高电平时,SDA从高电平切换到低电平。
  2. 主机发送从机地址 + 写标志 (0):7位地址 + R/W=0。
  3. 从机发送ACK:从机在第9个时钟周期将SDA拉低,表示应答。
  4. 主机发送数据字节:每发送一个字节(8位),等待从机ACK。
  5. 重复步骤4:直到所有数据发送完毕。
  6. 主机发送停止条件 (P):SCL高电平时,SDA从低电平切换到高电平。

2.2.2 读操作流程

  1. 主机发送起始条件 (S)。
  2. 主机发送从机地址 + 读标志 (1):7位地址 + R/W=1。
  3. 从机发送ACK。
  4. 从机发送数据字节:从机在SCL驱动下,逐位发送数据。
  5. 主机发送ACK/NACK:主机每接收一个字节后,发送ACK表示继续读取,发送NACK表示停止读取。
  6. 重复步骤4-5:直到主机发送NACK。
  7. 主机发送停止条件 (P)。
常见错误: 在组合传输(Combined Transfer)中,例如先写寄存器地址再读数据,主机在写操作结束后发送重复起始条件 (Sr) 而不是停止条件,然后发送读标志。这是I2C驱动中实现寄存器读取的标准方法。
I2C 读写操作流程图 写操作: S 地址+W ACK 数据字节 ACK P 读操作: S 地址+R ACK 数据字节 NACK P 组合传输 (写地址 + 读数据): S 地址+W ACK 寄存器地址 ACK Sr 地址+R ACK 数据字节 S/P/Sr 写地址 读地址 写数据 读数据 应答

2.3 ACK/NACK应答机制

ACK/NACK是I2C总线保证数据可靠传输的核心机制。每个字节(8位)传输完成后,接收方必须在第9个时钟周期内发送一个应答位。

2.3.1 应答位定义

应答类型 SDA电平 (第9个SCL周期) 含义 典型场景
ACK (Acknowledge) 低电平 (0) 接收方已成功接收数据,可以继续发送下一字节 从机确认地址匹配;主机确认数据写入成功;从机确认数据读取请求
NACK (Not Acknowledge) 高电平 (1) 接收方未成功接收数据,或不再接收更多数据 从机地址不匹配;从机忙或数据错误;主机读取完最后一个字节后通知从机停止

2.3.2 应答在驱动中的处理

在Linux I2C驱动中,ACK/NACK的处理通常由I2C控制器硬件自动完成,但驱动开发者需要理解其状态,以便进行错误处理。

// 示例:Linux I2C消息结构体中的标志位
struct i2c_msg {
    __u16 addr;    // 从机地址
    __u16 flags;   // 标志位,如 I2C_M_RD, I2C_M_TEN, I2C_M_NOSTART 等
    __u16 len;     // 数据长度
    __u8 *buf;     // 数据缓冲区
};

// 驱动中检查ACK/NACK的典型方式(通过控制器状态寄存器)
// 假设控制器状态寄存器 bit0 表示 ACK 状态
if (readl(controller->base + I2C_STATUS) & I2C_STATUS_NACK) {
    dev_err(&adapter->dev, "I2C transfer failed: NACK received\n");
    return -EREMOTEIO; // 返回远程IO错误
}
调试技巧: 当I2C通信失败时,使用逻辑分析仪或示波器抓取SDA和SCL波形,观察第9个时钟周期的SDA电平。如果SDA保持高电平(NACK),通常表明从机地址错误、从机未上电或从机忙。如果SDA被拉低(ACK)但后续数据错误,则可能是时钟速率不匹配或总线电容过大。

2.3.3 应答机制与多从机适配

在多从机系统中,ACK/NACK机制用于总线仲裁和冲突检测。当多个从机同时响应时,只有成功将SDA拉低的从机获得总线控制权。驱动开发中,需要确保每个从机在地址匹配后正确发送ACK,否则主机将认为从机不存在并终止传输。

ACK/NACK 应答时序图 SCL SDA (ACK) Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 ACK SDA (NACK) Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 ← 上一章 📖 返回目录 下一章 →