Hempl/I2C
I2C 代表“集成电路间总线”,用于不同硅芯片之间的通信。更具体地说,总线是一种数字通信通道,可以由多个设备或外设共享。
I2C 应用范围广泛,通常用于同一机箱内集成电路之间的通信,无论是在同一电路板上还是在不同的电路板之间,只要高速通信速度不是关键。
飞利浦最初开发 I2C 用于电视机内部芯片之间的通信,但随着时间的推移,该系统蓬勃发展,从 1982 年首次发布以来,它现已用于超过 1000 种不同的集成电路。
它取得成功的其中一个原因是,它提供了一种实用且经济的方法来创建复杂的电路,通过仅使用两根线(数据线和时钟线)将所有内容连接到同一总线上,这大大减少了必须在电路板上路由的电气信号数量。
现实世界应用的示例包括连接非易失性存储器、实时时钟电路、数字传感器、I/O 扩展器、数字 LED、液晶显示器和开关等设备。
I2C 规范已多次修订,始终保持向后兼容性,从 1992 年的 v1.0、2000 年的 v2.1 和 2007 年的 v3.0。标准模式以高达 100 kbit/s 的速度运行,快速模式以高达 400 kbit/s 的速度运行,快速模式加以高达 1 Mbit/s 的速度运行,或高速模式以高达 3.4 Mbit/s 的速度运行。较高的速度模式是在 I2C 规范的新修订版中添加的,因此并非所有集成电路都支持所有速度。但是,协议是向后兼容的,因此较新的、更快的设备仍然可以与较旧的、较慢的设备通信,并且连接到总线的某个设备的速度不会影响总线上其他设备的速度。Mizar32 I2C 接口的硬件支持标准模式,达到 100 kbit/s,快速模式高达 400 kbit/s。
一些制造商(例如我们的 Atmel 案例)将 I2C 命名为 TWI(双线接口),因为它没有实现完整的 I2C 的每一个细节,但它们是兼容的,本质上是相同的。
为了更好地理解 I2C,让我们更深入地了解 I2C 协议的工作原理。
I2C 是一种半双工协议,这意味着一次只能有一个设备进行通信。总线有两根线:时钟和数据。
主设备为总线提供时钟。最常见的配置是一个主设备和一个或多个从设备。另一种配置是多主模式,其中多个主设备可以在同一总线上通信而不会导致错误。主设备可以通过某种方式在它们之间决定谁在每个时刻控制总线。用于执行此操作的机制称为总线仲裁和时钟同步。
在一个包含单个主设备和多个从设备的配置中,是主设备提供时钟信号,但从设备可以将其降低到较低的速度,如果它们需要一些额外的時間。
在电气上,这两根线通过每个电阻被拉高,设备通过将这些线拉低来发送信号。在标准模式下,总线速度最高为 100 Kbit/s,电阻值为 10K 欧姆,快速模式下,高达 400 Kbit/s,每个电阻为 2.2K 欧姆。
每个从设备都有一个 7 位地址,它在总线上响应该地址,并且同一 I2C 总线上的每个设备都必须设置为响应不同的地址。
当两个设备进行通信时,其中一个是主设备,另一个是从设备,其中一个在总线上传输数据,另一个接收数据,因此在任何特定时刻,设备可以是主发射器、主接收器、从接收器或从发射器。
以下是主发射器(启动与从设备通信的设备)生成的信号序列。
第一个事件是主发射器生成一个启动条件,即数据 (SDA) 线在时钟 (SCL) 线为高电平时的从高电平到低电平的转换。所有 I2C 消息中的第一件事始终是启动条件。
启动条件会导致所有从设备唤醒并监听,因此主设备发送从接收器地址(由 7 位组成),后跟一个方向位(0 表示发送,1 表示接收),然后从接收器生成一个确认 (ACK) 位,以表示它已识别其地址并正在监听。如果方向位为 0,表示主设备要向从设备发送数据,它将传输 8 位数据,从设备再次发送一个 ACK 位,主设备发送另一个 8 位数据,从设备发送一个 ACK,依此类推。在每个数据字节之后,接收数据的从设备必须通过将数据线短时间拉低来发送一个 ACK 位。如果缺少 ACK,则表示没有人收到数据,并且正在传输的任何人都将停止传输。在所有数据字节传输完成后,主设备通过在总线上生成停止条件来关闭通信,即在时钟 (SCL) 为高电平时的 SDA 线从低电平到高电平的转换。所有 I2C 消息始终以停止条件结束。
以更简洁的形式
S | 启动条件 |
ADDR | 7 位从设备地址 |
R/W | 数据方向位:1 表示读取或 0 表示写入 |
DATA | 8 位数据 |
ACK | 1 位确认 |
P | 停止条件 |
有时 ADDR 和 R/W 被视为一个 8 位值,地址在最高 7 位,R/W 标志在最低有效位。例如,我们可能会谈论 7 位从设备地址 42 和方向位 1,而在其他时刻,我们可能会谈论 8 位从设备地址 85,其含义相同。
以下是主设备向从设备发送两个数据字节的简洁视图
S | ADDR | W | ACK | DATA | ACK | DATA | ACK | P |
AVR32UC3A 芯片有一个 I2C 控制器,Mizar32 在左侧总线连接器 BUS2 上提供其信号。
Mizar32 的主板还具有 PCA9540 双向 I2C 多路复用器芯片,它可以将 I2C 信号连接到两个或更多组 I2C 总线引脚中的任一组,即左侧和右侧 I2C 总线,其中一个在 BUS2 上可用,另一个在 BUS5 连接器上可用。如果您使用这些而不是主 I2C 总线引脚,则您的系统中可以拥有两倍的 I2C 设备。此外,如果您的硬件设计需要两个响应相同 I2C 地址的 I2C 设备,您可以将一个放在左侧 I2C 总线上,另一个放在右侧。
当 Mizar32 开机时,多路复用器处于非活动状态,AVR32 的 I2C 信号仅馈送到主 I2C 总线引脚。要使 I2C 总线信号出现在左侧 I2C 总线上,您将值 5 编程到多路复用器的控制字中,要与右侧总线通信,您将值 4 编程到控制字中。要禁用多路复用器,您将编程为 0。
请参见下面的代码示例,了解如何使用 eLua 执行此操作。
I2C 多路复用器和 Mizar32 附加模块上的所有主 I2C 设备都在主 I2C 总线上,因此您不必编程 I2C 多路复用器即可访问它们。Mizar32 模块放置在左侧和右侧 I2C 总线上的唯一设备是每个附加模块上的 EEPROM。
信号 | GPIO | 总线引脚 | 备注 |
---|---|---|---|
SDA | PA29 | BUS2 引脚 10 | 主 I2C 总线数据 |
SCL | PA30 | BUS2 引脚 11 | 主 I2C 总线时钟 |
BUS_SDA_L | - | BUS2 引脚 12 | 左侧 I2C 总线数据 |
BUS_SCL_L | - | BUS2 引脚 13 | 左侧 I2C 总线时钟 |
BUS_SDA_R | - | BUS5 引脚 3 | 右侧 I2C 总线数据 |
BUS_SCL_R | - | BUS5 引脚 4 | 右侧 I2C 总线时钟 |
下表显示了 Mizar32 及其附加模块上芯片使用的 I2C 从设备地址。
在下表中,我们同时提供了 7 位代码的十进制表示法和相应的 8 位命令字节值的十六进制表示法。
设备 | 7 位地址 (十进制) |
8 位 (十六进制) |
备注 |
---|---|---|---|
LCD 显示屏(命令) | 0111110 (62) |
7C/7D |
读取返回光标位置 |
LCD 显示屏(数据) | 0111111 (63) |
7E/7F |
读取返回按钮 |
VGA 板 24LC512 | 1010000 (80) |
A0/A1 |
(1) |
以太网板上的 PCF8563 RTC | 1010001 (81) |
A2/A3 |
|
以太网板上的 DS1337 RTC | 1101000 (104) |
D0/D1 |
|
I2C 多路复用器 PCA9540 | 1110000 (112) |
E0/E1 |
(1) VGA 的 24LC512 EEPROM 包含运行 VGA 板的 Parallax Propeller 芯片的程序,该程序仅在 VGA 板上焊接了 GS4 和 GS5 两对触点时才连接到 Mizar32 的主 I2C 总线,从而允许您使用Mizar32 Propeller 编程器从 Mizar32 编程 Propeller 芯片。
Hempl 具有一个i2c
模块,提供设置、启动、地址、发送/接收字节和停止基元。
# Send a byte to the i2c multiplexer to tell it to # enable the left i2c bus (setq id 0 # Which i2c bus to use? mux-addr 112 # The slave address of the i2c mux mux-disable 0 # Control word to disable the mux mux-left 4 # Control word to enable left bus mux-right 5 ) # Control word to enable right bus (i2c-start 0) (if (not (= T (i2c-address id mux-addr *i2c-transmitter*))) (prinl "The multiplexer did not reply") (if (not (= (i2c-write id mux-left) mux-left)) (prinl "The multiplexer did not acknowledge the write") ) ) (i2c-stop id)
请注意:您也可以从我们的 GitHub 示例库中下载上述代码 send-data.l
。
# Retrieve and print the contents of the i2c splitter's # control register # misc.l in the Alcor6L codebase contains # the function PicoLisp function stringToNum. # misc.l should exist in /mmc (load "@misc.l") (setq id 0 # Which i2c bus to use? (there's only one!) mux-addr 112 ) # The slave address of the i2c multiplexer (i2c-start id) (if (not (= T (i2c-address id mux-addr *i2c-receiver*))) (prinl "The multiplexer did not reply") (let (cr (i2c-read id 1)) # Read the control register (one byte) (prinl "Control register: " (stringToNum cr)) ) ) (i2c-stop id)
请注意:上述程序需要文件 misc.l
才能正常工作。此版本的 misc.l
与预装在现成 PicoLisp 中的版本不同。您也可以从我们的 GitHub 示例库中下载 read-data.l
。
- 维基百科的 I2C 文章
- Atmel AT32UC3A 数据手册 第 24 章:双线接口 (TWI)。
- 飞利浦半导体 PCA9540 双通道 I2C 多路复用器数据手册
- 飞利浦半导体 I2C 地址分配表