MiZ702学习笔记5——EMIO使用详解

上次讲到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文件。

我们从添加ZYNQ的IP开始讲,这次添加一个配置更加简洁的ZYNQ IP:

添加了zynq IP之后,点击Run Block Automation,将DDR等引脚引出:

还是双击点击进入从新配置,选择Default:

再将EMIO引出8个引脚(最多能引出64个),引出的引脚都是按bank2到bank3顺序排列的,也就是说53个MIO之后,我们引出的这8个EMIO,分别是54~61号引脚,之后会在程序中体现。

PL的输出时钟,也勾选掉不要:

我们,没有用到AXI总线,这个也勾选掉不要:

OK,完成ZYNQ核的配置.

右击GPIO_0引脚部分,选择make external把GPIO_0引脚引出,

依然是,右键单击Block,文件选择Generate the output products,是文件得到一定的约束:

继续右键单击Block,文件选择Create a HDL wrapper,创建一个HDL 的顶层文件:


这里我们得去瞧瞧,Vivado到底给我创建了这样的顶层:

我们发现,之前引出的EMIO——GPIO_0,到了顶层他的名字叫gpio_0_tri_io,而不是GPIO_0。所以分配引脚的时候就要注意了名字别错了,

创建一个约束文件,分配引脚如下:

set_property PACKAGE_PIN T22 [get_ports {gpio_0_tri_io[0]}]

set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[0]}]

set_property PACKAGE_PIN T21 [get_ports {gpio_0_tri_io[1]}]

set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[1]}]

set_property PACKAGE_PIN U22 [get_ports {gpio_0_tri_io[2]}]

set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[2]}]

set_property PACKAGE_PIN U21 [get_ports {gpio_0_tri_io[3]}]

set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[3]}]

set_property PACKAGE_PIN V22 [get_ports {gpio_0_tri_io[4]}]

set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[4]}]

set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[5]}]

set_property PACKAGE_PIN W22 [get_ports {gpio_0_tri_io[5]}]

set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[6]}]

set_property PACKAGE_PIN U19 [get_ports {gpio_0_tri_io[6]}]

set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[7]}]

set_property PACKAGE_PIN U14 [get_ports {gpio_0_tri_io[7]}]

可以,开始生成bit文件了:

编译成功之后,依然是导出硬件,打开SDK,然后新建一个工程,以及添加一个main.C文件,具体过程参加上一篇笔记。

添加程序如下:

#include

#include "xgpiops.h"

#include "sleep.h"

#include
#include "xgpiops.h"
#include "sleep.h"

int main()
{
static XGpioPs psGpioInstancePtr;
XGpioPs_Config* GpioConfigPtr;
int iPinNumber= 54; //54,EMIO的第一个引脚
u32 uPinDirection = 0x1; //1表示输出,0表示输入
int xStatus;

//--IO的初始化
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 \n\r");
//--IO的输入输出操作
XGpioPs_SetDirectionPin(&psGpioInstancePtr, iPinNumber,uPinDirection);//配置MIO输出方向
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, iPinNumber,1);//配置MIO的第7位输出
//--IO的段操作
XGpioPs_SetDirection(&psGpioInstancePtr,2,0xffffffff); //bank2的EMIO全部配置成输出
XGpioPs_SetOutputEnable(&psGpioInstancePtr,2,0xffffffff); //bank2的EMIO全部使能
XGpioPs_Write(&psGpioInstancePtr,2,0x50); //对整个bank2的IO进行段操作
while(1)
{
XGpioPs_WritePin(&psGpioInstancePtr, iPinNumber, 1);//点亮
sleep(1); //延时
XGpioPs_WritePin(&psGpioInstancePtr, iPinNumber, 0);//熄灭
sleep(1); //延时
}

return 0;
}

我们发现,驱动EMIO和MIO基本是一模一样的,上篇笔记中的添加的"xgpio.h"其实是多此一举,上次的程序中我们只要把

static XGpio psGpioInstancePtr;

这句替换成:

static XGpioPs psGpioInstancePtr;

"xgpio.h"其实是为系统自带的以总线的方式驱动IO的GPIO核服务的。这一点也是很容易搞错的地方。(呵呵,我之前就弄错了)GPIO核的使用也非常简单,我看看是否在下篇笔记里讲讲。

调试过程,也和上次笔记基本一样(请参考上篇笔记),不同的是,在此之前得先下载bit文件,下载文件可以直接在SDK中进行:


这次我们看看,如何在线调试,点击状态栏中的小爬虫:


最后,想说明一点,SDK的调试功能。不管是在线调试还是调试,这个不是非常好用,可能存在有时可以有时又不行(zed,和MiZ702我都试过),所以一定要确保USB线的稳定,最后插到电脑主机后面的USB,或者弄一个好点的可以单独供电的USB分线器。

扫一扫,关注FPGA开发圈微信

完成ZYNQ核的配置后我的IP设计图怎么和你的不一样?左边多了一个引脚!
然后报错ERROR: [BD 41-758] The following clock pins are not connected to a valid clock source:
/processing_system7_0/M_AXI_GP0_ACLK