我²C
内部集成电路,通常被称为I²C(通常发音为I²-C),是一种最初由飞利浦半导体公司(现在的NXP半导体公司)开发的通信方式。在本协议中,原本打算成为其中的一部分“Imod系列”,只有两个通信引脚被使用:一个串行数据线(SDA)是由“主”和“从”设备共享,以及一个串行时钟线(SCK)由主控制。通过使用上拉电阻器,这两条线路在逻辑上都保持在较高的位置。
I²C的7位或10位寻址方案提供了在单一数据和时钟线上放置许多设备的优势。然后,通过发出一个启动条件,然后在SDA行上向所有监听设备提交地址以及一个指示器,一个单独的主机就可以启动与设备的通信会话,以判断它是否想要读取或写入设备。如果主机板调用的设备在线路上(双关),该设备将响应一个确认(ACK)位,让它侦听下一个命令,而其他设备等待另一个启动条件,然后再侦听它们的地址。
在接收到ACK后,主控器就可以告诉监听设备它想要读取(或写入)的机载芯片内的哪个寄存器地址。一旦接收到额外的ACK,确认允许特定的动作,就可以在两个设备之间进行数据传输。
更多的细节
广泛使用的9位我²C的沟通风格,主会把SDA低而sci线处于高压状态(由于负载电阻)作为“开始”状态表明它希望与一个奴隶设备然后发送两件事;它希望与之通信的从机的7位地址,然后是一个读或写位,以显示它希望如何与Pmod通信。为了做到这一点,串行时钟线将首先被驱动到一个低电压状态,然后串行数据线要么被驱动到一个低电压状态,要么被留在一个空闲的高电压状态。然后,SCL线路将被释放,并允许回到空转的高压状态,向设备表明数据可以读取。在等待最少的时间以确保接收器已经看到了放置在SDA线上的位,然后master可以对剩余的6个地址位和读/写位重复这个过程。
对于第9位和第9个时钟信号,具有匹配地址的从机将发送一个确认(ACK)位在SDA线上,通过将线路驱动到低电压状态来表示它已经准备好进行通信。如果没有带有7位地址的从服务器,SDA线将在第9个时钟周期内保持高电平,主服务器将把这解释为一个未确认(NACK)信号。
假设一个Pmod确实发送了ACK信号,那么将有9个比特被传输;前8位将由主设备传输,让从设备知道它想要写入或从哪个内部寄存器读取。然后,从设备要么确认请求并允许通信会话成功地继续,要么让SDA处于高空闲状态,表明请求的操作不可能或注册地址无效。
再次收到ACK假设(我们将会发生什么如果发生NACK),发射机(主如果写命令发布或奴隶如果读命令发布)将适当改变电压水平为每一位在SDA行,尽管主人将保持控制的串行时钟线。8位数据已经传输后,接收器将拉数据线低,以承认传输或让线浮动高,以不承认传输。
一旦所有所需的数据传输完成(由用户的偏好决定),主服务器就可以发出一个“重启”(在SCL高空闲时拉低SDA)来开始一个新的通信会话,或者在SCL高空闲时释放SDA线作为其“停止”条件。
Ack !我们收到了一个NACK!
那么NACK意味着什么呢?这取决于何时接收到NACK以及哪个设备发送了NACK。下面的表格显示了几种不同的可能性和一个故障排除选项:
Ack !纳! | |||
---|---|---|---|
当我们收到NACK的时候 | 谁在传输数据 | 它意味着什么 | 你可以检查什么 |
在从地址之后 | 主 | 这个地址在总线上不存在 | 设备的正确地址和主机实际发送的地址的数据表 |
在命令字节之后 | 主 | 无效的命令 | 发送的寄存器地址存在吗?还要确保我们没有试图写入一个只读地址 |
数据传输后 | 主 | 接收设备将不能接受更多的数据 | 重新启动或结束传输,以允许设备处理数据和/或指向一个不同的寄存器地址 |
数据传输后 | 奴隶 | 主服务器不想传输任何额外的数据 | 发出重新启动或结束条件以放弃对公共汽车线路的控制 |
仲裁
因为多个设备能够出现在I²C总线上,有可能两个主可能在同一时间发起启动条件,或者有多个从设备响应一个地址。然而,线路上的任何组件都无法本能地“知道”还有另一个设备也在使用数据线。
因此,当前使用通信线路的所有设备都将通过仲裁来决定是否对线路进行控制。这是通过在每个设备可能试图用数据线把他们的数据,他们通常会开车(SDA低或离开它闲置高),然后读取电压水平在直线上是否该设备预计。如果一个设备看到线路被压低,而它期望它在高位空转,它将得出结论,另一个设备必须也在使用SDA线路,然后放弃对数据线的控制,失去仲裁。
第二个设备,它将看到电压水平是它所期望的,将继续传送它的信息,尽管它也将继续检查行后的每个位,以防有另一个设备刚好匹配它的位值到目前为止。当主设备失去仲裁时,它将放弃对SDA和SCL线的控制,并等待一个停止条件,然后再试图再次传输它的消息。
但是,如果两个设备在从开始位到停止位的整个通信会话期间匹配彼此的位值,那会怎么样呢?用户需要回答的问题是:这对我的系统来说真的是一个问题吗?
时钟拉伸
前面提到过,主设备总是在I²C总线内保持对串行时钟的控制,指定接收设备应该准备和读取比特的位置和时间。然而,由于一个设备无法本能地知道总线上是否有另一个设备,因此主设备将无法知道它的时钟是否过快,从设备无法向数据线放置或读取位。幸运的是,I²C协议通过一个叫做时钟延伸的特性缓解了这个问题。
时钟拉伸是一个从设备继续驱动串行时钟线低的能力,在主设备已经释放时钟线被拉到高电压状态。这是用来保证从设备有足够的时间(由从设备内部决定)在时钟再次“滴答”之前读取或准备下一个位。因此,主设备等待串行时钟线实际达到高压状态,然后延迟设定的时间,并驱动SCL线到低压状态。
时间图
时序图(由维基百科的页面我²C)说明了I²C协议的主要组成部分如下:
-
在这里,您可以看到一个通信会话从一个起始位开始,其中SDA线被压低,而SCL线通过上拉电阻保持高。
-
一旦SCL被主控设备驱动到较低的位置,SDA线要么被驱动到较低的位置,要么被留置到较高的位置,以设置每个蓝条所示的数据位。
-
当串行时钟线达到高电压水平(在任何时钟拉伸完成之后),然后接收设备读取SDA线来收集数据位,如图每一个绿色条所示。
-
这个过程的SCL转换和数据位被放置和读取,直到停止位,由SDA被上拉电阻拉高,而SCL线是高,发生。
更多的信息
虽然这种通信方式本质上不如SPI因为它只运行在半双工和需要一致的检查仲裁,它是更容易创建一个字符串或“菊花链”的I²C设备。这是因为提供I²C通信风格的Pmods有一个2×4引脚头用于I²C,允许一串设备。此外,由于通信风格是设置在主调用一个从地址,而不是在它自己的线上选择一个特定的从地址,只有两个输入/输出引脚曾经需要一个I²C通信设置。