2. I2C协议基础:总线物理层、主从机通信原理与数据帧格式

I2C(Inter-Integrated Circuit)总线是一种由Philips(现NXP)开发的同步、多主从、串行通信总线。在嵌入式系统中,I2C广泛用于连接传感器、存储器、IO扩展芯片等低速外设。理解其物理层与协议层是进行Zephyr驱动移植的前提。

学习提示: I2C协议虽然简单,但时序容限较窄。在Zephyr中配置I2C从机模式时,必须精确匹配物理层电气特性与协议帧格式,否则会导致总线挂死或数据错位。

2.1 I2C总线物理层

I2C总线仅使用两条双向信号线:

  • SCL(Serial Clock Line):串行时钟线,由主机驱动,用于同步数据传输。
  • SDA(Serial Data Line):串行数据线,用于传输地址和数据。

总线采用开漏(Open-Drain)输出结构,通过外部上拉电阻(通常为4.7kΩ~10kΩ)将总线拉高至VDD。任何设备都可以将总线拉低(驱动低电平),但不能主动驱动高电平。这种“线与”特性是I2C仲裁和时钟拉伸的基础。

关键电气参数:
  • 标准模式(Standard-mode):100 kbit/s
  • 快速模式(Fast-mode):400 kbit/s
  • 快速模式+(Fast-mode Plus):1 Mbit/s
  • 高速模式(High-speed mode):3.4 Mbit/s
  • 上拉电阻选择需平衡上升时间与功耗,典型值:5V系统用4.7kΩ,3.3V系统用10kΩ。
I2C总线物理连接示意图 I2C总线物理连接示意图 Rₚ Rₚ VDD SCL SDA 主机 (Master) 从机 1 从机 2 所有设备通过开漏输出连接到SCL和SDA,外部上拉电阻保证总线空闲时为高电平

2.2 主从机通信原理

I2C总线上的设备分为主机(Master)和从机(Slave)两种角色:

  • 主机:负责产生时钟信号(SCL)、发起通信、产生起始/停止条件。一个I2C总线上可以挂载多个主机,但同一时刻只能有一个主机控制总线。
  • 从机:被主机寻址并响应。从机不能主动发起传输,但可以通过时钟拉伸(Clock Stretching)机制让主机等待。
特性 主机(Master) 从机(Slave)
时钟产生 负责产生SCL时钟 不产生时钟,可拉低SCL(时钟拉伸)
通信发起 产生起始条件(START) 不能主动发起
地址匹配 发送从机地址 检测地址是否匹配
数据方向 决定读/写位 根据R/W位发送或接收数据
停止条件 产生停止条件(STOP) 不能产生停止条件
Zephyr移植注意: 在Zephyr I2C从机驱动中,从机设备需要注册中断服务函数来响应主机的读写请求。如果从机没有及时处理数据,主机可能因为时钟拉伸超时而报错。务必在设备树中配置正确的中断优先级和时钟拉伸超时参数。

2.3 起始条件与停止条件

I2C总线的数据传输以起始条件(START)开始,以停止条件(STOP)结束。这两个条件是唯一允许SDA在SCL为高电平时发生变化的时刻。

  • 起始条件(S):SCL为高电平时,SDA从高电平切换到低电平。
  • 停止条件(P):SCL为高电平时,SDA从低电平切换到高电平。
  • 重复起始条件(Sr):在未产生停止条件的情况下,再次产生起始条件,用于改变数据传输方向而不释放总线。
I2C起始条件与停止条件时序 起始条件(START)与停止条件(STOP)时序 SCL SDA S 起始 P 停止 数据有效(SCL高电平时采样SDA)

2.4 数据帧格式

I2C数据帧以字节(8位)为单位传输,每个字节后跟一个应答位(ACK/NACK)。数据传输时,SDA在SCL低电平时变化,在SCL高电平时被主机采样。

字节传输顺序:

  1. 主机发送8位数据(MSB first,高位在前)。
  2. 主机释放SDA(拉高),产生第9个SCL时钟。
  3. 接收方在第9个时钟周期将SDA拉低表示应答(ACK),保持高电平表示非应答(NACK)。
应答规则:
  • 主机发送地址字节后,从机必须应答(ACK)才能继续传输。
  • 主机发送数据字节后,从机接收时应答(ACK)。
  • 主机接收数据字节后,主机发送ACK表示希望继续接收,发送NACK表示传输结束。

2.5 地址与读写位

每个I2C从机都有一个唯一的7位或10位地址。主机在起始条件后发送的第一个字节包含从机地址和读写位:

  • 7位地址模式:第一个字节的高7位为地址,最低位(LSB)为读写位(R/W)。
  • 10位地址模式:第一个字节的前5位为11110,接着是地址的高2位,读写位在LSB;第二个字节为地址的低8位。

读写位含义:

  • R/W = 0:主机写数据到从机(主机发送,从机接收)。
  • R/W = 1:主机从从机读数据(主机接收,从机发送)。
I2C完整数据帧格式 I2C 7位地址模式完整数据帧格式 S 从机地址 (7位) R/W ACK 数据字节1 ACK 数据字节N ACK/NACK P S = 起始条件 | 从机地址 = 7位地址 | R/W = 0(写) / 1(读) | ACK = 应答 | P = 停止条件 每个字节后跟一个应答位,NACK表示传输结束或从机未准备好 地址字节分解:Bit[7:1] = 7位从机地址,Bit[0] = R/W位 例如:0x48 << 1 | 0 = 0x90(写操作),0x48 << 1 | 1 = 0x91(读操作)

2.6 典型I2C通信流程

一个完整的I2C写操作流程如下:

  1. 主机产生起始条件(S)。
  2. 主机发送7位从机地址 + 写位(R/W=0)。
  3. 从机匹配地址后,在第9个时钟周期发送ACK。
  4. 主机发送寄存器地址/子地址(可选,取决于设备)。
  5. 从机应答ACK。
  6. 主机发送数据字节,每字节后从机应答ACK。
  7. 主机产生停止条件(P),释放总线。

读操作流程与写操作类似,但在发送从机地址和寄存器地址后,主机需要产生重复起始条件(Sr),然后发送从机地址 + 读位(R/W=1),之后主机变为接收者,从机发送数据。

Zephyr实现提示: 在Zephyr中,I2C从机驱动通常使用i2c_slave_register()注册回调函数。回调函数需要处理I2C_SLAVE_WRITE_REQUEST和I2C_SLAVE_READ_REQUEST事件。注意:从机在写请求中接收数据,在读请求中发送数据,方向与主机视角相反。

2.7 多主机仲裁与时钟拉伸

仲裁(Arbitration): 当多个主机同时尝试控制总线时,通过SDA线的“线与”特性进行仲裁。哪个主机先拉低SDA,哪个主机就赢得仲裁,失去仲裁的主机必须释放总线。

时钟拉伸(Clock Stretching): 从机可以拉低SCL线,强制主机等待,直到从机准备好继续传输。这在从机处理速度较慢时非常有用。

特性 仲裁 时钟拉伸
发起方 多个主机 从机
作用线 SDA SCL
目的 决定哪个主机继续控制总线 让主机等待从机准备好
Zephyr支持 硬件自动处理 需在设备树中配置超时时间
常见陷阱: 在Zephyr I2C从机驱动中,如果从机在中断服务函数中处理时间过长,会导致时钟拉伸超时。建议在回调函数中只做数据拷贝,将耗时处理放到线程上下文中。同时,确保设备树中clock-stretch-timeout属性设置合理(通常为50~100ms)。