ZYNQ 分为 PS 和 PL 两部分,那么器件的引脚(Pin)资源同样也分成了两部分。
ZYNQ PS 中的外设可以通过 MIO(Multiuse I/O,多用输入/输出)模块连接到 PS 端的引脚上,也可以通过 EMIO 连接到 PL 端的引脚。Zynq-7000 系列芯片一般有 54 个 MIO,个别芯片如 7z007s 只有 32 个。
GPIO 是英文“general purpose I/O”的缩写,即通用的输入/输出。是 ZYNQ PS 中的一个外设,用于
观测和控制器件引脚的状态。
图 1 是 GPIO 的框图,从中可以看到 GPIO 分为 4 个 Bank,其中 Bank0和 Bank1 连接到 MIO;而 Bank2 和 Bank3 连接到 EMIO。 除 Bank1 之外的 Bank 都具有 32bit,Bank1 只具有 22bit 是因为总共只有 54 个 MIO,其中 32bit 的Bank0 控制了 MIO[0-31],剩下的MIO[31~53]就由 22bit 的 Bank1 控制。Bank2 和 Bank3 用于控制扩展的MIO 即 EMIO,也就是说总共可以有 32+32=64 个 EMIO。
PS 所有的外设都可以通过 MIO 访问,这些外设也是与 MIO 进行连接,每个 MIO 虽然可以独立控制,
以及独立驱动单个引脚的外设,但对于 QSPI、USB、以太网等这些外设,其于 MIO 的连接有着特殊的要求,如图 2 所示,(图中灰色框表示在 CLG225 封装的芯片中不可用)对于以太网而言,其只能与 MIO16~ 27 和 MIO28~39 引脚连接,而且以太网与 MIO28 连接的引脚只能作为以太网的 tx_clk 使用,可见当其作为以太网的接口引脚时,相应的 MIO 的功能就已经确定下来了。MIO 还有一特点,如 MIO28 ~ 39 引脚即可以与以太网进行连接,也可以作为 USB 以及其它外设的接口引脚,所以当我们设计 PS 的外设时要合理分配 MIO。 从图 2 MIO 一览表中我们可以看到 MIO 一但选定,引脚位置就已经确定下来了,不需要添加引脚约束。
图 3 展示了 MIO 与 PS 的连接。MIO 的 PS 外设的大多数 I/O 信号(USB 除外)可以通过 MIO 路
由到 PS 引脚,或通过 EMIO 路由到 PL 引脚。除千兆以太网外,大多数外设还在 MIO 和 EMIO 之间保持相同的协议。千兆以太网为减少引脚数,使用 4 位的 RGMII 接口以 250 MHz 数据速率(125 MHz 时钟,双倍数据速率)通过 MIO。如果接到 EMIO,就使用一个以 125 MHz 数据速率运行的 8 位 GMII 接口。需要注意的是 Quad-SPI、USB 和 SMC 接口不适用于 PL 的 EMIO 接口。
从图中可以看到 PS 通过 APB 总线对控制、状态寄存器的读写实现对 GPIO 的驱动,具体可以参见下图。
图 4 左边的一列是寄存器,上半部分是关于中断的,这里重点介绍下红色框圈出的下半部分。
DATA_RO 是数据只读寄存器,通过该寄存器能够观察器件引脚上的值。如果 GPIO 信号配置为输出,
则通常会反映输出上驱动的值,写入此寄存器将被忽略。
DATA 是数据寄存器,该寄存器控制 GPIO 信号配置为输出时要输出的值。该寄存器的所有 32 位都是
一次写入的。读取该寄存器返回写入 DATA 或 MASK_DATA_ {LSW,MSW}的先前值,它不会返回器件引脚上的当前值。
MASK_DATA_LSW 和 MASK_DATA_MSW 是数据掩码寄存器,该寄存器使软件能够有选择地一次更
改所需的的输出值。可以写入最多 16 位的任意组合,MASK_DATA_LSW 控制 Bank 的低 16 位,
MASK_DATA_MSW 控制高 16 位。未写入的那些位保持不变并保持其先前的值。读取该寄存器返回写入DATA 或 MASK_DATA_ {LSW,MSW}的先前值;它不会返回器件引脚上的当前值。该寄存器避免了对未更改位的读-修改-写序列的需要。
DIRM 是方向模式寄存器,用于控制 I/O 引脚是用作输入还是输出。当 DIRM [x] == 0 时,输出驱动器
被禁用,该引脚作为输入引脚使用。
OEN 是使能输出寄存器。将 I/O 配置为输出时,该寄存器控制是否启用输出。禁用输出时,引脚为 3
态。当 OEN [x] = = 0 时,输出被禁用。
从这些寄存器中可以看到,如果配置引脚为输出,不仅需要设置方向,还要使能输出。关于这些寄
存器的具体介绍,可参考 ug585 手册的 Appx.B:Register Details 中的 General Purpose I/O (gpio)一节。需要说明的是我们在程序中操作 MIO 时直接调用 Xilinx 官方提供的函数即可,无需直接操作这些寄存器。另外需要说明的是 MIO 信号对 PL 部分是透明的,所以对 MIO 的操作是纯 PS 的操作,且每个 GPIO都可独立动态编程为输入、输出或中断检测,此处需要注意的是 MIO7 和 8 只能做为输出 IO 使用。