一文搞懂 I2C 总线通信
本来不打算写这篇文章,因为网上关于 I2C 总线通信的资料很多很全。但是最近刚换工作,主要做驱动开发,第一个驱动就是 I2C 通信,想了想还是结合网上的资料再整理下思路,方便今后的查阅和温习。
1、简介
I2C(集成电路总线),由 Philips 公司(2006 年迁移到 NXP)在 1980 年代初开发的一种简单、双线双向的同步串行总线,它利用一根时钟线和一根数据线在连接总线的两个器件之间进行信息的传递,为设备之间数据交换提供了一种简单高效的方法。每个连接到总线上的器件都有唯一的地址,任何器件既可以作为主机也可以作为从机,但同一时刻只允许有一个主机。
I2C 标准是一个具有冲突检测机制和仲裁机制的真正意义上的多主机总线,它能在多个主机同时请求控制总线时利用仲裁机制避免数据冲突并保护数据。作为嵌入式开发者,使用 I2C 总线通信的场景有很多,例如驱动 FRAM、E2PROM、传感器等。
总结来说,I2C 总线具有以下特点:
只需要 SDA、SCL 两条总线;
没有严格的波特率要求;
所有组件之间都存在简单的主/从关系,连接到总线的每个设备均可通过唯一地址进行软件寻址;
I2C 是真正的多主设备总线,可提供仲裁和冲突检测;
传输速度分为四种模式:
标准模式(Standard Mode):100 Kbps
快速模式(Fast Mode):400 Kbps
高速模式(High speed mode):3.4 Mbps
超快速模式(Ultra fast mode):5 Mbps
最大主设备数:无限制;
最大从机数:理论上是 127。
2、物理特性
I2C 总线使用连接设备的"SDA"(串行数据总线)和"SCL"(串行时钟总线)来传送信息。
I2C 总线内部使用漏极开路输出驱动器,因此 SDA 和 SCL 可以被拉低为低电平,但是不能被驱动为高电平,所以每条线上都要使用一个上拉电阻,默认情况下将其保持在高电平。
I2C 总线上拉电阻阻值取决于系统应用,TI 官方手册推荐使用以下公式来计算上拉电阻值:
根据上表,这里不难发现需要在做电阻选择需要满足几个条件:
灌电流最大值为 3mA;
低电平输出电压设置了最大值为 0.4V。
所以根据上述公式可以计算,对于 5V 的电源,每个上拉电阻阻值至少 1.53kΩ,而对于 3.3V 的电源,每个电阻阻值至少 967Ω。
如果觉得计算电阻值比较麻烦,也可以使用典型值 4.7kΩ。若各位想了解更多可直接参见手册说明。
3、通讯时序
通常情况下,一个完整的 I2C 通信过程包括以下 4 部分:
开始条件
地址传送
数据传送
停止条件
主机在 SCL 线上输出串行时钟信号,数据在 SDA 线上进行传输,每传输一个字节(最高位 MSB 开始传输)后面跟随一个应答位,一个 SCL 时钟脉冲传输一个数据位。
标准的 I2C 时序如下图所示:
3.1、开始和停止条件
当总线上的主机都不驱动总线,总线进入空闲状态,SCL 和 SDA 都为高电平。总线空闲状态下总线上设备都可以通过发送开始条件启动通信。
当 SCL 线为高时,SDA 线上出现由高到低的信号,表明总线上产生了起始信号。SDA 线上出现由低到高的信号,表明总线上产生了停止信号,如下图所示:
当两个起始信号之间没有停止信号时,即产生了重复起始信号。主机采用这种方法与另一个从机或相同的从机以不同传输方向进行通信(例如:从写入设备到从设备读出)而不释放总线。如下图所示:
3.2、地址传送
开始条件或者重新开始条件后面的帧是地址帧(一个字节),用于指定主机通信的对象地址,在发送停止条件之前,指定的从机一直有效。
I2C 通讯支持:7 位寻址和 10 位寻址两种模式。
7 位寻址模式,地址帧(8bit)的高 7 位为从机地址,地址帧第 8 位来决定数据帧传送的方向:7 位从机地址 + 1 位读/写位,读/写位控制从机的数据传输方向(0:写;1:读)。帧格式如下所示:
10 位寻址模式,主机发送帧,第一帧发送头序列(11110XX0,其中 XX 表示 10 位地址的高两位),然后第二帧发送低八位从机地址。 主机接收帧,第一帧发送头序列(11110XX0,其中 XX 表示 10 位地址的高两位),然后第二帧发送低八位从机地址。接下来会发送一个重新开始条件,然后再发送一帧头序列(11110XX1,其中 XX 表示 10 位地址的高两位)帧格式如下所示:
解析如下:
S :表示开始条件;
SLA :表示从机地址;
R/W#:表示发送和接收的方向。当 R/W# 为“1” 时,将数据从从机发送到主机;当 R/W#为“0” 时,将数据从主机发送到从机;
Sr :表示重新开始条件;
DATA :表示发送和接收的数据;
P :表示停止条件。
3.3、数据传送
地址匹配一致后,总线上的主机根据 R/W 定义的方向一帧一帧的传送数据。 所有的地址帧后传送的数据都视为数据帧。即使是 10 位地址格式的低 8 位地址也视为数据帧。
数据帧的长度是 8 位。SCL 的低电平 SDA 变化,SCL 的高电平 SDA 保持,每个时钟周期发送一位数据。数据帧后的第 9 个时钟是应答位,是接收方向发送方传送的握手信号。
如果总线上从机接收数据,在第 9 个时钟周期不响应主机,从机必须发送 NACK。如果总线上主机接收数据,第 9 个周期发送 NACK,从机接收到 NACK,从机停止发送数据。
无论主机还是从机发送了 NACK,数据传送终止。主机可以做下列任一动作:
发送停止条件释放总线 ;
发送重新开始条件开始一个新的通信。
以华大 MCU(HC3F4A0 系列)为例,在主机接收模式中,主机输出 SCL 时钟,接收从机数据并返回应答。主机接收数据的运行时序例如下图所示:
在主机接收模式中,主机输出 SCL 时钟,接收从机数据并返回应答。主机接收数据的运行时序例如下图所示:
在从机发送模式中,接收来自主机的 SCL 时钟,本产品为从机发送数据,并且接收主机返回应答。从机发送数据的运行时序例如下图所示:
在从机接收模式中,接收来自主机的 SCL 时钟和数据,接收完数据后返回应答。从机接收数据的运行时序例如下图所示:
3.4、总线应答
每传输一个字节,后面跟随一个应答位。通过将 SDA 线拉低,来允许接收端回应发送端。ACK 为一个低电平信号,当时钟信号为高时,SDA 保持低电平则表明接收端已成功接收到发送端的数据。 当主机作为发送器件时,如果从机上产生无响应信号(NACK),主机可以产生停止信号来退出数据传输,或者产生重复起始信号开始新一轮的数据传输。当主机作为接收器件时,发生无响应信号(NACK),从机释放 SDA 线,使主机产生停止信号或重复起始信号。
3.5、总线仲裁
I2C 总线上的仲裁分为两个部分:SCL 线上的同步和 SDA 线上的仲裁。
SCL 线上的同步(时钟同步)
由于 I2C 总线具有线“与”的逻辑功能,SCL 线上只要有一个节点发送低电平,总线上就表现低电平。当所有的节点都发送高电平时,总线才能表现为高电平。所以,时钟低电平的时间由时钟电平期最长的器件决定,而时钟的高电平时间由时钟高电平期最短的器件决定。
由于 I2C 这种特性,当多个主机同时发送时钟信号时,在总线上表示的是统一的时钟信号。如果从机希望主机降低传送速度可以通过将 SCL 主动拉低延长其低电平时间来通知主机,当主机在准备下一次传送时发现 SCL 的电平被拉低时进行等待,直到从机完成操作并释放 SCL 线的控制权。
SDA 线上的仲裁
SDA 线上的仲裁也是由于 I2C 总线具有线“与”的逻辑功能。主机在发送数据后,通过比较总线上的数据来决定是否退出竞争。丢失仲裁的主机立即切换到未被寻址的从机状态,以确保自身能被仲裁胜利的主机寻址到。仲裁失败的主机继续输出时钟脉冲(在 SCL 上),直到发送完当前的串行字节。通过这种原理可以保证 I2C 总线在多个主机企图控制总线时保证数据的不丢失。
解析如下:
(1)另一器件发送串行数据;
(2)另一器件通过拉低 SDA 先撤消了该 I2C 主机发送的一个逻辑 1(虚线)。仲裁丢失,I2C 进入从接收模式;
(3)此时 I2C 处于从接收模式,但仍产生时钟脉冲,直至发送完当前字节。I2C 将不为下个字节的传输产生时钟脉冲。一旦赢得仲裁,SDA 上的数据传输由新的主机来启动。
4、工作过程
最后整体叙述一下 I2C 通讯过程,本小节内容整理来源于:微信公众号:小麦大叔,作者菜刀和小麦。
第 1 步:起始条件
主设备通过将 SDA 线从高电平切换到低电平,再将 SCL 线从高电平切换到低电平,来向每个连接的从机发送启动条件,如下图所示:
第 2 步:发送从设备地址
主设备向每个从机发送要与之通信的从机的 7 位或 10 位地址,以及相应的读/写位,如下图所示:
第 3 步:接收应答
每个从设备将主设备发送的地址与其自己的地址进行比较。如果地址匹配,则从设备通过将 SDA 线拉低一位以表示返回一个 ACK 位。
如果来自主设备的地址与从机自身的地址不匹配,则从设备将 SDA 线拉高,表示返回一个 NACK 位。
第 4 步:收发数据
主设备发送或接收数据到从设备,如下图所示:
第 5 步:接收应答
在传输完每个数据帧后,接收设备将另一个 ACK 位返回给发送方,以确认已成功接收到该帧,如下图所示:
第 6 步:停止通信
为了停止数据传输,主设备将 SCL 切换为高电平,然后再将 SDA 切换为高电平,从而向从机发送停止条件,如下图所示:
4.1、单个主设备连接多个从机
I2C 总线上的主设备使用 7 位地址对从设备进行寻址,可以使用 128(2 的 7 次方)个从机地址,如下图所示:
4.2、多个主设备连接多个从机
多个主设备可以连接到一个或多个从机。
当两个主设备试图通过 SDA 线路同时发送或接收数据时,同一系统中的多个主设备就会出现问题。
为了解决这个问题,每个主设备都需要在发送消息之前检测 SDA 线是低电平还是高电平;
如果 SDA 线为低电平,则意味着另一个主设备可以控制总线,并且主设备应等待发送消息;
如果 SDA 线为高电平,则可以安全地发送消息。
拓展学习:
1、I2C Bus
2、https://www.nxp.com.cn/docs/en/application-note/AN10216.pdf
版权声明: 本文为 InfoQ 作者【不脱发的程序猿】的原创文章。
原文链接:【http://xie.infoq.cn/article/2df47efb2f510af4c6755fe3f】。文章转载请联系作者。
评论