ZYNQ-利用PS引脚实现EMIO GPIO的驱动

本文详细介绍了在Vivado 18.3和pynq-z2开发板上,如何使用SDK和API初始化GPIO,配置EMIO驱动LED灯和按钮,实现LED呼吸灯效果,并通过串口读取按钮输入。涉及硬件平台搭建、寄存器配置、EMIO与MIO的区别以及SDK编程示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习内容

使用SDK和提供的API进行初始化GPIO,并驱动led和btn进行操作,实现led呼吸灯效果,串口读取btn的值。

开发环境

vivado 18.3 && SDK
开发板 pynq-z2

原理讲解

  • gpio可以看做一个外设,用于对器件的引脚作观测(input)以及控制(output)
  • MIO 是将PS的外设和静态存储器接口的访问多路复用到PS的引脚上。
  • 当我们的PS端的MIO不够用时候,我们可以在搭建硬件平台时候进行设计,将我们的PL端口的引脚定义拓展为EMIO然后被PS正常驱动。
  • gpio 被分为了4个bank bank0和bank1通过MIO连接到PS的引脚,bank2和bank3通过EMIO连接到PL
    在这里插入图片描述
    这里给出GPIO的一个寄存器的结构图,方便我们从底层更加深入了解gpio的具体配置的一个状态
    在这里插入图片描述
    图片的上半部分表示的是和IO的中断功能有关的寄存器,本节主要关注下面的部分。
    通过阅读UG585,我们可以知道寄存器组的不同功能:
  • DATA_RO:用来反映引脚的功能状态
  • DATA:当GPIO信号被配置为输出时,这个寄存器控制要输出的值。该寄存器的所有32位同时写入。
  • MASK_DATA_LSW: 用于屏蔽DATA的低16位
  • MASK_DATA_MSW: 用于屏蔽DATA的高16位
  • DIRM:用于控制IO引脚作为输入还是输出。0关闭输出驱动,1打开输出驱动
  • OEN:当IO配置为输出时,用于控制打开或者关闭输出使能。0关闭使能,1进行使能

硬件平台搭建

同样和前面相似,我们先添加IP ZYNQ7,然后进行IP配置,选中uart sd gpio
在这里插入图片描述
EMIO的 gpio
在这里插入图片描述

APB AP transaction error, DAP status f0000021 问题解决方法

我们可以简单的理解为zynq这个芯片是由这样几部分组成,ddr区,PS区,PL区。DDR区是存储区,包括我们的芯片运行SDK的程序时候也是下载到这里。所以在我们没有对应我们的板子配置好DDR时,会碰到这个错误信息 “APB AP transaction error, DAP status f0000021” 这也是可以定位到我们在配置ddr信息时候没有和开发板匹配,这里我进行操作的时候,我是添加了对应的板卡信息,ddr自动连线的时候会有一个加载预配置。
pynq板卡信息会自动帮你配置ddr的信息,这里我贴出pynqz2的ddr的具体信息,需要更改的地方我会标记指出:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

EMIO和MIO的区别

前面提到了zynq7000的大致划区,在ps区,也就是我们的arm核这里,一般都是引出了54个管脚进行开发,也就是我们在ZYNQ7的ip里在MIO config的可以配置的那些,这就是MIO我们可以针对这54个管脚进行配置自己想要的功能,一般不同的板卡会对应设计SD UART USB GPIO接口什么的,方便用户进行PS端的单独调试学习,那么,对于FPGA的PL端的引脚我们可以不可以进行PS操作调用呢?答案是肯定的!这就提到了EMIO的概念 EMIO的E就是 external的意思,也就是我们可以管脚定义了FPGA端的管脚进行扩展给PS端进行操作。
配置完成后如图:
在这里插入图片描述
然后我们可以输出生成顶层文件了
在这里插入图片描述
因为这里是用的EMIO,我们不能忘记新建约束文件进行管脚分配:


