通过I2C通信的设备必须符合特定的事件序列。每个事件对应于控制时钟(SCL)和数据(SDA)线的某种方式; 正如上面列出的“支持信息”文章中所讨论的,这两个信号是总线上设备可以共享信息的唯一方法。我们将一个通信序列称为“事务”; 这个词比“传输”更合适,因为每个事务都涉及传输数据和接收数据,尽管在某些情况下,唯一接收的数据是主设备检测到的确认(ACK)或不确认(NACK)位。以下时序图显示了典型的I2C事务。
请注意以下事项:
对应于时钟逻辑高电平部分的虚线提醒我们逻辑高电平(对于SCL和SDA)都是“隐性”状态 - 换句话说,信号通过上拉电阻自然浮动到逻辑高电平。“主导”状态是逻辑低,因为只有当设备实际将其驱动为低时,信号才会变低。
事务以“起始位”开始。每个I2C事务必须以一个起始位开始,该起始位定义为SDA的下降沿,而SCL为逻辑高电平。
事务以“停止位”结束,定义为SDA的上升沿,而SCL为逻辑高电平。I2C事务必须以停止位结束; 但是,正如本文后面所讨论的,在生成停止位之前可能会出现多个起始位。
数据在时钟为高时有效,在时钟为低时改变状态; 数字通信系统通常是边沿驱动的,因此实际上数据在时钟的上升沿读取,并在时钟的下降沿更新。
信息一次一个字节地交换,从最高有效位开始,每个字节后跟一个ACK或NACK。
您可能期望ACK由逻辑高指示,NACK由逻辑低指示,但事实并非如此。ACK为逻辑低,NACK为逻辑高。这是必要的,因为高是隐性状态 - 如果从属无功能,信号自然浮动到NACK。同样,只有当设备可操作并准备继续进行交易时,才能发送ACK(由主导逻辑低指示)。
以下列表描述了上述事务中的事件序列:
主机生成一个起始位以启动事务。
主设备发送与其想要通信的从设备相对应的7位地址。
第一个单字节段中的最后一位是读/写指示符。如果想要从从器件读取数据,则主器件将该位设置为逻辑高电平;如果要将数据写入从器件,则将其设置为逻辑低电平。
下一个字节是第一个数据字节。它来自主半导体设备或从设备,具体取决于读/写位的状态。像往常一样,我们有8位数据,从最重要的位开始。
数据字节之后是ACK或NACK,如果这是读事务则由主机生成,如果是写事务则由从机生成。ACK和NACK可能意味着不同的东西,具体取决于通信设备的固件或低级硬件设计。例如,主设备可以使用NACK来说“这是最后一个数据字节”,或者如果从设备知道要发送多少数据,它可以使用ACK来确认数据是否已成功接收。
事务以主机生成的停止位终止。
多少字节?
每个事务以相同的方式开始:起始位,地址,读/写,ACK / NACK。之后,任何数量的字节都可以从主机发送到从机或从从机发送到主机,每个字节后跟ACK或NACK。NACK可以用作说“停止发送数据!”的方式。例如,主设备可能希望从从设备(例如温度传感器)接收连续的数据流; 每个字节后面都会有ACK,如果主控器需要将注意力转移到其他位置,它可以NACK从器件并在它准备就绪时开始新的事务。
从没有停止开始
I2C协议允许称为“重复启动”条件。当主机启动具有起始位的事务然后通过另一个起始位启动新事务而没有中间停止位时,会发生这种情况,如下所示:
只要单个主服务器需要执行两个或多个单独的事务,就可以使用此功能。但是,有一种情况,重复启动条件特别方便:
假设您有一个从属设备将信息存储在一组寄存器中。您想从十六进制寄存器地址160,0xA0中检索数据。I2C协议不允许主机在单个事务中发送数据和接收数据。因此,您必须执行写入事务以指定寄存器地址,然后执行单独的读取事务以检索数据。但是,这种方法可能会导致问题,因为主机会释放总线在第一个事务结束时,因此另一个主设备可以声明总线并阻止第一个主设备获取它所需的数据。此外,第二主设备可以与同一从设备通信并指定不同的寄存器地址。。。如果第一个主设备然后声明总线并读取数据而不重新指定寄存器地址,它将读取错误的数据!如果第二个主设备然后尝试在其写入然后读取过程中执行读取事务,那么它也将以错误的数据结束!这是一个等待发生的系统故障 - 幸运的是,重复启动条件可以通过在不 释放总线的情况下启动第二个(读取)事务来防止这种混乱:
I2C如此通用的部分原因在于它支持多个主设备。但正如前一节所示,大师并不总能很好地融合在一起。器件的I2C逻辑必须能够确定总线是否空闲; 如果另一个主设备声明了总线,则设备会在启动自己的事务之前等待当前事务结束。但是当两个(或更多)主设备同时尝试启动交易时会发生什么?I2C为这个令人讨厌的问题提供了一种有效且令人惊讶的简单解决方案。这个过程被称为“仲裁”,它依赖于I2C的漏极开路总线配置的灵活性:如果一个主机尝试将信号逻辑驱动为高电平而另一个主机尝试逻辑低电平,则逻辑低电平主机将“赢, “此外,
该图表传达了I2C仲裁的基础; 过程如下:
两个主设备都生成一个起始位并继续进行传输。
如果主人碰巧选择相同的逻辑电平,则没有任何反应。
一旦主人试图施加不同的逻辑电平,主驱动信号就会被宣告为胜利者; 失败者检测到逻辑不匹配并放弃其传输。
花一点时间来欣赏这种安排的简单性和功效:
获胜者继续传输而不会中断 - 没有损坏的数据,没有驱动程序争用,不需要重新启动事务。
理论上,失败者可以在仲裁过程中监视从属地址,并且如果恰好是被寻址的从属,则实际上做出正确的响应。
如果竞争主设备都要求来自同一从设备的数据,则仲裁过程不会不必要地中断任一事务 - 不会检测到不匹配,并且从设备将其数据输出到总线,使得多个主设备可以接收它。
结论
本文介绍了影响固件或低级硬件设计的重要I2C细节。如果您的微控制器包含专用I2C或SMBus硬件,则会自动处理一些实现细节。这很方便,但肯定不是无知的借口,因为你仍然需要知道至少一点(可能更多一点)关于I2C如何工作。此外,如果您发现自己被困在没有I2C外围设备的荒岛上,这里提供的信息将帮助您顺利设计仅固件(又称“bit-banging”)I2C例程。