ZYNQ学习之路2. GPIO的使用

        在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系统硬件设计

        下面介绍着三种方式下GPIO的具体使用。

一. 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的使用方法,各有各的优点,下表列出了它们的却别对别:

GPIO方式

MIO

EMIO

AXI GPIO

硬件实现

硬核资源

硬核资源

PL资源

引脚

PS固定引脚

PL部分引脚

PL部分引脚

功能

输入,输出,三态

输入,输出

输入,输出

驱动库函数

xgpiops.h

xgpiops.h

xgpio.h

BANK区

BANK0,1

BANK2,3

PL

特点

资源少,大部分MIO作为特殊功能

使用

占用PL的引脚

占用PL的逻辑资源


欢迎关注亦梦云烟的微信公众号: 亦梦智能计算

 

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值