Full picture
13

内部集成电路(I²C)

13.1 概述

在撰写本文时,本项目选择的一些约束条件导致了主板上某些组件的选择。事实上,具有并行接口且同时采用 DIP 封装的集成设备越来越少见,较新的设备通常采用 SMD 封装,甚至不再使用 5V 供电。

一个例外是 I²C 设备,例如 EEPROM、传感器或实时时钟。这些设备占用面积非常小,在 PCB 上占据很少的空间,通常可以在不同电压下工作(包括 5V),并且它们使用相同的通信协议:内部集成电路,即 I²C,有时也称为两线接口。

该协议的主要优势在于它只需要两条线。第一条是 SCL,用于时钟;第二条是 SDA,用于数据。由于它是一种多主多从协议,我们想要通信的所有设备都将连接到这两条线上。此外,因为有时钟线,我们可以根据需要放慢速度,而不会影响传输数据的完整性。

13.2 硬件实现

与前面讨论的 UART 类似,I²C 的 SDA 和 SCL 线源自 Z80 PIO 的三个 I/O。 然而,其中两个,SDA OUTSCL OUT,经过充当开漏缓冲器的 74LS07 集成电路。 事实上,I²C 协议要求 SDA 和 SCL 线采用开漏配置。这意味着它们只能由主设备或从设备拉低,并且当它们处于高阻状态时,上拉电阻必须将其维持在高电平。

在 Zeal 8-bit Computer 的情况下,74LS07 的输出信号通过一个 4.7kΩ 电阻阵列(在 PCB 上标记为 RN3)连接到 Vcc。这个电阻值相当典型,让我们能够达到 100KHz,并且具有比使用更经典的 10kΩ 更快的跳变速度。

当然,PIO 还应该能够检查 SDA 线的当前状态,因为它是一条双向线,所以它也被路由到其中一个 I/O。

总的来说,Zeal 8-bit Computer 上的 I²C 总线组织如下:

I2C 连接
Zeal 8-bit Computer 上的 I²C 总线组织

13.3 协议描述

如上所述,I²C 是一种多主多设备协议,依赖于两条线:时钟线和数据线。为简单起见,在本部分中,我们只考虑只有一个主设备的情况,即我们的 Zeal 8-bit Computer。

默认情况下,当总线空闲时,时钟线 SCL 和数据线 SDA 都保持高电平。同样,这是通过上拉电阻实现的。

主设备发起所有传输,从设备无法仅通过 I²C 启动异步传输,这意味着主设备必须轮询从设备以等待特定事件的发生。要与某个从设备通信,主设备必须知道其地址:每个从设备都有 7 位或 10 位地址,在数据手册中有描述。这里,我们只考虑 7 位地址。它们总是在设备的数据手册中描述。

此外,无论传输是读取还是写入,主设备都要控制总线时钟。换句话说,主设备切换 SCL 线。连接的设备只有在 SCL 线为低电平时才能改变数据线(SDA)。一旦 SCL 线变为高电平,它们就不能再改变线路状态。

一次传输由以下部分组成:

  • 起始条件:当 SCL 线仍为高电平时,SDA 线变为低电平。
  • 从设备地址:由主设备在 SDA 线上写入。
  • $read$/$\overline{write}$ 位:由主设备写入,告知从设备此次传输是读取还是写入。
  • 从设备 ACK 位:如果某个设备识别到自己的地址,它通过将 SDA 线拉低来确认。
  • $n$ 个数据帧:每个帧为 8 位,如果是读取,由从设备写入;如果是写入,由主设备写入。每个帧后跟一个 ACK 位,分别由主设备或从设备控制。
  • 停止条件:当 SCL 线为高电平时,SDA 线变为高电平。

有关传输过程中每条线路状态的详细信息,请参考官方 I²C 规范。

📚 深入阅读

为了实现由从设备发起的异步传输,一些 I²C 设备可能会提供额外的信号,让主设备知道事件刚刚发生并且有数据可读。 实际上,这些额外信号可以是中断信号或简单的 GPIO,告知 CPU(主设备)某个从设备收到了事件,需要与之发起传输。

典型的读取传输

下图展示了一次读取传输在数据方面的样子:

I2C 读取事务
I²C 读取事务

需要注意的是,在读取传输过程中,主设备接收到的每个字节(最后一个除外)之后,SDA 线都会被拉低以标记 ACK 位。事实上,主设备接收到的最后一个字节必须后跟一个 NACK 位,这由 SDA 线被拉高来表示。

典型的写入传输

执行写入事务非常类似,不同之处在于从设备地址后发送的位是 1(SDA 线拉高),数据帧由主设备发送给从设备。当然,在这种情况下,ACK 位由从设备发送:

下图展示了写入传输在数据方面的样子:

I2C 写入事务
I²C 写入事务

典型的写-读传输

在大多数情况下,仅靠读取传输不足以指定应从从设备读取的确切数据。事实上,设备通常有内部寄存器或索引数据。

例如,如果从设备是一个 EEPROM,主设备很可能需要指定从哪个地址读取数据,否则它将需要读取整个 EEPROM 才能获取所需数据。

I²C 协议有一种特殊的传输方式,允许主设备在从从设备接收数据之前,先向从设备写入数据。这种事务称为写-读,如下图所示:

I2C 写-读事务
I²C 写-读事务

有趣的是,在第二次传输(即读取)之前有一个重启条件,而中间没有停止条件。

在读取之前先写入的数据帧数量取决于设备,应在其数据手册中查看。通常是一个或两个字节。在 Zeal 8-bit Computer 的情况下,内部的 I²C 设备只需要在相关数据读取前写入一个字节。

13.4 限制

与 UART 类似,由于 I²C 线路由软件驱动,时钟速度受限于 CPU 速度。因此,在 50% 占空比的情况下,Zeal 8-bit Computer 的 I²C 时钟可以达到标准化的 100KHz。

通过更多优化且不受 50% 占空比约束,可以达到更快的时钟速度,大约 120-130KHz,但不推荐这样做。

同样,关于如何实现此类协议的示例可以在 Zeal 8-bit Bootloader 源代码 中找到。

13.5 内部 I²C 连接器

用户可以通过用户端口使用 I²C 线路。这允许任何人创建包含一个或多个 I²C 设备的外部模块。

此外,还有一个内部连接器,在 PCB 上标记为 J5,提供这些 SCL 和 SDA 线。其主要目的是将来用于内部用途(例如在机箱内部),但目前仍然可以供需要的用户自由使用。

该连接器是一个标准的 5 针 XH2.54mm 带锁公座。任何 2.54mm XH 母座均可适配。其引脚排列如下:

I2C 内部连接器
内部 I²C 连接器引脚排列

各引脚说明:

  • $Vcc$ 和 $GND$:分别为 5V 电源和地
  • $I^2C\ SCL$:由软件生成的开漏 I²C 时钟信号。该信号上拉到 5V,请确保连接的设备支持 5V。
  • $I^2C\ SDA$:由软件生成的开漏 I²C 数据信号。该信号上拉到 5V,请确保连接的设备支持 5V。
  • $\overline{INT}$:连接到 Z80 CPU 的开漏中断线。每当一个设备想要在 CPU 上触发中断时,此线被拉低。请确保产生中断的设备与 Z80 模式 2 中断模式兼容!
EN | 中文Beta