ZYNQ学习:GPIO、MIO、EMIO的区别

来源:FPGA难得一P(CSDN)

芯片型号:XC7Z010-1CLG400C

Vivado版本:2016.1

点亮流水灯,共使用了三种方式:
(1)PS通过MIO点亮PS端LED
(2)PS通过EMIO点亮PL端LED
(3)PS通过AXI点亮PL端LED。

1. MIO与EMIO

首先来理清楚MIO与EMIO的关系。MIO是PS的I/O引脚,一共有54个,分为Bank0与Bank1,可以接许多外设比如UART、SPI或GPIO等,另外可以引脚复用。当我们想通过PS来访问PL又不想浪费AXI总线时,就通过EMIO接口来访问。在54个I/O中,有一些只能用于MIO,大部分可以用于MIO与EMIO,一些接口信号线只能通过EMIO访问。


EMIO依然属于PS,只是连接到了PL,再从PL输出信号。

2. PS通过MIO点亮PS端LED


从电路中看得很清楚,这两个LED直接连接在MIO0和MIO13上,所以直接在这两个端口输出高低电平就可以控制灯闪烁了。

首先建立.bd文件,添加zynq的ip核,去掉PL的资源(包括PS-PL configuration——general——Enable Clock Resets中的FCLK_RESET0_N以及AXI None Secure Enablement——GP Master AXI Interface中的GP0以及Clock Configuration——PL Fabric Clocks中的FCLK_CLK0)。

在外设I/O中,打开UART1,对应MIO48、49口,打不打开都无所谓,打开调试用。此时在MIO中已经看到UART1已经分配了管脚,然后在GPIO里,打开MIO。


最后在DDR里,找到所用的DDR芯片,比如我用的是HA-125。这样所有的平台就搭好了。直接generate out products——create HDL wrapper——export Hardware——lanuch SDK。

进入SDK,建立工程。首先引头文件xgpiops.h

对MIO0和MIO13,初始化引脚。

s32 XGpioPs_CfgInitialize(XGpioPs *InstancePtr, XGpioPs_Config *ConfigPtr,
			   u32 EffectiveAddr);

这个函数初始化gpio,第一个参数需要一个XGpioPs的结构体指针,直接在函数开头实例化就好了,结构体的组成在.h文件。第二个参数是一个XGpioPs_Config类型结构体指针,这个结构体的内容:

typedef struct {
	u16 DeviceId;		/**< Unique ID of device */
	u32 BaseAddr;		/**< Register base address */
} XGpioPs_Config;

包括gpio分配的ID和基地址。第三个参数就是基地址。

如何获得这些信息,首先ID的获得,打开xparameter.h头文件,里面定义了分配的各种资源的ID。

基地址就在配置信息查了,如何获得gpio的配置信息:

首先实例化一个XGpioPs_Config类型的指针。使用XGpioPs_LookupConfig函数,它能够在配置信息中找到对应ID的配置信息:

所以就很明确了:

xgpio_config = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);//找分配的MIO配置信息(基地址)
status = XGpioPs_CfgInitialize(&xgpio, xgpio_config,xgpio_config->BaseAddr);//初始化
 
if(status!=XST_SUCCESS)//初始化成功
return XST_FAILURE;

然后就是定义gpio口的属性,包括输入输出和端口使能:

XGpioPs_SetDirectionPin(&xgpio, LED1, 1);//output
XGpioPs_SetDirectionPin(&xgpio, LED2, 1);//
 
XGpioPs_SetOutputEnablePin(&xgpio, LED1, 1);//enable
XGpioPs_SetOutputEnablePin(&xgpio, LED2, 1);

再后面就在while(1)中循环点灯,用XGpioPs_WritePin函数输出高低电平。

这是纯PS点流水灯。

3. PS通过EMIO点亮PL端LED

通过EMIO点PL端LED,在配置zynq ip核时,基本步骤差不多,包括去到PL资源等,唯一不同的是,在GPIO里,勾上EMIO并且分配宽度是4(因为我的小板子PL端有四个LED)。

生成了新的系统:


接下来,分配管脚!!因为这里GPIO_0在PL端。看看pdf:


把刚分配的带宽4的EMIO(GPIO_0)绑定到这四个管脚上。

然后输出bitstream文件,导入到SDK中时,要加上这个比特流文件。进入SDK

初始化程序还是一样,头文件也是xgpiops.h,这还是PS操作。

xgpio_config = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
status = XGpioPs_CfgInitialize(&xgpio, xgpio_config,
    			   xgpio_config->BaseAddr);
if(status!=XST_SUCCESS)
return XST_FAILURE;

后面就是设置引脚工作模式:

这里的引脚号从54开始,因为从54后才是EMIO引脚:


0—53是MIO,53—...是EMIO。

之后点灯就可以了。在运行之前先下载比特流文件到FPGA,另外这个黑金的小板子,PL和PS协同仿真时,总报错,只需要在Reset entire system和Program FPGA打上勾,并且这个比特流文件要绝对地址!!


4. PS通过AXI点亮PL端LED

这个就是PL与PS协同点灯了。

首先配置zynq ip核,PL部分保留,因为用到了AXI,另外MIO gpio都去掉。其余配置都一样。添加AXI gpio IP核,并且设置宽度为4,最后Run connection Automation,加入其它必要组件,调整连线:


之后再绑定gpio_led管脚到四个LED上,综合并生成bitstream文件,导入到SDK。

引用头文件:XGpio.h

然后还是对引脚进行初始化和设置工作模式:

XGpio_Initialize(&GpioOutput, XPAR_AXI_GPIO_0_DEVICE_ID);
XGpio_SetDataDirection(&GpioOutput,1,0x0);//output
XGpio_DiscreteWrite(&GpioOutput,1,0x0);

协同点灯还是要先下载比特流文件,在运行SDK程序。

5. 总结

① 对MIO或EMIO gpio进行操作,都属于PS,引用xgpiops.h文件,对AXI_gpio引用xgpio.h

② 涉及PL引脚或操作时,生成比特流文件并且导入SDK,运行时先下载FPGA。

③ PL输出信号绑定引脚。

版权声明:本文为CSDN博主「FPGA难得一P」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/v13910/article/details/83504327

推荐阅读