GPIO 之 EMIO 按键控制 LED 实验
PS 和外部设备之间的通信主要是通过复用的输入/输出( Multiplexed Input/Output, MIO)实现的。 除此之外, PS 还可以通过扩展的 MIO( Extended MIO, EMIO)来实现与外部设备的连接。 EMIO 使用了 PL 的I/O 资源, 当 PS 需要扩展超过 54 个引脚的时候可以用 EMIO, 也可以用它来连接 PL 中实现的 IP 模块。本章我们将学习 GPIO 中 EMIO 接口信号的使用。 本章包括以下几个部分:
一. 简介
ZYNQ GPIO 接口信号被分成四组,分别是从 BANK0 到 BANK3。其中 BANK0 和 BANK1 中共计 54
个信号通过 MIO 连接到 ZYNQ 器件的引脚上,这些引脚属于 PS 端; 而 BANK2 和 BANK3 中共计 64 个信号则通过 EMIO 连接到了 ZYNQ 器件的 PL 端, 如下图所示:
在大多数情况下, PS 端经由 EMIO 引出的接口会直接连接到 PL 端的器件引脚上, 通过 IO 管脚约束来
指定所连接 PL 引脚的位置。 通过这种方式, EMIO 可以为 PS 端实现额外的 64 个输入引脚或 64 个带有输出使能的输出引脚。 EMIO 还有一种使用方式,就是用于连接 PL 内实现的功能模块( IP 核) , 此时 PL 端的 IP 作为 PS 端的一个外部设备, 如图 所示:
二. 设计实现
本章的实验任务是使用领航者 ZYNQ 底板上的两个用户按键分别控制 PS 端两个 LED 的亮灭。其中一个按键 PL_KEY0 连接到了 PL 端, 需要通过 EMIO 进行扩展,另外一个按键是底板上 PS 端的用户按键
PS_KEY0,这两个按键分别控制 PS_LED0 和 PS_LED1,底板上的 PS_KEY0 控制 PS_LED0、 PL_KEY0 控
制 PS_LED1。 两个 LED 灯在按键按下的时候点亮,释放后熄灭。
1. 硬件设计
当 PL_KEY0、 PS_KEY0 没有按下时,对应的 IO 端口为高电平;当按键按下时,对应的 IO 端口变为
低电平。由实验任务可知,本次实验是通过底板上的两个按键去控制 PS 端两个 LED 灯的亮灭,因此需要在硬件系统框图里添加 GPIO 外设控制器, 通过 GPIO 控制器上的 3 个 MIO 引脚路由到 PS 端两个 LED 灯和一个按键, 以及一个 EMIO 引脚路由到 PL 端的按键。 本实验系统框图如下图所示:
与《GPIO 之 MIO 控制 LED 实验》中的系统框图相比, 上图中的 PS 端多了 EMIO 模块。除此之外,
因为 EMIO 使用了 PL 端的 IO 资源,所以图中增加了 PL 部分。与按键 PL_KEY0 相连的 PL 端的引脚直接
通过 EMIO 连接到 PS 端。
a. step1:创建 Vivado 工程
本次实验可以在前一个实验的基础上进行。
1-1 我们打开《GPIO 之 MIO 控制 LED 实验》中的 Vivado 工程“ gpio_mio”,打开后在菜单栏中选择
File > Project > Save As,如下图所示:
1-2 在弹出的另存为界面中可以输入新的工程名,此处我们输入新的工程名“ gpio_emio”,工程位置保
持默认即可, 勾选了“ Create project subdirectory”后会在工程位置下创建一个与工程名同名的文件夹,这里的“ Include run results”可勾选也可不勾选(勾选后可以保留之前工程中的 Generate Output Products 的运行结果,不勾选的话则不会保留), 如下图所示,然后点击“ OK”按钮。
点击“ OK”按钮,原先的 Vivado 工程会关闭,并打开一个新的工程“ gpio_emio”。
此时如果我们打开工程所在的路径,即 F:\ZYNQ\Embedded_Vitis\gpio_emio,可以看到如下图所示的文
件目录:
此时我们就在 gpio_mio 工程的基础上得到了一个新的工程 gpio_emio,这样就省去了重新搭建硬件的
过程。
接下来我们将在《GPIO 之 MIO 控制 LED 实验》中硬件设计的基础上搭建本次实验的硬件平台。
b. step2:使用 IP Integrator 创建 Processing System
2-1 在 Flow Navigator 中,点击 IP INTEGRATOR 下的 Open Block Design,如下图所示:
2-2 在 Diagram 窗口中,双击打开 ZYNQ7 Processing System 重定义窗口。
2-3 在下图所示的配置界面中,点击左侧的 MIO Configuration。然后在右侧展开 GPIO 一栏, 勾选 EMIO GPIO,并设置位宽为 1。该设置将通过 EMIO 扩展一个 1 位的 GPIO 接口信号,此信号将用于连接 PL 端的引脚。
完成配置后,点击右下角的“ OK”按钮。 然后在 Diagram 窗口中可以看到 ZYNQ7 Processing System
多了一个 GPIO_0 端口,如下图所示:
将光标移动到上图中箭头所指示的位置,会发现光标变成了铅笔的样式。 点击选中该端口, 然后点击
鼠标右键,在弹出的列表中选择“ Make External” , 如下图所示:
可以看到 ZYNQ7 Processing System 引出了一个名为 GPIO_0_0 的接口, 如下图所示:
点击选中该接口,在左侧 External Interface Properties 一栏中将该接口的名称修改为 GPIO_EMIO_KEY,
如下图所示:
2-4 本次实验不需要添加其它的 IP,按 Ctrl+S 快捷键保存设计。
c. step3:生成顶层 HDL
3-1 在 Sources 窗口中展开 Design Sources, 然后右键点击 sysetm_wrapper 下的 system.bd, 在弹出的菜单中选择 Generate Output Products,如下图所示:
3-2 在弹出的对话框中选择“ Generate” ,然后等待 Generate 完成后点击“ OK” 。
3-3 创建顶层 HDL Wrapper
在之前的实验中, 我们创建顶层模块时选择了“ Let Vivado manage wrapper and auto-update” ,所以此处无需再创建顶层 HDL Wrapper, Vivado 会自动更新顶层 HDL Wrapper,但 vivado 有时会有 bug 导致无法自动更新,所以需要先双击打开 system_wrapper.v 文件,查看顶层端口是否会有出现 GPIO_EMIO_KEY_tri_io端口信号。
如果 system_wrapper.v 文件中出现了GPIO_EMIO_KEY_tri_io 端口信号,说明顶层文件已经自动更新了。若没有出现,就需要将 system_wrapper.v 删除,然后重新生成新的 system_wrapper.v 文件。只需右键点击system.bd, 在弹出的菜单中选择 Create HDL Wrapper…,之后就可以生成新的system_wrapper.v 文件。
d. step4:生成 Bitstream 文件并导出硬件
4-1 在左侧 Flow Navigator 导航栏中找到 RTL ANALYSIS, 点击该选项中的“ Open Elaborated Design” ,如下图所示:
在弹出的对话框中点击“ OK” , 如下图所示:
在 ELABORATED DESIGN 界面下方找到 I/O Ports 窗口。 如果没有找到 I/O Ports 一栏则通过在菜单栏
中点击 Layout, 然后在下拉列表中选择 I/O Planning。 我们将在 I/O Ports 窗口中对 PL 部分的接口进行管脚分配,如下图所示:
在上图中, DDR_12642 和 FIXED_IO_12642 里面是 PS 端的输入/输出接口,这部分接口不需要我们手
动进行管脚分配。 在图 4.3.13 中选择“ Generate Output Products” 之后, Vivado 工具会自动创建 PS 端的管脚约束文件。
在本次实验中,我们通过 EMIO 扩展了一个 GPIO 的接口信号,即上图中的 GPIO_EMIO_KEY。我们
需要将其分配到 PL 的 L14 引脚上,从原理图上可以看到, 该引脚最终与领航者 ZYNQ 底板上的按键
PL_KEY0 相连接。 另外 L14 位于 ZYNQ7020 芯片的 BANK35,该 BANK 的供电电压为 3.3V, 因此 I/O Std一列对应的电平也需要修改, 如下图所示:
4-2 设置完成后按快捷 Ctrl+S 保存管脚约束,在弹出的对话框输入文件名“ pin” , 最后点击“ OK” ,如下图所示:
4-3 在左侧 Flow Navigator 导航栏中找到 PROGRAM AND DEBUG, 点击该选项中的“ Generate
Bitstream”,然后在连续弹出的对话框中依次点击“ YES”、“ OK” 。 此时, Vivado 工具开始对设计进行综合、 实现、并生成 Bitstream 文件。
4-4 生成 Bitstream 完成后, 在弹出的对话框中选择“ Open Implemented Design” , 如下图所示:
点击“ OK” ,会弹出对话框提示关闭 Elaborated Design, 点击“ YES” 。
在 IMPLEMENTED DESIGN 界面我们可以查看设计对 PL 资源的使用情况。 在左侧 Flow Navigator 导
航栏中找到 IMPLEMENTATION, 点击该选项中的“ Report Utilization”, 然后在弹出的对话框中点击“ OK”,如下图所示:
在界面下方的 Utilization 标签页中,选择左侧的 Summary, 然后在右侧会以表格和柱状图两种方式显
示当前 PL 资源的使用情况。在我们本次实验中, 只消耗了 PL 端 1 个 LUT 和一个 IO 资源,这个 IO 就是
PS 通过 EMIO 扩展 GPIO 接口信号时所使用的 PL 引脚,如下图所示:
4-5 导出硬件。
在导出硬件之前,需要先关闭 Elaborated Design 界面(若不关闭,则无法导出硬件 xsa 文件)。
关闭 Elaborated Design 界面后, 在菜单栏中选择 File > Export > Export hardware。
在弹出的对话框中,勾选“ Include bitstream”,然后点击“ Next”按钮, 如下图所示:
在此处需要注意, 如果我们的设计使用了 PL 的资源,比如使用了 PL 的引脚,或者在 PL 内实现了部
分功能模块,那么我们就需要生成 Bitstream 文件, 并在导出硬件的时候包含该文件。
先在当前工程路径下新建一个 vitis 文件夹,然后在 Export Hardware Platform 对话框中点击 Export to 后面的省略号按钮,在弹出的 Export Directory 对话框中选中 vitis 文件夹,然后点击 select;返回到 Export Hardware Platform 对话框后点击 Finish。
到这里我们的硬件设计部分已经结束,接下来的软件设计部分需要在 Vitis 软件中进行, 在菜单栏中选
择 Tools > Launch Vitis,启动 Vitis 开发环境。 在弹出的对话框中,将路径指定到新建的 vitis 文件夹下,点击 Launch 启动 Vitis。
2. 软件设计
在硬件设计的最后,我们打开了 Vitis 开发环境, 下面我们开始第五步——创建应用工程。
a. step5:在 Vitis 中创建应用工程
5-1 可以在菜单栏选择 File > New > Application Project, 也可以在界面中点击“ Create Application Project”去新建一个 Vitis 应用工程
5-2 打开 Create a new platform from hardware(XSA)标签页,点击“Browse”添加 xsa 文件,如下图所示:
在弹出的窗口中选择 system_wrapper.xsa 文件,如下图所示:
添加 xsa 文件后的页面如下图所示,点击“ Next” :
5-3 在弹出的对话框中,输入工程名“ gpio_emio”,其它选项保持默认即可,点击“ Next” 。在弹出的界面中保持默认设置,然后继续点击“ Next” 。
5-4 然后选择工程模版 Empty Application,然后点击“ Finish”。
5-5 新建源文件。在 gpio_emio/src 目录上右键点击,选择 New > File,如下图所示
5-6 新建源文件之后,在左侧 gpio_emio/src 目录下可以看到 main.c 文件,同时在 Vitis 主页面已经打开了该文件的文本编辑框。我们在新建的 main.c 文件中输入自己编写的代码。
本程序的设计思路:
本次实验所用到的外设如按键和 LED 灯,都是通过 GPIO 控制器来实现其功能,所以主程序里需要先
对 GPIO 外设控制器做初始化,并对按键对应的 GPIO 做输入配置和使能,对 LED 灯对应的 GPIO 做输出
配置和使能。由硬件设计部分的原理图可知,按键未按下是高电平,按下后是低电平, 所以需要将读到的
按键值,取反后赋值给 LED 灯。
详细的代码如下所示:
#include "stdio.h"
#include "xparameters.h"
#include "xgpiops.h"#define GPIOPS_ID XPAR_XGPIOPS_0_DEVICE_ID //PS端 GPIO器件 ID#define MIO_LED0 7 //PS_LED0 连接到 MIO7
#define MIO_LED1 8 //PS_LED1 连接到 MIO8
#define MIO_KEY0 12 //PS_KEY0 连接到 MIO12
#define EMIO_KEY 54 //PL_KEY0 连接到EMIO0int main()
{printf("EMIO TEST!\n");XGpioPs gpiops_inst; //PS端 GPIO 驱动实例XGpioPs_Config *gpiops_cfg_ptr; //PS端 GPIO 配置信息//根据器件ID查找配置信息gpiops_cfg_ptr = XGpioPs_LookupConfig(GPIOPS_ID);//初始化器件驱动XGpioPs_CfgInitialize(&gpiops_inst, gpiops_cfg_ptr, gpiops_cfg_ptr->BaseAddr);//设置LED为输出XGpioPs_SetDirectionPin(&gpiops_inst, MIO_LED0, 1);XGpioPs_SetDirectionPin(&gpiops_inst, MIO_LED1, 1);//使能LED输出XGpioPs_SetOutputEnablePin(&gpiops_inst, MIO_LED0, 1);XGpioPs_SetOutputEnablePin(&gpiops_inst, MIO_LED1, 1);//设置KEY为输入XGpioPs_SetDirectionPin(&gpiops_inst, MIO_KEY0, 0);XGpioPs_SetDirectionPin(&gpiops_inst, EMIO_KEY, 0);//读取按键状态,用于控制LED亮灭while(1){XGpioPs_WritePin(&gpiops_inst, MIO_LED0,~XGpioPs_ReadPin(&gpiops_inst, MIO_KEY0));XGpioPs_WritePin(&gpiops_inst, MIO_LED1,~XGpioPs_ReadPin(&gpiops_inst, EMIO_KEY));}return 0;
}
在代码的第 7 至 9 行,我们指定了 PS 端的按键和 LED 所连接的 MIO 引脚编号,这些编号可以从领航
者 ZYNQ 核心板和底板的原理图中查到。 而在代码的第 10 行则指定了 PL 端的按键 PL_KEY0 连接到了 GPIO的第 54 号引脚, 那么这个 54 是怎么来的呢?
在本章的简介部分我们提到过, ZYNQ 的 GPIO 被分成了 4 组,其中通过 EMIO 扩展的 GPIO 接口位于
BANK2 和 BANK3 中, 如图 4.1.1 所示。在本次实验中我们通过 EMIO 扩展了 1 个 GPIO 信号, 即 BANK2的 EMIO0。由于 GPIO 的 BANK0 和 BANK1 分别有 32 和 22 个信号,所以 BANK2 的 EMIO0 编号为 54(从0 开始编号) 。
我们按住 Ctrl 键,然后点击代码开头处所引用的头文件“ xgpiops.h”以打开该文件。在文本编辑界面
的左侧空白边框处右击,然后选择“ Show Line Numbers”可以显示代码的行号。
在 xgpiops.h 文件第 162 行给出了 ZYNQ 器件 GPIO 最大的引脚数目,共 118 个, 分别位于 4 个 Bank
中.在下面的注释中则分别列出了各 Bank 的引脚编号范围,同样可以看到 Bank2 的第一个引脚编号为54。
在程序的第 42 至 52 行,我们在一个死循环中不断读取各按键的状态,然后将读到的值取反后分别写
入对应的 LED 中, 从而实现按键控制 LED 的功能。 从上面的程序中大家也可以看出, 通过 EMIO 扩展的GPIO 接口的使用方法和 MIO 没有任何区别。如果大家对 GPIO 的使用不熟悉的话,请参考《GPIO 之 MIO 控制 LED 实验》 。
3. 下载验证
完成了硬件设计和软件设计后,我们就可以进行板级验证了,也就是设计流程的最后一步。在进行板
级验证之前,我们先将开发板上的 JTAG 与电脑连接, 然后使用 USB 连接线将 USB UART(PS_PORT)接口
与电脑连接,然后连接开发板的电源,给开发板上电。
a. step6:板级验证
下载程序。因为本次实验使用了 PL 内的资源,因此我们在下载软件编译生成的 elf 文件之前,需
要先下载硬件设计过程中生成的 bitstream 文件,对 PL 部分进行配置。
右键选择 gpio_emio 工程,在弹出的菜单中选择 Run As-> Run Configurations…,如下图所示:
此时会弹出“ Run Configuration” 的页面,选择“ Debugger_gpio_emio.elf-Default” ,在“ Target
Setup” 页面,勾选中“ Reset entire system” 和“ Program FPGA” ,如下图所示。需要注意的是,如果页面中没有出现“ Debugger_gpio_emio.elf-Default” ,可双击“ Single Application Debug” 打开。
在点击“ Run” 之后, Vitis 软件首先会复位整个系统,清除 FPGA 逻辑,重新下载比特流和 elf 文件,
保证程序可以正常运行。软件程序下载完成后, 在下方的 Terminal 中可以看到应用程序打印的信息“ EMIO TEST!” ,如下图所示:
我们分别按下领航者底板上的两个用户按键 PS_KEY0 和 PL_KEY0,可以看到底板上对应的两个 PS 端
的 LED 灯在按键按下时点亮,释放后熄灭。
按下底板上 PL 端的用户按键 PL_KEY0,可以看到底板上 PS 端的 LED1(红色)在按键按下时点亮,
释放后熄灭。说明我们通过 EMIO 扩展 GPIO 接口, 使用 PL 端按键控制 PS 端 LED 的实验在领航者 ZYNQ 开发板上面下载验证成功, 实验结果如下图所示: