1、I2C协议简介与总线信号归纳总结

各位工程师朋友,咱们开始聊I2C。这门课叫《I2C总线恢复期间错误位处理与重试》,但我个人习惯,讲怎么修车之前,得先把发动机拆开看看。嗯,第一讲,咱们就回到I2C最根本的东西:它到底怎么工作的,总线上的信号长什么样。

1.1 从两根线说起

I2C,全称 Inter-Integrated Circuit,是飞利浦公司在80年代搞出来的。初衷很简单:让芯片之间用最少的线连起来。结果呢?两根线——SCL(时钟线)和SDA(数据线)——统治了嵌入式世界几十年。

你想想看,一根时钟线,一根数据线。所有设备挂在这两根线上,靠地址区分。主设备发起通信,从设备响应。没有片选线,没有中断线。就这么简单,但坑不少。

核心特征速览:

  • 物理层:开漏输出 + 上拉电阻。任何设备都可以拉低总线。
  • 主从架构:谁控制时钟谁就是主设备,同一时刻只能有一个主设备在总线。
  • 地址机制:7位地址(标准模式),或者10位地址(扩展模式),后者用得少。
  • 速度等级:标准模式100 kHz,快速模式400 kHz,高速模式3.4 MHz。

我在项目中遇到过最典型的问题:新手把I2C当成SPI来用,以为SCL不用管。大错特错。SCL是所有时序的基准,没有SCL就没有I2C。严格来说,SCL必须由主设备驱动,从设备只能通过时钟拉伸(Clock Stretching)来拉低SCL,但那个是后面几讲才聊的恢复机制。

1.2 总线信号归根结底就五种

别看I2C协议手册几百页,其实总线上的信号,拆解开来,就五种状态。我每次调试都默念这五个:起始、数据、应答、暂停、停止。

  1. 起始条件(S):SCL高电平时,SDA从高变低。
  2. 数据位传输:SCL低电平时,SDA改变电平;SCL高电平时,SDA稳定并被采样。
  3. 应答位(ACK/NACK):每字节第9个SCL周期,由接收方拉低SDA表示ACK,不拉低表示NACK。
  4. 重复起始条件(Sr):跟起始条件一样,但发生在传输中间。这是I2C不释放总线的关键。
  5. 停止条件(P):SCL高电平时,SDA从低变高。

我曾经踩过的坑:调试一个车载传感器,总线老是卡死。示波器一抓发现,从设备在第9个时钟拉了低电平——但那个位置根本不是应答位,是数据位。原来是我代码里把从设备地址发错了,导致它在错误时刻产生了应答冲突。所以,必须从根上搞懂这五种信号,否则后面所有恢复策略都是瞎蒙。

1.3 一个完整的I2C写操作长这样

咱们来看一个典型的I2C写操作,往一个EEPROM里写一个字节。我建议你对照示波器看这段伪代码,印象更深。

// I2C 写操作流程(伪代码)
// 假设从设备地址 0x50,内部寄存器地址 0x10

1. 主设备 发送 起始条件 (S)
2. 主设备 发送 从设备地址 + 写位 (0xA0)   // 7位地址0x50左移1位 + 0
3. 从设备 回复 应答 (ACK)
4. 主设备 发送 内部寄存器地址 (0x10)
5. 从设备 回复 应答 (ACK)
6. 主设备 发送 要写的数据 (0xAB)
7. 从设备 回复 应答 (ACK)
8. 主设备 发送 停止条件 (P)

实际项目建议:每次发完停止条件后,等待5ms再发起下一次通信。有些EEPROM在写周期内部擦写时,对任何I2C信号都不响应,包括停止条件。你发完P立刻再发S,可能会被忽略,导致通信错乱。

1.4 I2C协议的三层结构

我个人习惯把I2C协议分成三层来理解。你调试的时候,哪层出问题,症状完全不一样。

层 定义 典型故障 调试手段
物理层 开漏结构、上拉电阻、电平匹配、总线电容 SDA卡死低、SCL毛刺、边沿过缓 示波器量波形、查IO配置、换上拉电阻
数据链路层 起始/停止条件、字节格式、应答机制、仲裁、时钟拉伸 无应答、字节丢失、总线挂死、地址冲突 逻辑分析仪抓完整包、查ACK位
应用层 设备特定协议、寄存器读写命令、页写入等 数据错位、地址越界、等待超时 查数据手册、状态机跟踪

你看看这张表,物理层出了问题,你修数据链路层是没用的。上拉电阻没选好,总线电容过大,你再怎么重试都是白搭。所以,学习错误恢复之前,先把这三个层次分清楚。

1.5 一个图看懂I2C通信骨架

光说不行,我画一张图,你一眼就能看明白I2C通信的整体骨架。这张图我用了很多年,每次给团队做培训,第一张PPT就是这个。你把它存下来,调试时贴在旁边。

I2C协议通信骨架与信号层次 物理层:SCL+SDA 开漏输出 + 上拉电阻 VCC / 地 / 噪声 数据链路层:信号序列 起始 → 地址 → 应答 数据 → 应答 → 停止 仲裁 & 时钟拉伸 应用层:动作 读 / 写 / 寄存器 多字节 / 页写入 五种核心信号:S · 数据位 · ACK/NACK · Sr · P 提供信号载体 封装成动作 调试核心思路 • 波形不对先查物理层:上拉电阻、电平匹配、总线电容 • 无应答先查数据链路层:地址对不对、ACK检没检

嗯,这张图把三层结构和五种核心信号串起来了。我每次调I2C遇到问题,第一件事就是问自己:这问题是物理层的、数据链路层的、还是应用层的?物理层的波形干净吗?数据链路层有没有收到ACK?应用层的寄存器地址写对了吗?

往后的课程,咱们所有关于总线恢复和重试的讨论,都会回到这张图上来。你先把它吃透,后面讲各种异常恢复方案时,你就知道我在说什么了。