IIC (Inter-Integrated Circuit),是一种同步、多主、多从、分组交换、单端、串行计算机总线,由飞利浦半导体(现在的 NXP 半导体)在 1982 年发明。它广泛用于在短距离、板内通信中将低速外设集成电路附加到处理器和微控制器上。IIC 也可以写成 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 支持下面几种模式:
提供5 Mhz的I2C超快速模式UfM是可用的快速I2C模式。此模式与其他I2C模式完全不同:
当前只有少数设备支持此模式。恩智浦PCU 9669是一款3通道总线控制器,具有两个5 MHz UfM和一个快速模式加FM +接口。可以选择。
超快速模式总线主要专注于LED设备,例如恩智浦(NXP)随附的LED控制器PCU9656。
I2C 标准能带来些啥好处呢?
简单的 2 线串行 I2C 总线最小化互连,节省 PCB 布板走线空间;
完全集成的 I2C 总线协议消除了地址解码器。
I2C 总线的多主控能力允许终端用户设备通过外部连接到装配线进行快速测试和校准。
标准支持广泛,大量无铅封装 I2C 总线兼容集成芯片进一步降低了空间需求。
从概念上,I2C 总线有两根线 SDA/SCL 就可以连一堆芯片,实现很多的应用。连接拓扑极简!
比如这样一个系统:
接下来看看各模式下,连接拓扑图:
如果使用 IO 口模拟 I2C 总线,或者使用 FPGA 实现 I2C 接口,深刻理解 I2C 时序波形无疑是重点中的重点!即使使用内置的 I2C 控制器外设实现一个 I2C 总线编程,在调试底层时或者踩坑过程中,深入理解时序波形原理,也是非常必要的!
I2C 的时序图如下:
START 事件:可以联想一下 UART 的起始位,这个用于通知 I2C 通信的发起。用一句话描述就是在 SCL 常高时,采集到 SDA 高到低跳变,这就是启动事件。
数据有效性:SDA 线上的数据必须在时钟的高周期保持稳定。数据线的高或低状态只能在 SCL 线上的时钟信号低时改变。每个传输的数据位产生一个时钟脉冲。
ACK:确认信号 ACK 的定义如下:发送器在 ACK 时钟脉冲期间释放 SDA 线,因此接收器可以将 SDA 线拉低,并在此时钟脉冲的高电平期间保持稳定的低电平(见上图)。须严格遵循电气的建立保持时间,使用时需要用示波器去严格测试信号是否能满足这些参数。
NACK:当在第九个时钟脉冲期间 SDA 保持高电平时,这被定义为“NACK”信号。之后主机可以产生停止条件以中止传输,或产生重复的开始条件以开始新的传输。导致 NACK 产生的条件有五个:
时钟同步与仲裁
时钟同步:两个主机可以同时开始在空闲总线上进行传输,并且必须有一种方法来确定控制总线并完成其传输的方法。这是通过时钟同步和仲裁完成的。在单主机系统中,不需要时钟同步和仲裁。
时钟同步是通过 I2C 接口中 SCL 线的线与实现的。啥意思呢?
这里的几句话需要划重点去理解,这就是 I2C 总线的核心之核心工作原理:线与!
仲裁:仲裁与同步类似,仅在系统中使用多个主机时才会涉及到,从站不参与仲裁过程。首先要理解一下仲裁是干啥的?所谓仲裁就是在多主机模式下,哪一个主机能获取介质的访问权限,获得权限的主机才可以传输 I2C 通信报文。只有在总线空闲时,主机才可以开始传输。两个主机可以在 START 的最小保持时间内产生 START 条件这种情况会导致总线上出现有效的 START 条件。然后需要仲裁以确定哪个主机将完成其传输。
仲裁是一位一位地进行。节点发送 1 个位后,回读比较总线上所呈现的数据与自己发送的是否一致。是,继续发送;否则,退出竞争。SDA 线的仲裁可以保证 I2C 总线系统在多个主节点同时企图控制总线时通信正常进行并且数据不丢失。总线系统通过仲裁只允许一个主节点可以继续占据总线
上图显示了两个主机的仲裁程序。实际使用中连接到总线的主机数量可能会更多。当主机产生的 DATA1 的内部数据电平与 SDA 线上的实际电平之间存在差异时,DATA1 输出将关闭。从而主机 1 退出竞争,没有获得总线的控制权。
时钟延长:时钟延长通过将 SCL 线保持为低电平来暂停事务。直到再次释放高电平,事务才能继续。时钟延长是可选的,实际上,大多数从设备不包括 SCL 驱动能力,因此它们无法延长时钟。
为啥要设计这样一个机制呢?个人理解是为了增强系统的健壮性而设计的:
地址及 R/W 位
地址及 R/W
设备地址
读写位
描述
0000 000 | 0 | 广播地址 |
0000 000 | 1 | 启动字节 |
0000 001 | X | CBUS 地址 |
0000 010 | X | 预留给不同的总线格式 |
0000 011 | X | 预留未来扩展使用 |
0000 1XX | 1 | Hs-mode 主代码 |
1111 1XX | 1 | 设备 ID |
1111 0XX | X | 10 位从地址 |
通用广播地址
通用广播地址用于同时寻址连接到 I2C 总线的所有设备。但是,如果设备不需要处理广播数据,则可以通过不发出 ACK 来忽略该地址。如果某设备需要来自通用广播地址的数据,它将发送 ACK 给该地址并充当从接收器。
主机实际上不知道有一个或多个设备响应时确认了广播数据(不确定有多少个 ACK)。每个能够处理此数据的从机接收器都会确认第二个字节和随后的字节。无法处理这些字节的从机将不应答从而忽略。同样,如果一个或多个从机应答,则主机不会看到未确认的消息。通用广播地址的含义总是在第二个字节中指定,如下图:
1.当 B 为 0 时,第 2 字节定义如下:
对于 06h/04h 这两个命令,有些不太好理解。复位比较好理解。对于设置设备地址的可编程部分可能很多没有遇到过的朋友则不太好理解。
这里来一个实际芯片的例子,以 Microchip 的 MCP3423/MCP3424 为例进行描述一下,MCP3423/MCP3424 是一颗多通道 ADC 芯片,其芯片引脚如下:
当接收到通用广播访问且第 2 字节为 06h 命令后,芯片做两件事情:
当然对于不同的芯片,具体如何实现通用广播地址的处理则各有不同,只需要认真阅读芯片的手册就能获取相应信息。这里仅仅就通用广播地址举个栗子,方便理解。老实说这个功能好像不太常见,具体有什么用?我反正没这么用过,感觉这功能有点蛋疼(直接用电阻配置好不更省事?)。如果有好的应用实例场景,欢迎留言交流。
2.当 B 为“ 1”时,则该 2 字节序列为“硬件通用呼叫”。该报文由 I2C 主设备(例如键盘扫描器)发送,可以对其进行编程以发送所需的从地址。由于 I2C 主设备事先不知道该消息必须传输到哪个从设备,故利用通用广播地址及通用呼叫命令并将自身的地址放在高 7 位,从而标识总线上发送通用硬件呼叫的设备 ID。该地址由连接到总线的智能设备识别(比如该智能设备是一个单片机系统),然后该智能设备从硬件主机接收信息。如果硬件主机也可以充当从机,则从机地址与主机地址相同。
所以标准中定义这个功能,可以做些自适应应用,只需要制定出相应协议就可以完成比较灵活的多主通信应用协议。
软复位
如上面描述,当通用广播地址后面跟 06h 字节,就可以使从设备软复位。但这个功能并非所有芯片都支持,具体使用的时候需要仔细阅读芯片手册是否支持该功能。
须采取预防措施以确保设备在施加电源电压后不会拉低 SDA 或 SCL 线,因为这些低电平会阻塞总线。
起始 START 字节
单片机/DSP 可以用两种方法连接到 I2C 总线:
比如在一个多单片机用 I2C 总线连一起的系统,其中一个单片机 I2C 是用 IO 口模拟的,则快速的硬件设备与依赖软件轮询的相对较慢的单片机之间存在速度差异。这个不难想象,因为依靠轮询则不是硬实时,同时单片机肯定还有其他事物需要处理,那么检测 START 条件信号就有可能丢失,导致系统不健壮。那么 I2C 标准已然考虑这种需求了。
这就是起始字节需要解决的需求,前面介绍的就是起始字节设计的背景。那么起始字节究竟是怎样的呢?
在需要访问总线的主机发送了 START 事件之后,发送 START 字节(0000 0001)。另一个单片机/DSP 可以以低采样率对 SDA 线进行采样,直到检测到 START 字节中的七个零之一为止。在 SDA 线上检测到此 LOW 电平后,微控制器可以切换到更高的采样率,以找到重复的 START 事件,然后将其用于同步。
总线复位
在异常情况下,如果时钟 SDA 被拉为 LOW 了,则有哪些办法可以对总线复位呢?
//可能需要先关闭I2C控制器,如果是使用I2C控制器外设实现的
//I2C_SCL根据不同硬件进行移植,delay
#define I2C_SCL P10
void soft_rst_i2c(void)
{
I2C_SCL = 1;
for(int i=0;i<9;i++)
{
I2C_SCL = 0;
delay(xx);
I2C_SCL = 1;
delay(xx);
}
}
前面两种方法是更健壮的方案,如果硬件不支持,可以考虑后一种方法,但后一种方法的前提是拉死 SCL 的设备需要支持这种功能,如果两端都是自定义开发的则比较灵活了。
总线锁死,是 I2C 总线系统常踩的坑,有哪些原因会导致锁死呢?程序不健壮,I2C 的波形不满足 I2C 规格书要求,或者在外加干扰情况下导致波形被干扰。有经验的同学可能会遇到设备平时工作的好好的,但是做 EMC 测试,常常设备会莫名死机,如果你的设备有 I2C 总线,请记得检查 I2C 是否被 EMC 干扰干死了!
设备 ID
设备 ID 字段是一个可选的 3 字节只读(24 位)字,提供以下信息:
这个对于设计软件有什么可以利用的信息呢?比如一个系统可兼容不同厂家的基于 I2C 协议的传感器,利用这个字段就可以做设备信息管理。至于怎么读取,不同芯片或有不同。
接口电路简介
前面拓扑图中采用 open-drain 开漏结构。I2C 有的还用集电极开路输出结构,究其原因是内部是三极管的集电极开路。如下
Ultra Fast-mode
在 Rev 4 中还出现了 Ultra Fast-mode,该模式使用 push–pull 推挽定义 I2C 内部硬件接口电路(我把它叫推拉),这个又长什么样呢?
这种推挽接口是用在 Ultra Fast-mode(UFm)模式,为啥不继续采用集电极开路门/漏极开路门呢?因为这两种硬件已然无法满足如此高速的通讯波形要求了,推挽输出可以实现更为快速波形前沿特性以驱动总线电容负载。
对于 Ultra Fast-mode 模式其他如时序波形,报文定义基本一致,这里不做赘述了。需要提醒的是设备 ID 在该模式下不支持!
容性负载
为什么要特别讨论一下总线的容性负载特征呢?想象中的理想通信波形:
由于容性负载以及充放电常数特性,实际中却可能是这个鸟样:
如果实际总线中电阻选取过大,或者容性负载过大(设备节点过大或者布线不合理),也即RC常数过大,甚至可能是这个德行:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-szIqvEcO-1635736672420)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]
那么参数选取合适时,波形则可能是这样的:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZevZFmJy-1635736672421)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]
所以就其本质而言,就是由于驱动接口电路的RC参数影响了波形的时序参数:
实际应用中,一方面电阻需要选取足够大以降低不必要的电流消耗,另一方面电阻又需要选择足够小以满足对应传输速度的波形时序要求。故需要在这一对矛盾体中寻求一个折中平衡!实际项目中先用示波器测测I2C波形非常必要,代码对了总线可未必如愿工作。做底层开发,尽量先硬后软~~
I2C 总线标准从电气特性界定了容性负载特征:
Fast-mode:连接到总线的外部上拉设备必须经过调整,以适应快速模式 I2C 总线较短的最大允许上升时间。对于 200 pF 以内的等效总线负载,每条总线的上拉设备可以是一个电阻。对于 200 pF 至 400 pF 之间的总线负载,上拉设备可以是电流源(最大 3 mA)或开关电阻电路。
Fast-mode Plus (Fm+):该模式下设备中的驱动接口电路驱动能力比较强大,可以满足 Fast-mode Plus 时序规范,并具有与标准模式部件相同的 400 pF 负载。为了与标准模式向后兼容,它们还可以承受标准模式设备的 1μs 上升时间。在仅存在 Fast-mode Plus 部件的应用中,强驱动接口和对缓慢的上升和下降时间的容忍度允许使用较大的总线电容,只要软件设置好或硬件 IC 实现好,Fast-mode Plus 的最小 LOW 时间和最小 HIGH 时间即可满足所有要求,并且下降时间和上升时间不超过标准模式的 300ns 上升沿时间和 1μs 下降沿时间规格。可以将总线速度与负载电容进行折衷,总线电容可增加大约十倍。
Hs-mode: 高速模式(Hs-mode)器件在 I2C 总线传输速度方面实现了飞跃。高速模式设备可以实现高达 3.4Mbit/s 的比特率传输速度,但仍然向下兼容,与快速模式增强版、快速模式或标准模式(F/S)设备完全兼容以进行双向通信总线系统。除了在 Hs 模式传输期间不执行仲裁和时钟同步外,与 F/S 模式系统保持相同的串行总线协议和数据格式。那么如此高速是如何做到的呢?这里将个人认为与应用相关的要点翻译总结下:
Hs 模式主设备具有用于 SDAH 信号的漏极开路输出缓冲器,以及 SCLH 输出上的漏极开路下拉电路和电流源上拉电路的组合。该电流源电路缩短了 SCLH 信号的上升时间。任何时候仅在 Hs 模式下,仅启用一个主机的电流源。
在多主机系统的 Hs 模式传输期间,不执行仲裁以及时钟同步以提高位处理能力。仲裁过程始终在先前的 F/S 模式下的主代码传输之后完成。
Hs 模式主设备生成串行时钟信号,其占空比为 50%以减轻建立和保持时间的时序要求。这个项目中可利用示波器检查波形。
具体设计时,可参考规格书电气特性参数规定以及所选芯片的手册。
编程策略
编程时,比较好的方式就是处理相应的中断事件。利用内置 I2C 控制器是优选方案。
在实际项目中,需要特别注意 I2C 的上升沿、下降沿波形时间参数是否满足设计速率要求,可通过配置寄存器以及调整驱动上拉电阻进行调整。对于高速模式则可能需要用电流源进行驱动。另外需要注意的是,I2C 总线锁死情况处理。
总结一下
I2C 总线是一个比较复杂的芯片间总线系统,你或许会用。但是如果不注意标准的很多细节,你可能无法用好!尤其总线上挂很多设备时,系统极可能不健壮!本文主要参考 I2C version 6标准,I2C 总线看似简单却极为复杂,本文总结了规格书中一些要点,也并不全面。在复杂应用场景中,还需要多多踩坑、填坑并加以总结。前文谈到了对于技术要点尽量总结、概括以及提炼,这里想提醒的是一些技术要点的标准往往是最为严谨、也最为全面的总结。具体使用时,可多多研读。
I2C VERSION6 规格书可至 www.i2c-bus.org 下载,也可以至公众号后台回复数字【0202】,可直接领取。
该图显示了包含I2C所有相关因素的两个设备(主设备或从设备)之间的I2C连接的简化等效电路图。
VCC | I2C电源电压,通常为1.2 V至5.5 V |
---|---|
地线 | 共同点 |
SDA | 串行数据(I2C数据线) |
SCL | 串行时钟(I2C时钟线) |
p | 上拉电阻(又名I2C终端) |
Rs | 串联电阻 |
Cp | 线电容 |
Cc | 跨通道电容 |
典型值:
在总线速度为100KHz时,Rp = 10kΩ和Cp = 300 pF(I2C标准将Cp限制为最大值400 pF)。 在整个传输线上,线长越长等效Cp就越大,通常情况下不建议调节Cp,为了提高线路的稳定性可以适当增加终端电阻Rp。
端接电阻Rp与导线电容Cp一起影响SDA和SCL上信号的时间行为。
下图显示了典型的I2C传输。仔细观察信号可发现信号中的小尖峰。这些是由交叉通道电容Cc引起的结果。通常,只要产生的尖峰不太大,串扰就不会成为问题。通过使用尽可能短的互连,可以将Cc本身最小化。增加串联电阻Rs和端接Rp有助于降低交叉通道电容Cc的影响。