2. I2C协议基础:总线物理层、主从机通信原理与数据帧格式
I2C(Inter-Integrated Circuit)总线是一种由Philips(现NXP)开发的同步、多主从、串行通信总线。在嵌入式系统中,I2C广泛用于连接传感器、存储器、IO扩展芯片等低速外设。理解其物理层与协议层是进行Zephyr驱动移植的前提。
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Ω。
2.2 主从机通信原理
I2C总线上的设备分为主机(Master)和从机(Slave)两种角色:
- 主机:负责产生时钟信号(SCL)、发起通信、产生起始/停止条件。一个I2C总线上可以挂载多个主机,但同一时刻只能有一个主机控制总线。
- 从机:被主机寻址并响应。从机不能主动发起传输,但可以通过时钟拉伸(Clock Stretching)机制让主机等待。
| 特性 | 主机(Master) | 从机(Slave) |
|---|---|---|
| 时钟产生 | 负责产生SCL时钟 | 不产生时钟,可拉低SCL(时钟拉伸) |
| 通信发起 | 产生起始条件(START) | 不能主动发起 |
| 地址匹配 | 发送从机地址 | 检测地址是否匹配 |
| 数据方向 | 决定读/写位 | 根据R/W位发送或接收数据 |
| 停止条件 | 产生停止条件(STOP) | 不能产生停止条件 |
2.3 起始条件与停止条件
I2C总线的数据传输以起始条件(START)开始,以停止条件(STOP)结束。这两个条件是唯一允许SDA在SCL为高电平时发生变化的时刻。
- 起始条件(S):SCL为高电平时,SDA从高电平切换到低电平。
- 停止条件(P):SCL为高电平时,SDA从低电平切换到高电平。
- 重复起始条件(Sr):在未产生停止条件的情况下,再次产生起始条件,用于改变数据传输方向而不释放总线。
2.4 数据帧格式
I2C数据帧以字节(8位)为单位传输,每个字节后跟一个应答位(ACK/NACK)。数据传输时,SDA在SCL低电平时变化,在SCL高电平时被主机采样。
字节传输顺序:
- 主机发送8位数据(MSB first,高位在前)。
- 主机释放SDA(拉高),产生第9个SCL时钟。
- 接收方在第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:主机从从机读数据(主机接收,从机发送)。
2.6 典型I2C通信流程
一个完整的I2C写操作流程如下:
- 主机产生起始条件(S)。
- 主机发送7位从机地址 + 写位(R/W=0)。
- 从机匹配地址后,在第9个时钟周期发送ACK。
- 主机发送寄存器地址/子地址(可选,取决于设备)。
- 从机应答ACK。
- 主机发送数据字节,每字节后从机应答ACK。
- 主机产生停止条件(P),释放总线。
读操作流程与写操作类似,但在发送从机地址和寄存器地址后,主机需要产生重复起始条件(Sr),然后发送从机地址 + 读位(R/W=1),之后主机变为接收者,从机发送数据。
i2c_slave_register()注册回调函数。回调函数需要处理I2C_SLAVE_WRITE_REQUEST和I2C_SLAVE_READ_REQUEST事件。注意:从机在写请求中接收数据,在读请求中发送数据,方向与主机视角相反。
2.7 多主机仲裁与时钟拉伸
仲裁(Arbitration): 当多个主机同时尝试控制总线时,通过SDA线的“线与”特性进行仲裁。哪个主机先拉低SDA,哪个主机就赢得仲裁,失去仲裁的主机必须释放总线。
时钟拉伸(Clock Stretching): 从机可以拉低SCL线,强制主机等待,直到从机准备好继续传输。这在从机处理速度较慢时非常有用。
| 特性 | 仲裁 | 时钟拉伸 |
|---|---|---|
| 发起方 | 多个主机 | 从机 |
| 作用线 | SDA | SCL |
| 目的 | 决定哪个主机继续控制总线 | 让主机等待从机准备好 |
| Zephyr支持 | 硬件自动处理 | 需在设备树中配置超时时间 |
clock-stretch-timeout属性设置合理(通常为50~100ms)。