I2C 总线协议
1、协议介绍
IIC(Inter-Integrated Circuit)协议也称为 I2C 总线,是一种串行通信协议,通常用于连接低速外设。它由 Philips(现在的NXP Semiconductors)公司于 1980 年代初开发,现在已经成为一个标准。IIC 总线只需要两条数据线,分别是串行数据线(SDA)和串行时钟线(SCL),这使得它成为一种非常简单的接口。
I2C 有利于设计人员在系统的众多节点之间建立简单、双向、灵活的通信。I2C 仅使用两条双向线来发送和接收信息,从而降低了复杂性。它还允许设计人员配置多个主节点系统 IC 之间的通信
下表总结了 I2C 的关键特性:
特性 | 规格 |
---|---|
导线 | 2 |
最大速度 | 标准模式 = 100 kbps 快速模式 = 400 kbps 高速模式 = 3.4 Mbps 超快速模式 = 5 Mbps |
同步或异步? | 同步 |
串行或并行? | 串行 |
最大主器件数 | 无限制 |
最大节点数 | 1008 |
2、数据传输
2.1 起始/结束信号
总线上有这么多器件,显然需要靠地址来确定访问哪一个器件。主器件与从器件的通信需要发送一个开始条件和一个结束条件。如下图所示:
- 开始条件:SCL high, SDA high-to-low 转换
- 结束条件:SCL high, SDA low-to-high 转换
2.2 数据传输
开始条件发送之后,就可以传输数据了,如下图所示 I2C 协议要求:
- 传输时钟 SCL high 期间,数据线 SDA 必须保持稳定(这是起始、结束信号生效的必要条件)
- 在 SCL low 期间,数据 SDA 才能改变
- 必须遵守相关时序(例如数据保持时间至少为300ns)
2.3 ACK
I2C 最大的一个特点就是有完善的应答机制,从机接收到主机的数据时,会回复一个应答信号来通知主机表示“我收到了”。应答信号: 出现在 1 个字节传输完成之后,即第 9 个 SCL 时钟周期内,此时主机需要释放 SDA 总线,把总线控制权交给从机,由于上拉电阻的作用,此时总线为高电平,如果从机正确的收到了主机发来的数据,会把 SDA 拉低,表示应答响应。
- 应答位(ACK):当发送方传送完 8 位时,发送方释放 SDA,由接收方控制 SDA,且 SDA=0
- 否应答位(NACK):当发送方传送完 8 位时,发送方释放 SDA,由接收方控制 SDA,且 SDA=1
这表示 IIC 的应答机制 - SCL from master 波形:SCL,主机产生的时钟脉冲
- data output by transmitter 波形:SDA,主机发送的 8 位数据
- data output by receiver 波形:SDA,从机在第 9 个时钟信号进行拉低回应,表示收到了主机发来的数据,拉高则表示不应答
注:实际上,上面和中间是同样的 SDA 线,这里只是分开示意。因为 IIC 应答是一种相互关系,单片机发数据给 IIC 器件,IIC 器件要进行应答,表示收到了数据,同样,单片机接收 IIC 器件的数据后,也要给 IIC 器件一个应答。
非应答信号可能是主机产生也可能是从机产生,产生非应答信号的情况主要有以下几种:
- I2C总线上没有主机所指定地址的从机设备
- 从机正在执行一些操作,处于忙状态,还没有准备好与主机通讯
- 主机发送的一些控制命令,从机不支持
- 主机接收从机数据时,主机产生非应答信号,通知从机数据传输结束,不要再发数据了
3、关于从设备地址
地址位支持 7 bit、10 bit,主设备如果需要向从机发送/接收数据,首先要发送对应从机的地址,然后会匹配总线上挂载的从机的地址,故地址为主要用来辨识不同设备。地址位由主机发送,从设备负责接受并识别该地址是否位自己地址。
从设备地址格式如下:
D7 D6 D5 D4 D3 D2 D1 D0
- 器件类型由:D7-D4 共 4 位决定的。这是由半导公司生产时就已固定此类型的了,也就是说这 4 位已是固定的
- 用户自定义地址码:D3-D1共 3 位。这是由用户自己设置的,通常的做法如 EEPROM 这些器件是由外部 IC 的 3 个引脚所组合电平决定的(用常用的名字如 A0,A1,A2)。这也就是寻址码。所以为什么同一 IIC 总线上同一型号的 IC 只能最多共挂 8 片同种类芯片的原因了
- 最低一位就是 R/W 位
对于 7 bit 地址模式来说,如果在芯片手册上看到的地址是 0xD0,那么要注意,驱动中应该填写的 I2C 设备地址可能为:0XD0 >> 1 = 0x68。因为驱动中填写的设备地址,是不包括 R/W 位的!
4、实际应用
I2C 设备驱动开发中,尤其要注意 I2C 设备硬件上的时序,要阅读设备手册。例如:对于 pca955 I2C 转 IO 驱动,读取数据过程:
- step1 :START+器件地址(R/W bit 置为0,执行写)+ 寄存器地址
- step2 : 重复 START+器件地址(R/W bit置为1,执行读)+ 从器件输出data(1个或多个byte)+STOP
注意:如果没有 step1,直接执行 step2 就是顺序读的操作,因为每次读写 1 个 byte 内部的寄存器地址都会加 1,所以顺序读就是以上次读写之后的寄存器地址为起点,继续读下去。
写数据过程:
- step1 :START+器件地址(R/W bit 置为0,执行写)+寄存器地址
- step2:要写的数据(注意 step1 和 step2 之间没有 start 信号)
5、关于仲裁机制
I2C 的一大特点是可以在同一条总线上接多个主机。两个及以上的主机同时发起传输请求时,需要通过某种机制确定哪个主机获得总线的使用权;另外,每个主机都独立产生时钟,时钟速率可能千差万别,这也需要某种机制解决时钟速率不一致的问题。这种机制就是时钟同步(Clock Synchronization)和仲裁(Arbitration)。在单主机的 I2C 系统中,不需要时钟同步和仲裁。
I2C 的多主模式,一般很少用到,这里只是做一个简单的拓展
5.1 SDA 仲裁
当总线上有一个以上的主机时,协议通过仲裁的方法确定哪个主机获得总线的使用权。从机不参与仲裁的过程。
I2C 采用的是有线与 (Wired-AND) 逻辑,即:
- SDA 线上的实际电平 = 所有驱动它的器件的逻辑与(AND)运算结果
- 低电平(0)“更强”,即任何设备如果想输出低电平(0),则 SDA 线上一定是低电平
- 高电平(1)需要所有设备都不拉低 SDA,才能保持高
仲裁过程
- 两个主设备同时开始通信
- 设备 A 和 设备 B 都作为主设备,同时发送数据
- 发送数据的过程中,每个设备都会检查 SDA 的实际电平
- 例如,设备 A 发送的是 0x3C (0011 1100),设备 B 发送的是 0x38 (0011 1000)
- 在前四位 “0011” 期间,两个设备发送的数据相同,SDA 电平不会产生冲突
- 冲突发生
- 设备 A 发送第 5 位 “1”,试图拉高 SDA
- 设备 B 发送第 5 位 “0”,试图拉低 SDA
- 由于 I2C 的 Wired-AND 机制,SDA 线被拉低
- 仲裁结果
- 设备 A 发现它想发送 1(高电平),但 SDA 实际上是 0(低电平)
- 这说明 有另一个设备正在发送低电平,且比自己优先级更高
- 按照 I2C 规则,设备 A 立即停止发送,退出仲裁
- 设备 B 继续发送数据,赢得仲裁,成为总线的唯一主设备
由此可见,在仲裁过程中胜出的主机是没有丢失数据的。在仲裁中失去总线控制权的主机在本次字节传输结束后继续产生时钟,并在总线空闲时开始上次数据的重传。
如果同一个器件可以工作在主从两种模式,它在仲裁过程中失去总线控制权,那么有可能是仲裁胜出的主机将要访问该器件,该器件应该立即切换到从机模式。

