[导读] 前文总结了单片机串口个人认为值得注意的一些要点,本文来梳理一下 I2C 总线的一些要点。这个题目有点大,本文对于 I2C 其实很多地方也没整清楚,只为了与前文形成系列,如果大家有补充欢迎留言。说了些闲话,进入正题吧。
I2C 之前世今生(Inter-Integrated Circuit),是一种同步、多主、多从、分组交换、单端、串行计算机总线,由飞利浦半导体(现在的 NXP 半导体)在 1982 年发明。它广泛用于在短距离、板内通信中将低速外设集成电路附加到处理器和微控制器上。 也可以写成 I2C 或 IIC。
自 2006 年 10 月 10 日起,实施 I2C 协议不需要任何许可费用。但是,获得恩智浦分配的 I2C 从设备地址则需要付费。一些竞争者如西门子(后来的英飞凌技术,现在的英特尔移动通信)、NEC、德州仪器 TI、意法半导体(以前的 SGS-Thomson)、摩托罗拉(后来的飞思卡尔,现在与 NXP 合并)、Nordic 半导体和 Intersil,自 20 世纪 90 年代中期以来已经陆续发布了很多兼容的 I2C 标准的芯片。
说到总线,其种类很多,但其目的基本一致,就是一个用于传递信息的公共干线。如芯片内部地址总线、数据总线其对象可能为CPU核与各外设(RAM/ROM/外设控制器电路等);芯片级总线I2C,SPI等,设备级总线如RS422/RS485/HART/CAN/Ethernet/Fieldbus......
自 Version 4 之后 I2C 支持下面几种模式:
双向总线:
standard-mode(Sm): ≤100 Kbit/S
Fast-Mode(Fm):≤400 Kbit/S
Fast-mode Plus(Fm+):≤1Mbit/S
High-speed mode (Hs-mode): ≤ 3.4 Mbit/s
单向总线:
Ultra Fast-mode (UFm): ≤ 5 Mbit/s
I2C 标准能带来些啥好处呢?
简单的 2 线串行 I2C 总线最小化互连,节省 PCB 布板走线空间;
完全集成的 I2C 总线协议消除了地址解码器。
I2C 总线的多主控能力允许终端用户设备通过外部连接到装配线进行快速测试和校准。
标准支持广泛,大量无铅封装 I2C 总线兼容集成芯片进一步降低了空间需求。
系统管理总线(SMBus),由 Intel 在 1995 年定义,是 I2C 的一个子集,定义了更严格的用法。SMBus 的一个目的是促进健壮性和互操作性。因此,现代 I2C 系统合并了来自 SMBus 的一些策略和规则,有时同时支持 I2C 和 SMBus,只需要通过命令或输出引脚使用最小限度的重新配置。
TWI(双线接口)或 TWSI(双线串行接口),本质上是在 Atmel 和其他供应商的各种系统芯片处理器上实现的同一总线。
I2C 拓扑结构从概念上,I2C 总线有两根线 SDA/SCL 就可以连一堆芯片,实现很多的应用。连接拓扑极简!
比如这样一个系统:
LCD 显示
ADC 采样
EEPROM/FRAM 非易失存储
温度采集
.....
接下来看看各模式下,连接拓扑图:
标准速度/快速模式:
高速模式拓扑:
混速模式拓扑:
如果使用 IO 口模拟 I2C 总线,或者使用 FPGA 实现 I2C 接口,深刻理解 I2C 时序波形无疑是重点中的重点!即使使用内置的 I2C 控制器外设实现一个 I2C 总线编程,在调试底层时或者踩坑过程中,深入理解时序波形原理,也是非常必要的!
时序图I2C 的时序图如下:
START 事件:可以联想一下 UART 的起始位,这个用于通知 I2C 通信的发起。用一句话描述就是在 SCL 常高时,采集到 SDA 高到低跳变,这就是启动事件。
数据有效性:SDA 线上的数据必须在时钟的高周期保持稳定。数据线的高或低状态只能在 SCL 线上的时钟信号低时改变。每个传输的数据位产生一个时钟脉冲。
ACK:确认信号 ACK 的定义如下:发送器在 ACK 时钟脉冲期间释放 SDA 线,因此接收器可以将 SDA 线拉低,并在此时钟脉冲的高电平期间保持稳定的低电平(见上图)。须严格遵循电气的建立保持时间,使用时需要用示波器去严格测试信号是否能满足这些参数。
NACK:当在第九个时钟脉冲期间 SDA 保持高电平时,这被定义为“NACK”信号。之后主机可以产生停止条件以中止传输,或产生重复的开始条件以开始新的传输。导致 NACK 产生的条件有五个:
总线上没有报文中所包含地址的接收器,因此没有设备响应应答。
接收器无法执行接收或发送操作,比如它正在执行某些实时功能,并且尚未准备好与主机进行通信。
在传输过程中,接收器收到应用协议不理解的数据或命令。
在传输期间,接收器无法再接收更多有效数据字节。比如程序或者芯片内置缓冲区已经满了
主接收器用 NACK 通知从发送器结束传输。这是何意呢?比如主设备已经接受到足够多的数据,不希望从设备发送更多的数据时,就可以 NACK 从设备,这样从设备就会停止发送
时钟同步:两个主机可以同时开始在空闲总线上进行传输,并且必须有一种方法来确定控制总线并完成其传输的方法。这是通过时钟同步和仲裁完成的。在单主机系统中,不需要时钟同步和仲裁。
时钟同步是通过 I2C 接口中 SCL 线的线与实现的。啥意思呢?
这里的几句话需要划重点去理解,这就是 I2C 总线的核心之核心工作原理:线与!
当 SCL 从高到低的过渡时,总线上的主机开始计数其低电平时间,且一旦主机时钟变为低,它就会将 SCL 保持在该状态,直到变为高状态为止。
但是,如果另一个主机时钟仍在其低周期内,则此时钟从低到高的转变不会改变 SCL 线的状态。所以,SCL 线由主机以最长的低电平周期保持为低电平。低电平周期较短的主机在此期间进入高电平等待状态。
上面的话不好理解?看看线与的本质是与,啥叫与呢?比如 C=A&B,只要其中一个变量 A/B 为低,那么 C 就必然为 0,比如下图中,即便 CLK1(为其中一个主机)为高了,但奈何另一主机的 CLK2 任然为低啊?所以 SCL 线上测出来就是低。
当所有相关的主机都计数完低电平周期后,时钟线被释放并变为高电平。这样,主时钟和 SCL 线的状态之间就没有区别,所有主时钟都开始计数其高电平周期。第一个完成其高电平周期的主机将 SCL 线再次拉低。
仲裁:仲裁与同步类似,仅在系统中使用多个主机时才会涉及到,从站不参与仲裁过程。首先要理解一下仲裁是干啥的?所谓仲裁就是在多主机模式下,哪一个主机能获取介质的访问权限,获得权限的主机才可以传输 I2C 通信报文。只有在总线空闲时,主机才可以开始传输。两个主机可以在 START 的最小保持时间内产生 START 条件这种情况会导致总线上出现有效的 START 条件。然后需要仲裁以确定哪个主机将完成其传输。
仲裁是一位一位地进行。节点发送 1 个位后,回读比较总线上所呈现的数据与自己发送的是否一致。是,继续发送;否则,退出竞争。SDA 线的仲裁可以保证 I2C 总线系统在多个主节点同时企图控制总线时通信正常进行并且数据不丢失。总线系统通过仲裁只允许一个主节点可以继续占据总线
上图显示了两个主机的仲裁程序。实际使用中连接到总线的主机数量可能会更多。当主机产生的 DATA1 的内部数据电平与 SDA 线上的实际电平之间存在差异时,DATA1 输出将关闭。从而主机 1 退出竞争,没有获得总线的控制权。
时钟延长:时钟延长通过将 SCL 线保持为低电平来暂停事务。直到再次释放高电平,事务才能继续。时钟延长是可选的,实际上,大多数从设备不包括 SCL 驱动能力,因此它们无法延长时钟。
为啥要设计这样一个机制呢?个人理解是为了增强系统的健壮性而设计的:
在字节传输级别,设备可能能够以快速速率接收数据字节,但需要更多时间来存储接收到的字节或准备另一个要发送的字节。此时,从机可以在接收和确认字节后将 SCL 线保持为 LOW,以强制主机进入等待状态,直到从机为握手过程中的下一个字节传输做好准备。
在位级别上,诸如微控制器之类的设备可以通过延长每个时钟的 LOW 周期来减慢总线时钟。任何主机的速度都将根据该设备的内部工作速率进行调整。
7 位地址:分读写两种情况
10 位地址:分读写两种情况
保留地址
通用广播地址用于同时寻址连接到 I2C 总线的所有设备。但是,如果设备不需要处理广播数据,则可以通过不发出 ACK 来忽略该地址。如果某设备需要来自通用广播地址的数据,它将发送 ACK 给该地址并充当从接收器。主机实际上不知道有一个或多个设备响应时确认了广播数据(不确定有多少个 ACK)。每个能够处理此数据的从机接收器都会确认第二个字节和随后的字节。无法处理这些字节的从机将不应答从而忽略。同样,如果一个或多个从机应答,则主机不会看到未确认的消息。通用广播地址的含义总是在第二个字节中指定,如下图:
1.当 B 为 0 时,第 2 字节定义如下:
0000 0110(06h):设备将复位以及设置地址的可编程部分。接收到这个 2 字节命令后,所有支持响应通用广播地址的设备将复位,并将其地址的可编程部分改写保存。须采取预防措施以确保设备在施加电源电压后不会拉低 SDA 或 SCL 线,因为这些低电平会阻塞总线。
0000 0100 (04h):收到该命令后设备将通过硬件设置地址的可编程部分。(Write programmable part of slave address by hardware).
0000 0000 (00h): 不允许将此代码用作第二个字节.
对于 06h/04h 这两个命令,有些不太好理解。复位比较好理解。对于设置设备地址的可编程部分可能很多没有遇到过的朋友则不太好理解。这里来一个实际芯片的例子,以 Microchip 的 MCP3423/MCP3424 为例进行描述一下,MCP3423/MCP3424 是一颗多通道 ADC 芯片,其芯片引脚如下:
当接收到通用广播访问且第 2 字节为 06h 命令后,芯片做两件事情:
芯片复位如上电复位的行为一样
同时锁住 Adr1/Adr0 的电平作为地址,这两位地址为芯片地址的可编程部分。
当然对于不同的芯片,具体如何实现通用广播地址的处理则各有不同,只需要认真阅读芯片的手册就能获取相应信息。这里仅仅就通用广播地址举个栗子,方便理解。老实说这个功能好像不太常见,具体有什么用?我反正没这么用过,感觉这功能有点蛋疼(直接用电阻配置好不更省事?)。如果有好的应用实例场景,欢迎留言交流。
2.当 B 为“ 1”时,则该 2 字节序列为“硬件通用呼叫”。该报文由 I2C 主设备(例如键盘扫描器)发送,可以对其进行编程以发送所需的从地址。由于 I2C 主设备事先不知道该消息必须传输到哪个从设备,故利用通用广播地址及通用呼叫命令并将自身的地址放在高 7 位,从而标识总线上发送通用硬件呼叫的设备 ID。该地址由连接到总线的智能设备识别(比如该智能设备是一个单片机系统),然后该智能设备从硬件主机接收信息。如果硬件主机也可以充当从机,则从机地址与主机地址相同。
所以标准中定义这个功能,可以做些自适应应用,只需要制定出相应协议就可以完成比较灵活的多主通信应用协议。
软复位如上面描述,当通用广播地址后面跟 06h 字节,就可以使从设备软复位。但这个功能并非所有芯片都支持,具体使用的时候需要仔细阅读芯片手册是否支持该功能。
须采取预防措施以确保设备在施加电源电压后不会拉低 SDA 或 SCL 线,因为这些低电平会阻塞总线。
起始 START 字节单片机/DSP 可以用两种方法连接到 I2C 总线:
有的单片机/DSP 具有片上 I2C 硬件外设,这就可以直接使用。
如果没有或者被其他功能占用,则可以使用 GPIO 去模拟 I2C 总线时序。用这个方式去实现,则比较消耗 CPU 时间,
比如在一个多单片机用 I2C 总线连一起的系统,其中一个单片机 I2C 是用 IO 口模拟的,则快速的硬件设备与依赖软件轮询的相对较慢的单片机之间存在速度差异。这个不难想象,因为依靠轮询则不是硬实时,同时单片机肯定还有其他事物需要处理,那么检测 START 条件信号就有可能丢失,导致系统不健壮。那么 I2C 标准已然考虑这种需求了。
这就是起始字节需要解决的需求,前面介绍的就是起始字节设计的背景。那么起始字节究竟是怎样的呢?
START 事件(英文叫 condition,我这样叫成一个事件有一点软件原语抽象的意思)
START 字节 0000 0001
ACK
重复 START 事件
在需要访问总线的主机发送了 START 事件之后,发送 START 字节(0000 0001)。另一个单片机/DSP 可以以低采样率对 SDA 线进行采样,直到检测到 START 字节中的七个零之一为止。在 SDA 线上检测到此 LOW 电平后,微控制器可以切换到更高的采样率,以找到重复的 START 事件,然后将其用于同步。
总线复位在异常情况下,如果时钟 SCL 被拉为 LOW 了,则有哪些办法可以对总线复位呢?
则优选的做法是如 I2C 设备具有硬件复位输入,则使用硬件复位信号来复位总线。
如果 I2C 设备没有硬件复位输入信号,如果硬件设计可以考虑用 MOSFET 控制设备电源,重新通电以激活强制性的内部上电复位(POR)电路。
还有一种做法是主机发送 9 个时钟 SCL 脉冲。使总线保持低电平的设备应在这九个时钟内的某个时间释放它。这个具体怎么做呢?主设备初始化 I2C 总线时,可以冗余加 9 个 SCL 脉冲以复位 I2C 总线,或者检测到 SCL 长时间被拉低后,可以以控制 IO 高低翻转的方式控制 SCL 产生 9 个脉冲
//可能需要先关闭I2C控制器,如果是使用I2C控制器外设实现的
//I2C_SCL根据不同硬件进行移植,delay
#define I2C_SCL P10
void soft_rst_i2c(void)
{
I2C_SCL = 1;
for(int i=0;i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?


微信扫码登录