ZYNQ学习之路2. GPIO的使用

匿名 (未验证) 提交于 2019-12-03 00:19:01

ZYNQ7000中,GPIO的使用可以分为三种,即MIO、EMIO以及GPIO IP方式。其中MIO和EMIO方式是使用PS部分的GPIO硬件模块来实现GPIO功能,由于MIO是直接连接在硬核A9之上,它们可以输出三态(处理MIO7, MIO8外),并且支持IO复用,MIO共54个,引脚固定,大部分MIO用来作为外设(如ethernet, usb, qspi等)的引脚,因此MIO是比较稀缺的资源;相比之下EMIO则比较多,共64个,MIO与EMIO在硬件中按顺序编号,MIO为0~53, EMIO为54~117。GPIO IP方式则与前面两方式不同,IP方式占用PL资源,PS通过AXI总线来访问PL的IP核,从而实现GPIO功能,这个方式最大的优点是引脚资源多,PL部分有多少引脚能使用就有多少GPIO。

ZYNQ最小Linux系统硬件设计

MIO的使用

开发板的原理图,PS端MIO0和MIO9连接在LED上,因此只使用这两个IIO进行试验。在之前的模板工程基础上进行开发,双击ZYNQ7 IP, 选择Peripheral I/O Pins,勾选GPIO MIO的0号和9号,在最小系统中没有使用的IO只有0, 7~15(使用的是QSPI Flash)。

编译->综合->生成bit流->导出硬件到SDK,在Xilinx SDK软件中,在原来的test工程(以Hello world为模板的工程,未修改)中添加MIO的配置文件

#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "xgpiops.h" #include "sleep.h" //此宏定义对应于MIO的编号 #define LED1	0 #define LED2	9  XGpioPs gpio_mio;  int MIO_Config(void); void MIO_LED(int led, int status);  int main() {      init_platform();      xil_printf("test for GPIO MIO\n\r");     MIO_Config();      while(1)     {     	MIO_LED(LED1, 0);     	MIO_LED(LED2, 1);     	sleep(1);     	MIO_LED(LED1, 1);     	MIO_LED(LED2, 0);     	sleep(1);     }      cleanup_platform();     return 0; }  int MIO_Config(void) { 	XGpioPs_Config *gpioPtr;  	int status; 	//每个外设都有一个ID,GPIO的ID在xparameters.h中定义 	gpioPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID); 	status = XGpioPs_CfgInitialize(&gpio_mio, gpioPtr, gpioPtr->BaseAddr); 	if(status != XST_SUCCESS) 	{ 		xil_printf("can't config gpio\n\r"); 		return XST_FAILURE; 	} 	//配置GPIO为输出模式 	XGpioPs_SetDirectionPin(&gpio_mio, LED1, 1); 	XGpioPs_SetDirectionPin(&gpio_mio, LED2, 1); 	//使能输出 	XGpioPs_SetOutputEnablePin(&gpio_mio, LED1, 1); 	XGpioPs_SetOutputEnablePin(&gpio_mio, LED2, 1); 	return XST_SUCCESS; }  void MIO_LED(int led, int status) { 	//写GPIO的输出值 	XGpioPs_WritePin(&gpio_mio, led, status); }

编译运行在终端打印了"test for GPIO MIO",开发板上的两个绿色LED交替闪烁,间隔为1秒。


二. EMIO的使用

三色LED连接的是PL端的IO,因此使用三个EMIO来点亮三色LED。

2.1 在ZYNQ7 IP核配置中,选择Peripheral I/O Pins, 勾选GPIO EMIO, 在MIO Configuration中选择GPIO->EMIO GPIO(width),选择位宽为3

2.2 编译,综合工程,打开引脚配置界面,配置EMIO的三个引脚对应为三色LED


bit流文件,导出硬件设计,开始编写EMIO的驱动。

2.3 新建一个应用程序,仍然以hello world为模板,但不重新生成bsp工程,添加以下程序

