1、GPIO 简介
GPIO 是英文“general purpose I/O”的缩写,即通用的输入/输出。
以Zynq-7000 SoC Technical reference Mannual 介绍为力;
通用I/O (GPIO)外围设备通过MIO模块提供多达54个设备引脚的观察和控制软件。它还提供来自可编程逻辑(PL)的64个输入和通过EMIO接口到PL的128个输出。GPIO被组织成四组寄存器,用来分组相关的接口信号。每个GPIO都被独立地动态编程为输入、输出或中断感知。软件可以使用一条加载指令读取bank内的所有GPIO值,也可以使用一条存储指令将数据写入一个或多个GPIO(在一个GPIO范围内)。GPIO控制寄存器和状态寄存器映射在基址0xE000_A000的内存中。
2、特征
GPIO 它是 ZYNQ PS 中的一个外设,用于 观测和控制器件引脚的状态。 GPIO 的框图,从中我们可以看到 GPIO 分为 4 个 Bank,其中 Bank0 和 Bank1 连接到 MIO;而 Bank2 和 Bank3 连接到 EMIO。
Zynq-7000 系列芯片一般有 54 个 MIO;
除 Bank1 之外的 Bank 都具有 32bit,Bank1 只具有 22bit ,总共只有 54 个 MIO,其中 32bit 的 Bank0 控制了 MIO[0~31],剩下的 MIO[31~53]就由 22bit 的 Bank1 控制。Bank2 和 Bank3 用于控制扩展的 MIO 即 EMIO,也就是说总共可以有 32+32=64 个 EMIO
ZYNQ 分为 PS 和 PL 两部分,那么器件的引脚(Pin)资源同样也分成了两部分。ZYNQ PS 中的外设可以通过 MIO(Multiuse I/O,多用输入/输出)模块连接到 PS 端的引脚上,也可以通过 EMIO 连接到 PL 端的引脚。
GPIO 框图如下所示

2.1 功能描述 和 引脚控制
左边的一列是寄存器,上半部分是关于中断的控制,下半部分是GPIO接口的控制。
DATA_RO : 是一个只读寄存器,这个寄存器使软件能够观察设备引脚上的值。如果GPIO
信号被配置为输出,那么这通常会反映输出上驱动的值。对这个寄存器的写入将被忽略。
DATA: 这个寄存器控制将GPIO信号配置为输出时的输出值。这个寄存器的所有32位一次写入。从这个寄存器读入返回之前写到DATA或MASK_DATA_{LSW,MSW}的值;它不返回设备引脚上的当前值。
MASK_DATA_LSW: 是一个16位的数据掩码器,该寄存器控制Bank的低16位,能够使软件有选择的一次更改所需要的输出值,即可以屏蔽Bank中低16位中的某些位的写入,使其保持不变。
MASK_DATA_MSW: 是一个16位的数据掩码器,该寄存器控制Bank的高16位。
DIRM: 是方向模式寄存器,用于控制 I/O 引脚是用作输入还是输出。当 DIRM [x] == 0 时,输出驱动器 被禁用,该引脚作为输入引脚使用。
OEN: OEN 是使能输出寄存器。将 I/O 配置为输出时,该寄存器控制是否启用输出。禁用输出时,引脚为 3 态。当 OEN [x] == 0 时,输出被禁用。
根据上述引脚的介绍,我们总结出使用GPIO的要点:
确定引脚位输入或者输出,即确定引脚方向
给引脚使能

3、实验设计
3.1 实验任务
使用 GPIO 通过 MIO和EMIO读取PS端和PL端按键值
使用 GPIO 通过 MIO和EMIO 写入引脚值,控制 PS 端 LED 的亮灭。

3.2实验内容
创建Vivado工程
用 IP Integrator 创建 Processing System ,
即添加 ZYNQ7 Processing System 模块,重新定义 ZYNQ7 Processing System,在Peripheral I/O Pins 中在Bank0的GPIO14\15选择UART0;
在Bank1中选择电压为LVCOMS 1.8V 实验设计的引脚是PS端引脚,不需要绑定
生成顶层HDL(generate Output Products、creat HDL Wrapper)
生成 Bitstream 文件并导出到 SDK,打开SDK
软件设计
#include "xgpiops.h"
#include "sleep.h"
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID //PS 端 GPIO 器件 ID
#define MIO0_LED 0 //PS_LED0 连接到 MIO 0
#define MIO7_LED 7 //PS_LED7 连接到 MIO 7
#define MIO8_LED 8 //PS_LED8 连接到 MIO 8
#define MIO11_KEY 11 //PS_KEY1 连接到 MIO11
#define MIO12_KEY 12 //PS_KEY0 连接到 MIO12
#define MIO54_KEY 54 //PL_KEY0 连接到 EMIO54
int main(){
XGpioPs_Config *ConfigPtr; //PS 端 GPIO 配置信息实例
XGpioPs Gpio; //PS 端 GPIO 驱动实例
int Status;
/* Initialize the GPIO driver. */
//根据器件 ID 查找配置信息,写入PS 端 GPIO 配置信息实例
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
//初始化器件驱动
Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/* Set the direction for the pin to be output and
* Enable the Output enable for the LED Pin.
*/
//设置 LED 为输出
XGpioPs_SetDirectionPin(&Gpio, MIO0_LED, 1);
XGpioPs_SetDirectionPin(&Gpio, MIO7_LED, 1);
XGpioPs_SetDirectionPin(&Gpio, MIO8_LED, 1);
//使能 LED 输出
XGpioPs_SetOutputEnablePin(&Gpio, MIO0_LED, 1);
XGpioPs_SetOutputEnablePin(&Gpio, MIO7_LED, 1);
XGpioPs_SetOutputEnablePin(&Gpio, MIO8_LED, 1);
//设置 KEY 为输入
XGpioPs_SetDirectionPin(&Gpio, MIO11_KEY, 0);
XGpioPs_SetDirectionPin(&Gpio, MIO12_KEY, 0);
XGpioPs_SetDirectionPin(&Gpio, MIO54_KEY, 0);
/* Set the GPIO output to be low. */
u32 key11; //PS_KEY1
u32 key12; //PS_KEY0
u32 key54; //PS_KEY0
while(1){
//读取引脚状态值
key11 = XGpioPs_ReadPin(&Gpio, MIO11_KEY);
key12 = XGpioPs_ReadPin(&Gpio, MIO12_KEY);
key54 = XGpioPs_ReadPin(&Gpio, MIO54_KEY);
//在引脚写入数据
XGpioPs_WritePin(&Gpio, MIO0_LED, ~key54);
XGpioPs_WritePin(&Gpio, MIO7_LED, ~key12);
XGpioPs_WritePin(&Gpio, MIO8_LED, ~key11);
}
}
6.上板验证
