I2C(Inter-Integrated Circuit)是一种由飞利浦半导体(现为恩智浦半导体)在1980年代初开发的同步、串行的总线型通信协议。它主要用于短距离通信,特别是在同一块印刷电路板(PCB)上的集成电路(IC)之间进行通信。

I2C单个字节写时序:(截图来自友晶科技书籍《DE2-115实战宝典》): 

 

  • 发送起始位;

  • 发送slave地址+write bit set;

  • 从设备应答;

  • 发送内部寄存器地址;

  • 从设备应答;

  • 发送8位数据;

  • 从设备应答;

  • 发送停止信号。

 

I2C单个字节读时序

 

  • 发送起始位;

  • 发送slave地址+write bit set;

  • 从设备应答;

  • 发送内部寄存器地址;

  • 从设备应答;

  • 重新发送起始位,即restart;

  • 重新发送slave地址+read bit set;

  • 从设备应答;

  • 从设备发送8位数据;

  • 主机不应答;

  • 发送停止信号。

 

为什么读操作的时序要设计得这么麻烦呢?有一种说法是这里存在一个叫做哑写(Dummy Write )的操作。哑写行为不是真正向地址写数据,不会触发写操作,所以才叫做dummy write。其目的是为了 重置 I2C 从设备的微控制器的内部字节地址计数器归零。但我认为这种说法可能不正确,因为我从恩智浦的I2C官方文档 https://www.nxp.com.cn/docs/en/user-guide/UM10204.pdf 里面并没找到dummy write 的概念。

 

 
 (摘自正电原子的视频截图)

另一种说法是I2C读时序中传输寄存器地址(或者是I2C从设备内部地址)时是写操作,所以前面需要先设置W/R位为W,然后才能向从设备写内部地址。我认为这种说是法正确的。

参考DE2-115 开发板的 EEPROM器件 24LC32来说, 它支持当前地址读随机地址读, 以及连续读操作 这三种模式。I2C 从设备的微控制器的内部字节地址计数器( internal address counter)会根据每读一个数据或者写一个数据就累加1,直到累加到31(写操作) 或者是累加到页尾(读操作)。

以下是对internal address counter描述的原文:

 

如果直接发送器件地址(也就是进行当前地址读),那么它读出来的是当前计数器所指的地址:

 

如果是想读取指定地址的数据(也就是 24LC32的 随机地址读 模式),就需要先指定地址:

 

 以上文字翻译如下:随机读取操作允许主设备以随机方式访问任何内存位置。为了执行这种读取操作,必须首先设置字地址。这通过作为写入操作的一部分将字地址发送给24XX32A来实现(R/W位设为0”)。一旦发送了字地址,主设备将在确认后生成一个起始条件。这终止了写入操作,但内部地址指针还没有被设置。主设备再次发出控制字节,但将R/WV位设为“1”,24XX32A 随后将发出确认信号,并传输8位数据字。主设备不会发送确认,但会生成一个停止条件,导致 24XX32A停止传输(图6-2)。在接收到一个随机的读取命令后,内部地址计数器将指向刚刚读取的地址之后的地址位置。

以上截图来自DE2-115_v.3.0.6_SystemCD\DE2_115_datasheets\Memory\EEPROM\24LC32.pdf。