前言:
I2C 总线,也可写作IIC总线(Inter-Integrated Circuit),是一种非常流行且功能强大的总线,用于主设备(或多个主设备)与单个或多个从设备之间的通信。图 1 说明了有多个不同的外设可以共享一条仅通过 2 根信号线(还需要一个参考地线)连接到处理器的总线,这是 I2C 总线与其他接口相比可以提供的最大优势之一。
本文解释I2C 总线规范的工作原理。
图 1 显示了嵌入式系统的典型 I2C 总线,其中使用了多个从设备。微控制器代表 I2C 主机,并控制 IO 扩展器、各种传感器、EEPROM、ADC/DAC等。所有这些都仅由主机的 2 个引脚控制。
1. 电气特性
I2C 使用漏极开路或集电极开路,在同一条线路上有一个输入缓冲器,允许单条数据线用于双向数据流。
1.1 用于双向通信的漏极开路
漏极开路是指一种输出类型,它可以将总线拉低到电压(在大多数情况下是接地),也可以“释放”总线并使其被上拉电阻拉起。如果总线被主机或从机释放,线路上的上拉电阻 (RPU) 负责将总线电压拉至电源轨。由于任何设备都不能在线路上强制高电平,这意味着总线永远不会遇到通信问题,即一个设备可能尝试传输高电平,而另一个设备传输低电平,从而导致短路(电源轨对地)。I2C 要求,如果多主机环境中的主设备传输高电平,但看到线路为低电平(另一个设备正在将其拉下),则由于另一个设备正在使用总线而停止通信。推挽式接口不允许这种自由度,这是 I2C 的一个优势。
图2显示了SDA/SCL线路上从器件或主器件内部结构的简化视图,该结构由一个用于读取输入数据的缓冲器和一个用于传输数据的下拉FET组成。器件只能将总线线拉低(提供对地短路)或释放总线线(对地高阻抗),并允许上拉电阻提高电压。在处理 I2C 设备时,这是一个需要实现的重要概念,因为任何设备都不能将总线保持在高电平。此属性允许进行双向通信。
1.1.1开漏拉低
如上一节所述,漏极开路设置可能仅将总线拉低,或“释放”总线并让电阻器将其拉高。图3显示了将总线拉低的电流。想要传输低电平的逻辑将激活下拉 FET,这将提供对地短路,从而将线路拉低。
1.1.2 开漏释放总线
当从机或主机希望传输逻辑高电平时,它只能通过关闭下拉FET来释放总线。这会使总线悬空,上拉电阻会将电压拉至电压轨,这将被解释为高电平。图4显示了通过上拉电阻的电流,该电阻将总线拉高。
2. I2C 接口
2.1 常规 I2C 操作
I2C 总线是一种标准的双向接口,它使用控制器(称为主控制器)与从设备进行通信。除非主设备已寻址,否则从设备不得传输数据。I2C 总线上的每个设备都有一个特定的设备地址,用于区分同一 I2C 总线上的其他设备。许多从属设备在启动时需要配置以设置设备的操作。这通常在主设备访问从设备的内部寄存器映射时完成,这些映射具有唯一的寄存器地址。设备可以有一个或多个寄存器,用于存储、写入或读取数据。
物理 I2C 接口由串行时钟 (SCL) 和串行数据 (SDA) 线路组成。SDA 和 SCL 线路都必须通过上拉电阻连接到 VCC。上拉电阻的大小由 I2C 线路上的电容量决定。仅当总线处于空闲状态时,才能启动数据传输。如果 SDA 和 SCL 线路在 STOP 条件后均为高电平,则总线被视为空闲。
主设备访问从设备的一般过程如下:
- 假设主节点想要向从节点发送数据:
主发送器发送START条件并寻址从接收器
主发送器向从接收器发送数据
主发射器以 STOP 条件终止传输 - 如果主站想要从从站接收/读取数据:
主接收机发送 START 条件并寻址从发器
主接收机发送请求的寄存器以读取到从发机
主接收机从从发机接收数据
主接收方以 STOP 条件终止传输
2.1.1 START 和 STOP 条件
与此器件的 I2C 通信由发送 START 条件的主设备启动,并由发送 STOP 条件的主机终止。当 SCL 为高电平时,SDA 线路上的高到低转换定义了 START 条件。当 SCL 为高电平时,SDA 线上的低电平到高电平转换定义了 STOP 条件。
2.1.2重复启动条件
重复的 START 条件类似于 START 条件,用于代替背靠背的 STOP 然后 START 条件。它看起来与 START 条件相同,但与 START 条件不同,因为它发生在 STOP 条件之前(当总线未空闲时)。当主站希望开始新的通信,但不希望在STOP条件下让总线处于空闲状态时,这很有用,因为主站有可能失去对另一个主机的总线的控制(在多主机环境中)。
2.2 数据有效性和字节格式
在 SCL 的每个时钟脉冲期间传输一个数据位。一个字节由 SDA 线上的 8 位组成。字节可以是设备地址、寄存器地址,也可以是写入或从从站读取的数据。数据首先传输最高有效位 (MSB)。在START和STOP条件之间,可以从主设备传输任意数量的数据字节。SDA线路上的数据在时钟周期的高电平期间必须保持稳定,因为当SCL为高电平时数据线的变化被解释为控制命令(START或STOP)。
2.3 确认 (ACK) 和不确认 (NACK)
每个数据字节(包括地址字节)后面跟着一个来自接收器的 ACK 位。ACK位允许接收器与发送器通信,表明该字节已成功接收,并且可以发送另一个字节。
在接收器发送 ACK 之前,发射器必须释放 SDA 线路。要发送 ACK 位,接收方应在 ACK/NACK 相关时钟周期(周期 9)的低相位下拉 SDA 线,以便 SDA 线在 ACK/NACK 相关时钟周期的高电平期间保持稳定的低电平。必须考虑设置和保持时间。
当 SDA 线在 ACK/NACK 相关时钟周期内保持高电平时,这被解释为 NACK。有几种情况会导致 NACK 的产生:
1.接收器无法接收或发送,因为它正在执行一些实时功能,并且没有准备好开始与主站通信。
2.在传输过程中,接收方会收到它不理解的数据或命令。
3. 在传输过程中,接收方无法接收更多的数据字节。
4. 主接收器完成读取数据,并通过 NACK 向从设备指示数据。
3. I2C 数据
数据必须从属设备发送和接收,但实现此目的的方式是从属设备中的寄存器读取或写入寄存器。
寄存器是从机内存中包含信息的位置,无论是配置信息,还是要发送回主站的一些采样数据。主设备必须将信息写入这些寄存器,以便指示从设备执行任务。
虽然在 I2C 从设备中具有寄存器是很常见的,但请注意,并非所有从设备都有寄存器。有些器件很简单,只包含 1 个寄存器,可以通过在从地址之后立即发送寄存器数据而不是寻址寄存器来直接写入寄存器。单寄存器器件的一个例子是 8 位 I2C 开关,它通过 I2C 命令进行控制。
由于它有 1 位来启用或禁用通道,因此只需要 1 个寄存器,并且主设备只需在从地址之后写入寄存器数据,跳过寄存器编号。
3.1 写入 I2C 总线上的从机
要在 I2C 总线上写入,主设备将在总线上发送一个启动条件,其中包含从设备的地址,以及将最后一位(R/W 位)设置为 0,表示写入。在从机发送确认位后,主机将发送它希望写入的寄存器的寄存器地址。从机会再次承认,让主机知道它已经准备好了。在此之后,主机将开始向从机发送寄存器数据,直到主机发送完它需要的所有数据(有时这只是一个字节),主机将以 STOP 条件终止传输。
图 8 显示了将单个字节写入从寄存器的示例。
深色:主机SDA
白色:从机SDA
写入从机中的一个寄存器
3.2 从I2C总线上的从机读取
读从机与写从机相似,但有一些额外的步骤。为了从机读取,主机必须首先指示从机它希望从哪个寄存器中读取。这是由主机以与写入类似的方式开始传输来完成的,方法是发送 R/W 位等于 0 的地址(表示写入),然后是需要读取的寄存器地址。一旦从机确认此寄存器地址,主机将再次发送 START 条件,然后是 R/W 位设置为 1 的从机地址(表示读取)。这一次,从机将确认读取请求,主机释放SDA总线,但将继续向从机提供时钟。在事务的这一部分,主机将成为主接收方,从机将成为发送方。
主机将继续发送时钟脉冲,但会释放SDA线,以便从机可以传输数据。在每个字节的数据末尾,主机将向从机发送一个 ACK,让从机知道它已准备好接收更多数据。一旦主机收到预期的字节数,它将发送一个NACK,向从机发出信号,停止通信并释放总线。主机将使用 STOP 条件跟进此操作。
图 9 显示了从从寄存器读取单个字节的示例。
深色:主机SDA
白色:从机SDA
读从机中的一个寄存器