前面的工程6用AXI GPIO的方式 让PS去控制PL端的LED灯(相当于 PL端需要生成AXI GPIO相应的电路,占用资源), 本文换个思路用EMIO的方式 将PL端的LED 映射到PS端的GPIO上。 该方法在项目上更常用,(对PL端的资源占用非常小,可以简单理解为PS端拉了根导线到PL端对应的IO口)除了GPIO可以EMIO映射外, SPI I2C UART 都可以用相同方式来进行映射,极大的增加了系统的可拓展性
本文在 vivado2018.3版本上 演示, 其他版本请自行研究
(备注 此章节内容适用于 EBAZ4205的转接板)
本实验将通过点亮主板上的两个LED灯(非转接板上的LED灯)来演示PS通过EMIO方式来控制PL端GPIO的功能
1创建Vivado工程
1) 具体步骤 新建一个VIVADO 工程,打开软件 选中Create Project, 如下图所示
![](http://www.hellofpga.com/wp-content/uploads/2021/07/Create-Project.png)
2)点击NEXT ,在出现的第二个对话框“Project name”中输入工程名;在“Project location”中选择保存路径;勾选“Create project subdirectory”,最后点击“Next” 备注,所有的路径均不能出现中文名称
![](http://www.hellofpga.com/wp-content/uploads/2024/02/image-6.png)
3)点击 RTL PROJECT 选项,点击NEXT
![](http://www.hellofpga.com/wp-content/uploads/2021/07/image.png)
4) 第四步Add Sources 选项直接留空,NEXT
5)第五步Add Constraints 选项直接留空,NEXT
6)选择芯片型号 我们板子上用的芯片是XC7Z010 ,并在列表栏中选择对应的封装型号,完整型号是XC7Z010CLG400-1 如下所示,选中后点NEXT
![](http://www.hellofpga.com/wp-content/uploads/2021/07/image-1.png)
7)确认所选信息 点击“Finish”,完成vivado的工程创建
![](http://www.hellofpga.com/wp-content/uploads/2023/01/image-67.png)
2 创建一个BLOCK设计
1)IP INTEGRATOR→Create Block Design,在弹出的对话框中输入设计名,最后点击“OK”,如下图所示
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-1.png)
2)在右侧的窗口里 ,点击加号,在选择框里搜索ZYNQ,并找到ZYNQ7 PROCESSING SYSTEM ,双击并打开
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-2.png)
3)软件自动生成了一个 zynq的block 如下图所示,接下来要做一些相应的设置,双击下图中的ZYNQ核
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-3.png)
4) 依次在弹窗里找到DDR Configuration→DDR Controller Configuration→DDR3,在Memory Part下拉菜单中根据自己板子上的DDR来选择相应的DDR3,本实验所用到型号:MT41K128M16JT 125,数据位宽选择16bit 最后点击“OK”,如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-5.png)
5)关键的一步 有别于第六章节的地方,在PS的MIO配置选项的GPIO栏里,增加两路EMIO(因为本次测试的是两个,如果需要增加按键或者其它IO 这里可以对应的调整)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-41.png)
6)最后 点击“Run Block Automation”如下图所示。在弹出的选项中保持默认,点击“OK”,即可完成对ZYNQ7 Processing System的配置
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-43.png)
7)将刚才添加EMIO GPIO 引出 右键GPIO_0—->Make External
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-44.png)
8)用线将M_AXI_GP0_ACLK与 FCLK_CLK0连接起来
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-47.png)
9)source→Design Source ,右键我们创建的BLOCK工程,点击create HDL wrapper如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-12.png)
在弹出的对话框里保持默认
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-13.png)
软件自动为我们生成HDL文件
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-14.png)
3.创建约束文件,并且定义管脚
1)Add Source → Add or create constraints 点Next
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-15.png)
因为这个项目没有创建过约束文件 所以这里创建一个约束文件,并在File name 里设置约束文件的名称,并且点击FINISH 完成约束文件的创建
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-16.png)
2)Sources → Constraints 里找到刚才创建的约束文件 双击并打开该XDC约束文件
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-17.png)
在约束文件里面复制下面代码来对输出的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 W13 [get_ports GPIO_0_0_tri_io[0]] set_property PACKAGE_PIN W14 [get_ports GPIO_0_0_tri_io[1]]
4.生成bit文件
按下绿色箭头对工程进行编译
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-19.png)
按下Generate Bitstream 完成综合以及生成bit文件
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-18.png)
5.SDK程序编写
1)File→Export→Export hardware…,在弹出的对话框中勾选“include bitstream”,点击“OK”确认,如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-20.png)
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-24.png)
2)File→Lauch SDK,在弹出的对话框中,保存默认,点击“OK”,如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-21.png)
系统将自动打开SDK开发环境
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-22.png)
3)新建一个工程 file→new→Application Project,来新建一个“Application Project”,如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-23.png)
4)在新建工程名中输入自己的工程名称,点击NEXT
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-37.png)
5)选择空工程,点击完成FINISH
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-26.png)
6) 在工程中添加main.c文件 src—>New—>Source File 如下图所示
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-48.png)
7)在弹出的窗口中填入main.c 并且保存
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-49.png)
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; }
6.下载到板子上进行验证
选中工程中的硬件平台,并点击右键→Program FPGA,在弹出的对话框中选择默认,点击“program”,完成FPGA PL部分的Program工作
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-42.png)
2)选中我们生成的GPIO工程 展开绿色箭头(RUN)右边的图标,选择Run As→1 Launch on Hardware(System Debugger)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-50.png)
可以看到板子(主板)上的LED(红绿灯)在闪烁,如果想改成转接板上的LED灯 只需要修改上文的管脚约束号即可
备注 :如果 RUN 的时候弹出错误 可以按照下面的操作 进行设置 再进行DEBUG
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-51.png)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-39.png)
之后点 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 不停的点亮熄灭,反复循环。
其实不管是 EMIO方式 还是AXI GPIO的方式 ,或者参考设计的 代码 或者我精简的代码 都是大同小异的,只要知道自己想实现什么功能,再去有针对性的研究参考设计的代码,都能写出自己想要的功能
另外赋上 下面地址是自己之前整理的MIO EMIO AXIGPIO 三者的区别,有兴趣的可以看一下
http://www.hellofpga.com/index.php/2021/08/08/zynq_emio_mio_axi_gpio/
本文的完整工程如下,大家自行研究: