版本:Vivado2020.2(Vitis)
任务:使用GPIO MIO 和 EMIO 实现按键 KEY 控制 LED( 两个PL端LED、两个PS端KEY)
目录
一、MIO 、EMIO 介绍
特性 | MIO | EMIO |
---|---|---|
位置 | PS端直接控制,不占用PL资源 | 通过PL扩展,占用FPGA逻辑和引脚 |
数量 | 固定(如Zynq-7000有54个) | 灵活,取决于PL可用引脚 |
延迟 | 低(直接由PS控制) | 较高(需通过PL路由) |
用途 | 标准外设(UART、I2C、SPI等) | 扩展外设、自定义接口、PS-PL交互 |
配置方式 | Vivado Zynq配置界面直接分配 | 需在PL中连接信号到引脚 |
二、硬件设计
(1)ZYNQ 其他配置不赘述,本次用到了UART(用作debug)、MIO、EMIO。配置如下:注意Bank0、1分别设置3.3V和1.8V,根据原理图进行设置,图二为原理图。
两个PL端LED用了两个EMIO管脚,设置EMIO位宽为2。
(2)最后整体 bd 设计部分如图所示:设计检查、Generate Output Products、 Create HDL Wrapper、管脚约束、Gnerate Bitstream、Export Hardware(包含比特流文件)、启动 Vitis。
约束管脚是对PL端进行管脚分配,PS端的管脚是固定的不用分配引脚,其编号需查看开发板手册或原理图,可直接在Vitis中软件定义。此外注意PL端的GPIO_0管脚在软件中编号54,GPIO_1对应编号55,(ZYNQ7000为例,MIO54个固定管脚占用0到53共54个编号,EMIO管脚低位开始从54依次编号)
三、软件设计
#include "stdio.h"
#include "xparameters.h"
#include "xil_printf.h"
#include "xgpiops.h"
#include "sleep.h"
//===========================自定义宏===========================//
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID //宏定义器件ID(GPIO_DEVICE_ID为简化名)
#define MIO_KEY0 50 //宏定义KEY管脚(PS端KEY,根据开发板设值,这里对应GPIO MIO 50)
#define MIO_KEY1 51 //宏定义KEY管脚(PS端KEY,根据开发板设值,这里对应GPIO MIO 51)
#define EMIO_LED0 54 //宏定义LED管脚(PL端LED,根据EMIO管脚分配设值,这里对应GPIO 54)
#define EMIO_LED1 55 //宏定义LED管脚(PL端LED,根据EMIO管脚分配设值,这里对应GPIO 55)
//===========================实例化===========================//
XGpioPs Gpio; //定义GPIO引脚(实例化)
//===========================函数、变量声明===========================//
static void Gpio_Init(); //GPIO初始化(包括MIO和EMIO)
static void LED_blink(); //LED闪烁
//===========================主函数===========================//
int main()
{
u32 key0_value;
u32 key1_value;
print("GPIO MIO EMIO TEST! \r\n");
Gpio_Init(); //GPIO初始化
LED_blink(); //LED闪烁测试
LED_blink();
while(1)
{
//从GPIO引脚读数据(PS端KEY0、1)
key0_value = XGpioPs_ReadPin(&Gpio, MIO_KEY0);
key1_value = XGpioPs_ReadPin(&Gpio, MIO_KEY1);
//写数据到GPIO引脚(PL端LED0、1)
XGpioPs_WritePin(&Gpio, EMIO_LED0, key0_value);
XGpioPs_WritePin(&Gpio, EMIO_LED1, key1_value);
}
return 0;
}
//===========================GPIO初始化===========================//
void Gpio_Init()
{
int Status;
//定义器件ID(指针类型)
XGpioPs_Config * ConfigPtr;
//根据器件ID,查找器件配置信息
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
//初始化GPIO的驱动(如果失败串口打印报错,函数如有状态返回值,都可以进行debug,这里举一个例子)
Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
print("XGpioPs_CfgInitialize Failed\r\n");
}
//GPIO方向设置(0输入/1输出)
XGpioPs_SetDirectionPin(&Gpio, EMIO_LED0, 1);
XGpioPs_SetDirectionPin(&Gpio, EMIO_LED1, 1);
XGpioPs_SetDirectionPin(&Gpio, MIO_KEY0, 0);
XGpioPs_SetDirectionPin(&Gpio, MIO_KEY1, 0);
//设置输出使能(1使能)
XGpioPs_SetOutputEnablePin(&Gpio, EMIO_LED0, 1);
XGpioPs_SetOutputEnablePin(&Gpio, EMIO_LED1, 1);
}
//===========================LED闪烁===========================//
void LED_blink()
{
//向GPIO写1
XGpioPs_WritePin(&Gpio, EMIO_LED0, 0x1);
XGpioPs_WritePin(&Gpio, EMIO_LED1, 0x1);
sleep(1);//延迟1s(头文件sleep.h内秒延时函数,还有usleep微秒级延时)
//向GPIO写0
XGpioPs_WritePin(&Gpio, EMIO_LED0, 0x0);
XGpioPs_WritePin(&Gpio, EMIO_LED1, 0x0);
sleep(1);//延迟1s
}
四、效果
上板运行两个LED闪烁两次,之后按下按键时对应LED灯亮起,松开熄灭