I2C

 

介绍

在这篇指导里,你将学习I2C通信协议,为什么你想用它,以及它怎么执行。

I2C协议是一个允许多个“从机”数字集成电路(“芯片”)来和一或多个“主机”芯片通信。像串口外围接口,它只允许在信号设备范围内短距离通信。像异步串行接口(比如RS-232或者UART),它仅仅要求两条信号线来交换信息。

推荐阅读

在读这篇指导之前,可以先阅读以下材料帮助了解相关知识:

为什么用I2C?

为了指出为什么我们想要通过I2C来通信,你需要先比较它与其他可选择的不同之处。

串行端口有什么问题?

i2c1

因为串行端口是异步的(没有发射时钟数据),设备使用它们必须先统一数据传输速率。两个设备还需要有相近这个速度的时钟,要用两个时钟速率差异过大的设备来传输会导致产生垃圾数据。

异步串行接口要求硬件开销——UART插口是比较复杂的,而且很难在软件上精确实现(有必要的话)。至少一个起始位和终止位是每一帧数据的一部分,这意味着每8位的数据传输需要相当于10位的传输时间,这就占进了传输速率。

另外一个异步串行接口的错误就是它们实质上只适合两个设备间传输。然而它能够连接多台设备到一个串行端口上,总线争用(两个设备尝试同时在一条线上传输)就是一个常见的问题而且处理时很要注意不能让设备收到损害,这通常需要外部硬件解决。

最后,数据传输速率也是个问题。尽管理论上并没有限制异步串行通信,大部分UART设备仅仅支持一个确定的波特率,而最高的大约是230400位每秒。

SPI有什么问题?

i2c2

SPI最明显的缺陷就是引脚需求量。用SPI线连接一个主机和从机要求四条线;每一个额外的从机要求主机一个额外的选择I/O口。这样快速的增长对于要求一台主机连接多台从机的情况是很不便利的。每一条设备都要大量连接的话,也会使得信号在PCB上的紧密布线很困难传输。SPI只允许有一个主机在总线上,但是支持任意个从机(仅受驱动能力和芯片的选择引脚的数量限制。)

SPI有利于高速率全双工(同时发送和接收数据)连接,有些设备支持的时钟速率高达10MHz,而且速率扩展性可观。两端的硬件都是非常简单的移位寄存器,需要软件进行一些简单的实现。

进入I2C-两全其美!

I2C3

I2C只需要两条线,像异步串行,但那两条线可以支持高达1008个从机。不像SPI,I2C,它可以支持多个主系统,允许多个主机在一条线上通信(尽管主机之间不能通过总线交流,而且必须轮流使用总线)。

在异步串行和SPI间数据速率会下降;大部分I2C设备可以以100kHz或者400kHz的速率传输。这里有一些开销的I2C,每8位的数据被传输,元数据的一个额外的位(“ACK/NACK”位,我们之后说到)就会被发送。

实施I2C的硬件要求比SPI更加复杂,但比异步串行简单。而且能在软件上简单地完成。

I2C-一个短暂的历史

I2C本来是1982年时飞利浦设计给各种飞利浦芯片而发展起来的。原来的标准只允许100kHz的速率传输,而且仅仅提供7位地址,限制总线上的设备数位为112(有一些保留地址不会被用作为I2C的有效地址)。在1992年,第一个公认规范推出,把400kHz作为最高速度以及扩展为10位地址。大多数时候(比如,在大多数Arduino兼容板子上的ATMega328设备),设备在这一点上看能支持I2C。这里有三个额外模块规定:快速模式加,1MHz;高速模式,3.4MHz;以及超快模式,5MHz。

此外,“香草”I2C,英特尔在1995年推出了一款名为“系统管理总线”(SMBus)的变种。SMBus是一种更严格控制的格式,为了最大限度的提高PC主板对支持的IC间通信的可预测性。SMBus之间最显著的区别就是它的限制速度,低至10kHz高达100kHz,然而I2C可以支持的设备是0kHz到5MHz的。SMBus含有一个时钟暂停模块用于非法低速操作,尽管许多SMBus设备支持它以任意方式最大化嵌入式I2C系统间的互通性。

在硬件层面上的I2C

信号

每一个I2C总线由两个信号组成:SCL和SDA。SCL是时钟信号,SDA是数据信号。时钟信号总是由当前的总线控制;一些从属设备可能有时会强制低电平时钟信号来延迟主设备传输更多的数据(或者获取更多时间以在主设备放出时钟信号之前准备数据)。这称作“时钟延长”在协议部分有说明。

不同于UART或者SPI连接,I2C总线驱动是“漏极开路”,意味着它们可以降低相对应信号线的电平,但不可以使它升高。因此,不会有当一个设备试图把线设为高电平而另一个设备想要降低电平这样的总线争用情况,消除了对驱动器造成损害或者在系统中功耗过大这些潜在危险。每一个信号线有一个上拉电阻,用于无设备设置它位低电平时恢复高电平。

I2C4

注意两条通信线上有两个上拉电阻