#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "xgpiops.h" #include "sleep.h" //此宏定义对应于EMIO的编号 #define LEDR	54 #define LEDG	55 #define LEDB	56 #define LED_ON	0 #define LED_OFF 1  XGpioPs gpio_emio;  int EMIO_Config(void); void EMIO_LED(int led, int status);  int main() {     init_platform();      xil_printf("test for GPIO EMIO\n\r");     EMIO_Config();      while(1)     {     	EMIO_LED(LEDR, 0);     	EMIO_LED(LEDG, 1);     	EMIO_LED(LEDB, 1);     	sleep(1);     	EMIO_LED(LEDR, 1); 		EMIO_LED(LEDG, 0); 		EMIO_LED(LEDB, 1);     	sleep(1);     	EMIO_LED(LEDR, 1); 		EMIO_LED(LEDG, 1); 		EMIO_LED(LEDB, 0); 		sleep(1);     }      cleanup_platform();     return 0; }  int EMIO_Config(void) { 	XGpioPs_Config *gpioPtr;  	int status; 	//每个外设都有一个ID,GPIO的ID在xparameters.h中定义 	gpioPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID); 	status = XGpioPs_CfgInitialize(&gpio_emio, gpioPtr, gpioPtr->BaseAddr); 	if(status != XST_SUCCESS) 	{ 		xil_printf("can't config gpio\n\r"); 		return XST_FAILURE; 	} 	//配置GPIO为输出模式 	XGpioPs_SetDirectionPin(&gpio_emio, LEDR, 1); 	XGpioPs_SetDirectionPin(&gpio_emio, LEDG, 1); 	XGpioPs_SetDirectionPin(&gpio_emio, LEDB, 1); 	//使能输出 	XGpioPs_SetOutputEnablePin(&gpio_emio, LEDR, 1); 	XGpioPs_SetOutputEnablePin(&gpio_emio, LEDG, 1); 	XGpioPs_SetOutputEnablePin(&gpio_emio, LEDB, 1); 	return XST_SUCCESS; }  void EMIO_LED(int led, int status) { 	//写GPIO的输出值 	XGpioPs_WritePin(&gpio_emio, led, status); }

重新下载bit流文件,运行应用程序,可以看到三色灯按红->绿->蓝顺序循环闪烁。

对比MIO的工程可以发现,两个工程的驱动配置几乎一模一样,唯一需要注意的是使用EMIO时GPIO的编号从54开始,54对应EMIO的0号,依次类推。


三. AXI GPIO IP的使用

3.1 取消之前的EMIO,然后配置GP0端口,PS-PL Configuration->AXI Non Secure Enablement->GP Master AXI Interface, 勾选GP0,注意不要勾选成了GP Slave的端口。

3.2 在原理图中添加AXI GPIO的IP,自动连接信号线


3.3双击axi_gpio_0,配置GPIO为3bit,全部设置为输出模式


3.4 编译综合,配置gpio_led的引脚为三色LED对应的引脚,然后在SDK中设计软件驱动

3.5 新建一个应用程序,以Hello world为模板,编写AXI GPIO驱动代码如下:

#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "sleep.h" #include "xgpio.h"  #define AXI_GPIO_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID  #define LEDR	1 #define LEDG	2 #define LEDB	4 #define LED_ON	1 #define LED_OFF 0  XGpio gpio;  int AXIGPIO_Config(void); void AXIGPIO_LED(int led, int status);  int main() {     init_platform();      print("AXI GPIO test!\n\r");     AXIGPIO_Config();     while(1)     {     	AXIGPIO_LED(LEDR, LED_ON);     	AXIGPIO_LED(LEDG, LED_OFF);     	AXIGPIO_LED(LEDB, LED_OFF); 		sleep(1); 		AXIGPIO_LED(LEDR, LED_OFF); 		AXIGPIO_LED(LEDG, LED_ON); 		AXIGPIO_LED(LEDB, LED_OFF); 		sleep(1); 		AXIGPIO_LED(LEDR, LED_OFF); 		AXIGPIO_LED(LEDG, LED_OFF); 		AXIGPIO_LED(LEDB, LED_ON); 		sleep(1);     }     cleanup_platform();     return 0; }  int AXIGPIO_Config(void) { 	XGpio_Config *XGpioCfg; 	int status; 	XGpioCfg = XGpio_LookupConfig(AXI_GPIO_DEVICE_ID); 	status = XGpio_CfgInitialize(&gpio, XGpioCfg, XGpioCfg->BaseAddress); 	if(status != XST_SUCCESS){ 		print("can't config axi gpio\n\r"); 		return XST_FAILURE; 	} 	//设置IO方向为输出 	XGpio_SetDataDirection(&gpio, 1, ~(LEDR | LEDG | LEDB)); 	//初始写1 	XGpio_DiscreteWrite(&gpio, 1, LEDR | LEDG | LEDB); 	return XST_SUCCESS; }  void AXIGPIO_LED(int led, int status) { 	u32 temp; 	temp = XGpio_DiscreteRead(&gpio, 1); 	if(status) 		XGpio_DiscreteWrite(&gpio, 1, temp & (~led)); 	else XGpio_DiscreteWrite(&gpio, 1, temp | led); }

下载bit流文件,运行应用程序,则与EMIO工程表现出一样的效果。


四. 总结

介绍了ZYNQ的三种GPIO的使用方法,各有各的优点,下表列出了它们的却别对别:

ZYNQ GPIO三种方式比较
GPIO方式
MIOEMIOAXI GPIO
硬件实现方式硬核资源硬核资源
引脚
功能输入,输出,三态
驱动库函数xgpiops.hxgpiops.hxgpio.h
BANK区BANK0,1BANK2,3PL
特点
使用PL的引脚PS的硬件


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!