I2C 即Inter-Integrated Circuit(集成电路总线),是由Philips 半导体公司(现在的 NXP 半导体公司)在八十年代初设计出来的一种简单、双向、二线制总线标准。多用于主机和从机在数据量不大且传输距离短的场合下的主从通信。主机启动总线,并产生时钟用于传送数据,此时任何接收数据的器件均被认为是从机。
I2C 总线由数据线SDA 和时钟线 SCL 构成通信线路,既可用于发送数据,也可接收数据。在主控与被控IC 之间可进行双向数据传送,数据的传输速率在标准模式下可达100kbit/s,在快速模式下可达400kbit/s,在高速模式下可达 3.4Mbit/s,各种被控器件均并联在总线上,通过器件地址(SLAVE ADDR,具体可查器件手册)识别。I2C 总线物理拓扑结构如下图所示。
图中的I2C_SCL 是串行时钟线,I2C_SDA 是串行数据线,由于I2C 器件一般采用开漏结构与总线相连,所以 I2C_SCL 和 I2C_SDA 均需接上拉电阻,也正因此,当总线空闲时,这两条线路都处于高电平状态,当连到总线上的任一器件输出低电平,都将使总线拉低,即各器件的 SDA 及SCL 都是“线与”关系。
I2C 总线支持多主和主从两种工作方式,通常工作在主从工作方式。在主从工作方式中,系统中只有一个主机,其它器件都是具有 I2C 总线的外围从机。在主从工作方式中,主机启动数据的发送(发出启动信号)并产生时钟信号,数据发送完成后,发出停止信号。
I2C 总线结构虽然简单,使用两线传输,然而要实现器件间的通信,需要通过控制 SCL 和SDA 的时序,使其满足 I2C 的总线传输协议,方可实现器件间的数据传输。那么 I2C 协议的时序是怎样的呢?
在I2C 器件开始通信(传输数据)之前,串行时钟线 SCL 和串行数据线SDA 线由于上拉的原因处于高电平状态,此时 I2C 总线处于空闲状态。如果主机想开始传输数据,只需在 SCL 为高电平时将 SDA 线拉低,产生一个起始信号,从机检测到起始信号后,准备接收数据,当数据传输完成,主机只需产生一个停止信号,告诉从机数据传输结束,停止信号的产生是在 SCL 为高电平时,SDA 从低电平跳变到高电平,从机检测到停止信号后,停止接收数据。I2C 整体时序如下图。起始信号之前为空闲状态,起始信号之后到停止信号之前的这一段为数据传输状态,主机可以向从机写数据,也可以读取从机输出的数据,数据的传输由双向数据线(SDA)完成。停止信号产生后,总线再次处于空闲状态。
了解到了整体时序之后,我们可能有疑问,数据是以什么样的格式传输的呢?满足怎样的时序要求呢?是在任何时候改变都可以吗?怎么知道从机有没有接收到数据呢?带着这些疑问,我们继续学习 I2C。
由于只有一根数据线进行数据的传输,如果不规定好传输规则肯定会导致信息错乱,如同在单条道路上驾驶,没有交通规则,再好的道路也会发生拥堵甚至更糟。采用两线结构的 I2C 虽然只有一根数据线,但由于还有一条时钟线,可以让数据线在时钟线的带领下有顺序的传送,就好像单条道路上的车辆在交警或信号指示灯的指示下有规则的通行。那么 I2C 遵循怎样的规则呢?
如果要想回答这些问题,我们得读懂上图 。由上图可知,我们在起始信号之后,主机开始发送传输的数据;在串行时钟线 SCL 为低电平状态时,SDA 允许改变传输的数据位(1 为高电平,0 为低电平),在SCL 为高电平状态时,SDA 要求保持稳定,相当于一个时钟周期传输1bit 数据,经过8 个时钟周期后,传输了 8bit 数据,即一个字节。第8 个时钟周期末,主机释放SDA 以使从机应答,在第 9 个时钟周期,从机将 SDA 拉低以应答;如果第 9 个时钟周期,SCL 为高电平时,SDA 未被检测到为低电平,视为非应答,表明此次数据传输失败。第 9 个时钟周期末,从机释放 SDA 以使主机继续传输数据,如果主机发送停止信号,此次传输结束。我们要注意的是数据以8bit 即一个字节为单位串行发出,其最先发送的是字节的最高位。
I2C 的时序部分已经基本介绍完了,但还有一个小问题,就是当多个 I2C 器件挂接在总线上时,怎样才能与我们想要传输数据的器件进行通信。这就涉及到了器件地址(也称从机地址,SLAVE ADDRESS)。
每个I2C 器件都有一个器件地址,有些 I2C 器件的器件地址是固定的,而有些I2C 器件的器件地址由一个固定部分和一个可编程的部分构成,这是因为很可能在一个系统中有几个同样的器件,器件地址的可编程部分能最大数量的使这些器件连接到 I2C 总线上,例如EEPROM 器件,为了增加系统的 EEPROM 容量,可能需要多个EEPROM。器件可编程地址位的数量由它可使用的管脚决定,比如EEPROM 器件一般会留下 3 个管脚用于可编程地址位。但有些I2C 器件在出厂时器件地址就设置好了,用户不可以更改(如实时时钟 PCF8563 的器件地址为固定的 7’h51)。所以当主机想给某个器件发送数据时,只需向总线上发送接收器件的器件地址即可。
对于AT24C64 (EEPROM)而言,其器件地址为 1010 加 3 位的可编程地址,3 位可编程地址由器件上的 3 个管脚A2、A1、A0(见下图)的硬件连接决定。当硬件电路上分别将这三个管脚连接到GND 或VCC 时,就可以设置不同的可编程地址。图示这3 个管脚接地。
进行数据传输时,主机首先向总线上发出开始信号,对应开始位S,然后按照从高到低的位序发送器件地址,一般为 7bit,第 8bit 位为读写控制位R/W,该位为 0 时表示主机对从机进行写操作,当该位为1 时表示主机对从机进行读操作,然后接收从机响应。对于AT24C64 来说,其传输器件地址格式如下图所示。
发送完第一个字节(7 位器件地址和一位读写控制位)并收到从机正确的应答后就开始发送字地址(Word Address)。一般而言,每个兼容 I2C 协议的器件,内部总会有可供读写的寄存器或存储器。所以,当我们对一个器件中的存储单元(包括寄存器)进行读写时,首先要指定存储单元的地址即字地址,然后再对该地址读写内容。该地址为一个或两个字节长度,具体长度由器件内部的存储单元的数量决定,当存储单元数量不超过一个字节所能表示的最大数量(28=256)时,用一个字节表示,超过一个字节所能表示的最大数量时,就需要用两个字节来表示,例如同是 EEPROM 存储器,AT24C02 的存储单元容量为Kbit=256Byte(一般 bit 缩写为 b,Byte 缩写为B),用一个字节地址即可寻址所有的存储单元,而AT24C64 的存储单元容量为 64Kb=8KB,需要 13 位(213=8KB)的地址位,而 I2C 又是以字节为单位进行传输的,所以需要用两个字节地址来寻址整个存储单元。下图分别为单字节字地址和双字节字地址器件的地址分布图,其中单字节字地址的器件是以存储容量为 2Kb 的EEPROM 存储器AT24C02 为例,双字节字地址的器件是以存储容量为 64Kb 的EEPROM 存储器AT24C64 为例,WA7 即字地址Word Address 的第7 位,以此类推,用 WA是为了区别前面器件地址中的A。
主机发送完字地址,从机正确应答后就把内部的存储单元地址指针指向该单元。如果读写控制位 R/W位为“0”即写命令,从机就处于接收数据的状态,此时,主机就开始写数据了。写数据分为单次写(对于EEPROM 而言,称为字节写)和连续写(对于EEPROM 而言,称为页写),那么这两者有什么区别呢?对比下图可知,两者的区别在于发送完一字节数据后,是发送结束信号还是继续发送下一字节数据,如果发送的是结束信号,就称为单次写,如果继续发送下一字节数据,就称为连续写。下图分别是 AT24C64 的单次写(字节写)时序和AT24C64 连续写(页写)时序。对于字地址为单字节的 I2C 器件而言,在发送完字地址(对应下图单次写时序的字地址高位),且从机应答后即可串行发送 8bit 数据。要注意的是,对于 AT24C64 的页写,是不能发送超过一页的单元容量的数据的,而 AT24C64 的一页的单元容量为 32Byte, 当写完一页的最后一个单元时,地址指针指向该页的开头,如果再写入数据,就会覆盖该页的起始数据。
如果读写控制位R/W 位为“1”即读命令,主机就处于接收数据的状态,从机从该地址单元输出数据。读数据有三种方式: 当前地址读、 随机读和 连续读。
当前地址读是指在一次读或写操作后发起读操作。由于 I2C 器件在读写操作后,其内部的地址指针自动加一,因此当前地址读可以读取下一个字地址的数据。也就是说上次读或写操作的单元地址为 02 时,当前地址读的内容就是地址03 处的单元数据,时序图如下图所示。
由于当前地址读极不方便读取任意的地址单元的数据,所以就有了随机读,随机读的时序有点奇怪,见下图,发送完器件地址和字地址后,竟然又发送起始信号和器件地址,而且第一次发送器件地址时后面的读写控制位为“0”,也就是写命令,第二次发送器件地址时后面的读写控制位为“1”,也就是读。为什么会有这样奇怪的操作呢?这是因为我们需要使从机内的存储单元地址指针指向我们想要读取的存储单元地址处,所以首先发送了一次Dummy Write 也就是虚写操作,只所以称为虚写,是因为我们并不是真的要写数据,而是通过这种虚写操作使地址指针指向虚写操作中字地址的位置,等从机应答后,就可以以当前地址读的方式读数据了,如下图所示,随机地址读是没有发送数据的单次写操作和当前地址读操作的结合体。
至于连续读,对应的是当前地址读和随机读都是一次读取一个字节而言的,它是将当前地址读或随机读的主机非应答改成应答,表示继续读取数据,下图是在当前地址读下的连续读。