set_property -dict { PACKAGE_PIN R14   IOSTANDARD LVCMOS33 } [get_ports { GPIO0_tri_io[0] }]; #IO_L6N_T0_VREF_34 Sch=led[0]
set_property -dict { PACKAGE_PIN P14   IOSTANDARD LVCMOS33 } [get_ports { GPIO0_tri_io[1] }]; #IO_L4P_T0_35 Sch=btn[0]
set_property -dict { PACKAGE_PIN D20   IOSTANDARD LVCMOS33 } [get_ports { GPIO0_tri_io[2] }]; #IO_L4N_T0_35 Sch=btn[1]

最后综合生成bit流,导出硬件,launch SDK

SDK软件部分

运行SDK新建helloworld工程(不再多说,看前文),这里贴出SDK的main代码:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xgpiops.h"
#include "xparameters.h"

#define GPIO_ID XPAR_PS7_GPIO_0_DEVICE_ID
#define LED0 54
#define BTN0 55
#define BTN1 56
static XGpioPs GpioPs;
static XGpioPs_Config *XGpioPs_Cfg;
int initGpio();
int main()
{
	u32 led = 0;
	int i,j;
	init_platform();
    initGpio();
    while(1){

    	for(i=0;i<1000;i++){
    		for(j=0;j<1000;j++){
    			usleep(1);
    			if(i<j){
    				XGpioPs_WritePin(&GpioPs,LED0,led);
    			}
    			else{
    				XGpioPs_WritePin(&GpioPs,LED0,~led);
    			}
    		}
    	}
    	led=~led;
    	printf("btn0 :%d btn1 :%d \n",XGpioPs_ReadPin(&GpioPs,BTN0),XGpioPs_ReadPin(&GpioPs,BTN1));



    }
    print("Hello World\n\r");

    cleanup_platform();
    return 0;
}
int initGpio(){
	int status;
	XGpioPs_Cfg = XGpioPs_LookupConfig(GPIO_ID);
	status = XGpioPs_CfgInitialize(&GpioPs,XGpioPs_Cfg,XGpioPs_Cfg->BaseAddr);
	if( status != XST_SUCCESS){
		return XST_FAILURE;
	}
	XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01);
	XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01);
	XGpioPs_SetDirectionPin(&GpioPs,BTN0,0x00);
	XGpioPs_SetOutputEnablePin(&GpioPs,BTN0,0x00);
	XGpioPs_SetDirectionPin(&GpioPs,BTN1,0x00);
	XGpioPs_SetOutputEnablePin(&GpioPs,BTN1,0x00);
}

部分代码解释

#include "xgpiops.h"
#include "xparameters.h"

#define GPIO_ID XPAR_PS7_GPIO_0_DEVICE_ID
#define LED0 54
#define BTN0 55
#define BTN1 56

这里的XPAR_PS7_GPIO_0_DEVICE_ID可以在 “xparameters.h” 寻到,对于LED0 BTN0 BTN1的定义,正是因为前文提到的EMIO的概念,直接PS课操作的管脚54个,是从MIO 0 – MIO 53
所以这里的EMIO的扩展引脚编号就是54往后,从GPIO0_tri_io 0 依次往后进行编号,也可以理解为管脚号。

int initGpio(){
	int status;
	XGpioPs_Cfg = XGpioPs_LookupConfig(GPIO_ID);
	status = XGpioPs_CfgInitialize(&GpioPs,XGpioPs_Cfg,XGpioPs_Cfg->BaseAddr);
	if( status != XST_SUCCESS){
		return XST_FAILURE;
	}
	XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01);
	XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01);
	XGpioPs_SetDirectionPin(&GpioPs,BTN0,0x00);
	XGpioPs_SetOutputEnablePin(&GpioPs,BTN0,0x00);
	XGpioPs_SetDirectionPin(&GpioPs,BTN1,0x00);
	XGpioPs_SetOutputEnablePin(&GpioPs,BTN1,0x00);
}

初始化函数同前文iic的配置,和keil开发32的流程类似,声明结构体进行初始化,然后设置GPIO的方向,输入还是输出模式。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FPGA and ICer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值