S02_CH03_EMIO实验
3.1 EMIO 和MIO的对比介绍
上次讲到MIO的使用,初步熟悉了EDK的使用,这次就来说说EMIO的使用。如你所见zynq的GPIO,分为两种,MIO(multiuse I/O)和EMIO(extendable multiuse I/O)
MIO分配在bank0和bank1直接与PS部分相连,EMIO分配在bank2和bank3和PL部分相连。除了bank1是22-bit之外,其他的bank都是32-bit。所以MIO有53个引脚可供我们使用,而EMIO有64个引脚可供我们使用。
使用EMIO的好处就是,当MIO不够用时,PS可以通过驱动EMIO控制PL部分的引脚,接下来就来详细介绍下EMIO的使用。
EMIO的使用和MIO的使用其实是非常相似的。区别在于,EMIO的使用相当于,是一个PS + PL的结合使用的例子。所以,EMIO需要分配引脚,以及编译综合生成bit文件。
3.2 电路分析与实验现象
本节我们将使用Miz系列开发的LED,通过SDK操作EMIO来控制LED灯的流水操作。
3.3 创建VIVADO工程
Step1:新建一个名为为Miz_sys的工程,芯片类型根据自身情况设置。
Step2:创建一个BD文件,并命名为system。
Step3:添加 ZYNQ7 Processing System,根据自己的硬件类型配置好输入时钟频率与内存型号。
Step4:在MIO Configuration选项卡,再看到I/O Peripherals 中的GPIO一栏,勾选上其中的EMIO一栏,并选择4位引脚输出(最多可以选择64位,但是这个使用只需要4位足够了。)
Step5:单击OK,仔细观察发现的zynq核心多出一组引脚名为GPIO_0,这个正是我们刚刚设置的一组EMIO,我们右击该引脚,选择make external把GPIO_0引脚引出(或者单击该引脚处,按快捷键Ctrl +t,也可以将引脚引出)。效果如下图所示:
Step6:单击GPIO_0,将其修改为EMIO_0,如下图所示:
Step7:接着,将如下两引脚连接起来,其实就是给M_AXI_GP0_ACLK提供一个时钟。
Step8:右键单击Block文件,文件选择Generate the Output Products。
Step9:单击Block文件,选择Create a HDL wrapper,根据Block文件内容产生一个HDL 的顶层文件,并选择让vivado自动完成。
3.4 创建约束文件
根据自身的硬件,对芯片的引脚进行分配,首先打开我们提供的原理图文件,此处以Miz702开发板为例,Miz702的LED部分原理图如下所示:
此处我们选择LD1-LD4分配给EMIO。
Step1:选中Project manager,然后右单击Constraints,选择Add Sources。
Step2:输入文件名,完成创建,将以下约束文件加入约束文件当中。
set_property PACKAGE_PIN T22 [get_ports {emio_0_tri_io[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {emio_0_tri_io[0]}] set_property PACKAGE_PIN T21 [get_ports {emio_0_tri_io[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {emio_0_tri_io[1]}] set_property PACKAGE_PIN U22 [get_ports {emio_0_tri_io[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {emio_0_tri_io[2]}] set_property PACKAGE_PIN U21 [get_ports {emio_0_tri_io[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {emio_0_tri_io[3]}] |
其他型号的用户,可同理查阅原理图或根据型号打开我们提供的源程序的约束文件对系统引脚进行分配。
3.5 产生bit文件并导入到SDK中
Step1:生成bit文件。
Step2:导出到硬件。
Step3:打开SDK,单击File-New-Application project。
Step4:输入工程名字,此处命名为MIO_Test,单击Next。
Step5:选择Empty Application,创建一个空的工程,单击Finish完成创建。
Step6:单击工程名字右边的三角形按钮,然后右单击src,选择New-source file。
Step7:输入一个文件名,此处命名为main.c,单击Finish按钮完成C文件的添加。
Step8:在main.c中添加程序如下:
#include "xgpiops.h" #include "sleep.h" int main() { static XGpioPs psGpioInstancePtr; XGpioPs_Config* GpioConfigPtr; int xStatus; //-- EMIO的初始化 GpioConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID); if(GpioConfigPtr == NULL) return XST_FAILURE; xStatus = XGpioPs_CfgInitialize(&psGpioInstancePtr,GpioConfigPtr, GpioConfigPtr->BaseAddr); if(XST_SUCCESS != xStatus) print(" PS GPIO INIT FAILED "); //--EMIO的输入输出操作 XGpioPs_SetDirectionPin(&psGpioInstancePtr, 54,1); XGpioPs_SetDirectionPin(&psGpioInstancePtr, 55,1); XGpioPs_SetDirectionPin(&psGpioInstancePtr, 56,1); XGpioPs_SetDirectionPin(&psGpioInstancePtr, 57,1); //使能EMIO输出 XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 54,1); XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 55,1); XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 56,1); XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, 57,1); while(1) { XGpioPs_WritePin(&psGpioInstancePtr, 54, 1);//EMIO的第0位输出1 usleep(200000); //延时 XGpioPs_WritePin(&psGpioInstancePtr, 54, 0);//EMIO的第0位输出0 usleep(200000); //延时 XGpioPs_WritePin(&psGpioInstancePtr, 55, 1);//EMIO的第1位输出1 usleep(200000); //延时 XGpioPs_WritePin(&psGpioInstancePtr, 55, 0);//EMIO的第1位输出0 usleep(200000); //延时 XGpioPs_WritePin(&psGpioInstancePtr, 56, 1);//EMIO的第2位输出1 usleep(200000); //延时 XGpioPs_WritePin(&psGpioInstancePtr, 56, 0);//EMIO的第2位输出0 usleep(200000); //延时 XGpioPs_WritePin(&psGpioInstancePtr, 57, 1);//EMIO的第3位输出1 usleep(200000); //延时 XGpioPs_WritePin(&psGpioInstancePtr, 57, 0);//EMIO的第3位输出0 usleep(200000); //延时 } return 0; } |
Step9:右击工程,选择Debug as ->Debug configuration。
Step10:选中system Debugger,双击创建一个系统调试。
Step11:设置系统调试。
Step12:单击窗口上的运行按钮,运行程序,可看到LED的流水操作。
3.6 程序分析
本章程序与第二章MIO基本上是一模一样的,如果还有不懂得地方请返回去查看第二章程序的分析,这里不再重复的讲解。这里需要注意的是本章程序中为什么要定义成54开头呢?答案如下图所示:
因为MIO和EMIO是同一编号的MIO共54个,从0~53。而从54开始就开始是EMIO了的范围了。之前我们应出了4个引脚emio_0_tri_io[0]~emio_0_tri_io[3],他们其实就依次对应54~57这几个序号,同时也对应了我们开发板上的4个LED(这是引脚约束的结果)。
3.7 本章小结
通过本章的学习,我们掌握了在MIO不够使用的情况下,通过PL部分扩展EMIO增加IO的使用量。并且通过一个简单的例子演示了如何添加EMIO IP 并且启动SDK 通过JTAG下载调试的方法。