基于Smart ZYNQ (SP/SP2/SL 版) 的PS实验一 GPIO之用EMIO方式点亮LED(完整图文)

之前的 FPGA 实验中,我们是通过 PL 资源(FPGA 逻辑)来点亮 LED 灯。这次我们将介绍如何利用 ZYNQ 的 PS 资源来实现点亮 LED 灯。由于板上的 LED 资源连接在 PL 端,我们将使用 EMIO方式来进行控制,本次实验的目的是熟悉 PS (SDK) 的开发流程。值得一提的是,从 2019 年开始,Vivado 中的 SDK 已被更名为 Vitis,但基本开发流程相似。

PS 的GPIO分三种:MIO,EMIO和AXI-GPIO: MIO是 ZYNQ PS的固定引脚,用于连接 ARM 处理器和外部设备,而 EMIO是可编程的扩展引脚,允许通过 FPGA 逻辑灵活配置和连接外部设备,AXI-GPIO 则提供了一种通过 AXI 接口与 GPIO 进行通信的方式,进一步增强了系统的灵活性。

通俗的理解MIO就是接在PS上的引脚, 而EMIO可以理解为PS映射到PL(FPGA)端的引脚(对PL端的资源占用非常小,可以简单理解为PS端拉了根导线到PL端对应的IO口),而AXI-GPIO是通过AXI-GPIO模块拓展的功能引脚(相当于PL端需要生成AXI GPIO响应的电路,占用PL资源较EMIO方式多)。

因为Smart ZYNQ上的IO以及外设大多都是接在PL端的(具有更好的拓展性),所以我们着重了解EMIO以及AXI-GPIO的使用方法即可。(MIO和EMIO在PS端的调用方法几乎一致)。

本文先介绍EMIO方式点亮LED灯,下一节再介绍AXI-GPIO方式。

  • 此章节内容适用于Smart ZYNQ SP SP2和 SL 版的板子 ( 不包含Smart ZYNQ 标准版 ),如是标准版或本站其他板子请看对应板子目录
  • 本文在 vivado2018.3版本上演示

一、创建Vivado工程

1) 具体步骤 新建一个VIVADO 工程,打开软件 选中Create Project, 如下图所示

2)点击NEXT ,在出现的第二个对话框“Project name”中输入工程名;在“Project location”中选择保存路径;勾选“Create project subdirectory”,最后点击“Next” 备注,所有的路径均不能出现中文名称

3)点击 RTL PROJECT 选项,点击NEXT

4) 第四步Add Sources 选项直接留空,NEXT

5)第五步Add Constraints 选项直接留空,NEXT

6)选择芯片型号 XC7Z020CLG484-1

7)确认所选信息 点击“Finish”,完成vivado的工程创建

二、创建一个BLOCK设计

1)IP INTEGRATOR→Create Block Design,在弹出的对话框中输入设计名,最后点击“OK”,如下图所示

2) 在右侧的窗口里 ,点击加号,在选择框里搜索ZYNQ,并找到ZYNQ7 PROCESSING SYSTEM ,双击并打开

3)软件自动生成了一个 zynq的block 如下图所示,接下来要做一些相应的设置,双击下图中的ZYNQ核

4)依次在弹窗里找到DDR Configuration→DDR Controller Configuration→DDR3,在Memory Part下拉菜单中根据自己板子上的DDR来选择相应的DDR3,本实验所用到型号:MT41K256M16RE-125,数据位宽选择16bit 最后点击“OK”,如下图所示。

5)在PS的MIO配置选项的GPIO栏里,增加两路EMIO(因为本次测试的是两个,如果需要增加按键或者其它IO 这里可以对应的调整)

6)最后 点击“Run Block Automation”如下图所示。在弹出的选项中保持默认,点击“OK”,即可完成对ZYNQ7 Processing System的配置

7)将刚才添加EMIO GPIO 引出 右键GPIO_0—->Make External

8)用线将M_AXI_GP0_ACLK与 FCLK_CLK0连接起来(本章用不到AXI资源,也可以在设置页将AXI接口禁用掉,此处就不需要连接了)

9)source→Design Source ,右键我们创建的BLOCK工程,点击create HDL wrapper如下图所示。

在弹出的对话框里保持默认

软件自动为我们生成HDL文件

三、创建约束文件,并且定义管脚

1)Add Source → Add or create constraints 点Next

因为这个项目没有创建过约束文件 所以这里创建一个约束文件,并在File name 里设置约束文件的名称,并且点击FINISH 完成约束文件的创建

2)Sources → Constraints 里找到刚才创建的约束文件 双击并打开该XDC约束文件

在约束文件里面复制下面代码来对输出的GPIO进行管脚(所有的管脚转接板上丝印都有实际标注对应的IO)

set_property IOSTANDARD LVCMOS33 [get_ports GPIO_0_0_tri_io[0]]
set_property IOSTANDARD LVCMOS33 [get_ports GPIO_0_0_tri_io[1]]

set_property PACKAGE_PIN P20 [get_ports GPIO_0_0_tri_io[0]]
set_property PACKAGE_PIN P21 [get_ports GPIO_0_0_tri_io[1]]

四、生成bit文件

1) 按下绿色箭头对工程进行编译

2)按下Generate Bitstream 完成综合以及生成bit文件

五、SDK程序编写

1)File→Export→Export hardware…,在弹出的对话框中勾选“include bitstream”,点击“OK”确认,如下图所示。

2)File→Lauch SDK,在弹出的对话框中,保存默认,点击“OK”,如下图所示。

系统将自动打开SDK开发环境

3)新建一个工程 file→new→Application Project,来新建一个“Application Project”,如下图所示。

4)在新建工程名中输入自己的工程名称,点击NEXT

5)选择空工程,点击完成FINISH

6) 在工程中添加main.c文件 src—>New—>Source File 如下图所示

7)在弹出的窗口中填入main.c 并且保存

8).打开刚才创建的main.c

然后 写入以下代码(代码是在 例程的基础上进行精简的) 有一个地方值得注意 EMIO的 IO口编号 是从54开始的,也就是我VIVADO 下创建的 EMIO端口,在PS端都是从54-55-56 依次排序的(小贴士 小于54的是MIO 也就是芯片PS的硬件IO口)

#include "xparameters.h"
#include "xgpiops.h"
#include "xstatus.h"
#include "xplatform_info.h"

#define LED1    	54
#define LED2  		55

#define GPIO_DEVICE_ID  	XPAR_XGPIOPS_0_DEVICE_ID
XGpioPs Gpio;


void Gpio_Init(void){
	XGpioPs_Config *ConfigPtr;

	ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
	XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);

	XGpioPs_SetDirectionPin(&Gpio, LED1, 1);
	XGpioPs_SetOutputEnablePin(&Gpio, LED1, 1);

	XGpioPs_SetDirectionPin(&Gpio, LED2, 1);
	XGpioPs_SetOutputEnablePin(&Gpio, LED2, 1);

	XGpioPs_WritePin(&Gpio, LED1, 0);
	XGpioPs_WritePin(&Gpio, LED2, 0);
}


#define LED_DELAY     10000000
volatile int Delay;

int main(void)
{
	Gpio_Init();

	while(1){

		XGpioPs_WritePin(&Gpio, LED1, 0);
		XGpioPs_WritePin(&Gpio, LED2, 1);
		
		for (Delay = 0; Delay < LED_DELAY; Delay++);

		XGpioPs_WritePin(&Gpio, LED1, 1);
		XGpioPs_WritePin(&Gpio, LED2, 0);

		for (Delay = 0; Delay < LED_DELAY; Delay++);

	};

	return 0;
}

六、下载到板子上进行验证

选中工程中的硬件平台,并点击右键→Program FPGA,在弹出的对话框中选择默认,点击“program”,完成FPGA PL部分的Program工作

2)选中我们生成的GPIO工程 展开绿色箭头(RUN)右边的图标,选择Run As→1 Launch on Hardware(System Debugger)

可以看到板子上的LED1灯在闪烁

备注 :如果 RUN 的时候弹出错误 可以按照下面的操作 进行设置 再进行DEBUG

之后点 APPLY 然后 再选择Run As→1 Launch on Hardware(System Debugger)看是否下载成功(如果仍然不行,请对板子进行断电后重试,一般发生这种问题的原因是因为debug的时候跟之前运行的程序产生冲突导致的)

七、代码解读

#define LED1 54 定义LED 1为 PS的第54脚(即EMIO第0脚)
#define LED2 55 定义LED 2为 PS的第55脚(即EMIO第1脚)

备注(EMIO 是从第54脚开始的)

XGpio_SetDataDirection 设置GPIO为输入/输出
XGpioPs_SetOutputEnablePin(&Gpio, LED, 1);//使能 LED 对应的GPIO的输出功能
XGpioPs_WritePin(&Gpio, LED, 0); //拉低 LED 对应的GPIO
XGpioPs_WritePin(&Gpio, LED, 1); //拉高 LED 对应的GPIO

for (Delay = 0; Delay < LED_DELAY; Delay++); 这是一个耗费系统资源的delay函数的简写

所以整个程序的效果就是两个LED  不停的交错闪烁,反复循环。 

八、 调用SDK示例DEMO介绍

其实SDK中几乎所有的硬件资源都有样例DEMO程序的,包括我们的GPIO 也有DEMO,你只需要点mss文件,并在右侧找到对应的资源,点选import Examples ,就能找到SDK官方留下的demo了。有很多DEMO都是直接可以使用的。


其实不管是 EMIO方式 还是AXI GPIO的方式 ,或者参考设计的 代码 或者我精简的代码 都是大同小异的,只要知道自己想实现什么功能,再去有针对性的研究参考设计的代码,都能写出自己想要的功能

另外赋上 下面地址是自己之前整理的MIO EMIO AXIGPIO 三者的区别,有兴趣的可以看一下zynq 中EMIO MIO AXIGPIO区别

  • 本文的完整工程下载:01_PS_LED_TEST_EMIO
  • VIVADO的版本:2018.3
  • 工程适用主板: Smart ZYNQ (SP / SP2 / SL) (不适用于Smart ZYNQ 标准版 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注