5.2 SCL 时钟同步
时钟同步只会在仲裁时发生。SCL 是由主机产生的时钟信号,用于和从机确定数据发送和采样的时间点。倘若处在仲裁期间,会有多个主机同时发送往 SCL 上发送时钟信号。两个主机配置的通信速率可能不同,因此时钟频率必然不同;即使配置了相同的通信速率,两者开始发送数据的时间也不同。此时时钟信号具体如何确定就要通过 clock synchronization 的机制。
在总线空闲的时候,SCL 被上拉电阻拉高。开始通信后,主机的时钟信号接入 SCL 中。如下图所示,有两个主机(时钟信号分别为 CLK1 和 CLK2,其中 CLK1 时钟频率更高)都认为主机空闲,因此开始将时钟信号输入 SCL。同步分为以下五个阶段:
-
CLK1 率先变为低电平,由于线与特性 CLK2 也变成低电平
-
但是 CLK2 的低电平时间更长,即使主机 1 内部的 CLK1 已经变成高电平,SCL的实际电平仍然和 CLK2 保持一致。此时,主机 1 将会检测到这一情况,并从此时开始计数(计算低电平持续的时间,即下图中的 wait state,稍后用)
-
CLK2 迎来高电平之后,主机 1 内部的 wait state 结束,因为两者都为高,因此 SCL 总线进入高电平,两个主机内部都会开始对高电平持续的时间进行计数
-
随后,CLK1 会比 CLK2 先回到低电平
-
现在,CLK1 以及获得了需要延长的低电平时间,CLK2 也获得了需要减短的高电平时间(最右边的虚线部分),两个主机会根据之前的计数重新调整自己的时钟周期,从而完成时钟同步
例如,在时钟同步之前,主机 1 的速度为 400kbit/s(fast mode),主机 2 的速度为 100kbit/s(standard mode),同步之后,速度都会变为 100kbit/s。如果两者的通信速率本就相同,但也会因为 CLK 的开始时间不一样而出现错位,这同样会通过时钟同步而矫正。
关于时钟同步的原始描述,可以参见 I2C-bus specification and user manual