电阻要根据总线上的设备来选择,但一个比较好的经验法则是从4.7k开始,根据需要往下调整。I2C相当强大的协议,可以用于短线(2-3m。)对于长线,或者多设备的系统,小电阻比较适合。

信号电平

因为总线上的设备实际上并不能使信号设置为高电平,I2C对允许连接设备的I/O电压要求具有一定的灵活性。总的来说,系统里如果有一个设备的电压比另一个高一些,它可能可以通过I2C直接连接而不用在它们之间加转换电平的电路。它是利用了上拉电阻来升高较低电压的那个设备的电压。这只能在部分情况可行,当两个系统电压中的较低者超过了输入系统的高电平电压——比如,5V的Arduino和3.3V的加速度计。

如果两个系统间的电压差太大(如5V和2.5V),SparkFun提供了一个I2C电平转换板。因此板需要包括一条启动信号线,它可以用于禁用通信来选择设备。当多个设备用同一个地址连接到信号主机时是非常有用的——Wii Nunchucks就是个好例子。

协议

通过I2C通信要比UART或者SPI复杂很多。发信号必须按照总线上设备的协议来识别出有效的I2C通信。幸运的是,大部分设备都会照顾到这繁琐的细节,你只需注意好你想要传输的数据就可以了。

基础

I2C5

信息被分成两种类型的帧:地址帧,用于主机指示信息要传输到哪台从机;数据帧,8位数据信息从主机传到从机,反之亦然。当SCL进入低电平后数据被放到SDA线,当SCL为高电平时就取样。时钟边缘和数据读写之间的时间由总线上的设备来定义,这和芯片到芯片有很大不同。

初始状态

为了开始地址帧,主设备把SCL设为高电平SDA设为低电平。这能让所有从机知道传输准备开始了。如果两个主设备同时想要火的总线的所有权,先把SDA的电平降下来的设备就能获得总线的控制权了。可能会发生重复启动的情况,没有放弃其他主设备对总线的控制直接开始新的通信序列;这我们将会在后面讲到。

地址帧

地址帧总是在新通信序列的最前面。对于7位的地址帧,地址是从最高有效位(MSN)开始发送的,紧接着是决定读(1)(0)写的R/W位。

帧的第九位是NACK/ACK位。所有帧都遵循的(数据或者地址)。一旦前8位被发送,接收器就被授予控制SDA的权力。如果接收器没有在第9个时钟脉冲前降低SDA的电平,就可以推断出接收器没有收到数据或者不知道如何解析信息。在这种情况下,通信暂停,直到系统决定如何处理。

数据帧

地址帧被传输之后,数据帧开始被传输。主机会继续按固定时间间隔发送时钟脉冲,数据就会被主机或者从机放到SDA上,这取决于R/W位是读还是写的操作。数据帧的数量是随意的,大部分从机会自动递增内部寄存器,意味着随后读或者写的数据来自下一个线上的寄存器。

终止状态

一旦所有数据都被传输,主机就会开始终止状态。终止状态被定义为在SCL0->1后SDA0->1(低到高)过渡,而且SCL保持高电平。在一般数据写入操作中,SCL是高电平SDA就不会变,这样可以避免错误终止状态。

高级协议主题

10位地址

I2C6

在10位地址的系统中,两个帧需要被传送到从机地址。第一帧由代码b11110xyz组成,x代表从机地址的MSB,y指8位的从机地址,而z则是上述的读写位。第一帧的ACK位将会被所有成功配对地址前两位的从机声明。随着一般的7位传输,另外的传输也立刻开始,而这次传输包含7:0位的地址。这一点上,合地址的从机需要回应一个ACK位。否则,失败模式也一样是个7位的系统。

注意10位地址的设备可以与7位地址的设备共存,因为地址前面的‘11110’部分不是7位地址的任何有效部分。

重启状态

I2C7

有时候,在没有其他主设备在总线上的情况下,允许主设备一次性交换几个信息是非常重要的。为了解决这个问题,就有了重启状态。

要形成重启,当SCL为低电平时SDA要允许是高电平,SCL可以升高,当SCL高电平时SDA再次被拉低。因为线上没有终止状态,原来的通信没有真正完成,而当前的主机保持控制总线。

在这一点上,下一个可以开始传输。新信息的句法和其他信息一样——一个地址帧紧接着数据帧。重启的次数是随意的,主机在总线终止状态前都具有总线的控制权。

时钟延长

I2C8

有些时候,主机的数据速率超过从机能接收数据的能力。这是因为数据被没有真正准备好(比如,从机没有完成模数转换)或者因为先前的操作没有完成(比如说,EEPROM没有完成写入非易失性存储器就要去完成其他要求)。

在这种情况下,一些从机会执行称作“时钟延长”的操作。一般地,所有时钟由主机控制——从机只负责收发数据来回应主机的时钟脉冲。无论数据怎么被传输处理,在主机发送了数据后,对应的从机可以把SCL线设为低电平。主机要避免额外时钟脉冲或者传输数据直到从机释放SCL线。

 

打赏

发表评论