在嵌入式开发中,GPIO 是最常见的外设。GPIO 是 General Purpose I/O 的缩写,译为通用输入/输出。GPIO 用于连接外部设备,例如按键、传感器等,实现数字信号的输入或输出功能。本文主要介绍 Zynq GPIO 的基本概念,并对比 GPIO 与 AXI GPIO 的使用方法。
GPIO
Zynq GPIO 被称为 MIO,是 Multiplexed I/O 的缩写,译为多路复用 I/O。一般 MIO 指Zynq PS 端的用户管脚,而 PL 端的用户管脚属于扩展的 MIO,因此也被称为 EMIO(Extendable Multiplexed I/O)。
从下图可以看到,Zynq PS 端的 MIO 管脚由 MIO Multiplexer 模块控制,PL 端的用户管脚需要通过 EMIO 接口访问。
Zynq GPIO 以 Bank 的形式组织,其中 MIO 位于 Bank 0 和 Bank1,共有 54 个;EMIO 则位于 Bank2 和 Bank3,共有 64 个。
Zynq 每个 GPIO 的功能都可以单个或以 Bank 为单位进行动态编程,并由软件通过一系列内存映射寄存器进行控制。GPIO 可以通过读写相关寄存器进行访问,也可以使用高层次的方式,即使用结构体与函数读写 GPIO。
下图是 xgpiops.h 头文件关于 XGpioPs_Config 和 XGpioPs 结构体的定义。
XGpioPs API
#include "xparameters.h"
#include "xgpiops.h"#define GPIO_0 0
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_IDvoid XGpioPs_Init(XGpioPs *GpioInstance, u32 deviceID) {// XGpioPs_Config object definitionXGpioPs_Config *ConfigPtr;ConfigPtr = XGpioPs_LookupConfig(deviceID);XGpioPs_CfgInitialize(GpioInstance, ConfigPtr, ConfigPtr->BaseAddr);// Gpio initializationXGpioPs_SetDirectionPin(GpioInstance, GPIO_0, 1);XGpioPs_SetOutputEnablePin(GpioInstance, GPIO_0, 1);XGpioPs_WritePin(GpioInstance, GPIO_0, 0);
}int main(void) {XGpioPs Gpio;XGpioPs_Init(&Gpio, GPIO_DEVICE_ID);// Todoreturn -1;
}
AXI GPIO
AXI GPIO 是 Xilinx 提供的 GPIO IP,使用 AXI 接口通信,需要消耗一部分 PL 逻辑资源。
从下图可以看到,AXI GPIO 包含两个 GPIO 通道,每个通道最多 32 个 GPIO。
使用 AXI GPIO 时,需要 include 对应的头文件 xgpio.h,下图是 xgpio.h 中关于 XGpio_Config 和 XGpio 结构体的定义。
XGpio API
XGpio_Initialize() 函数调用了 XGpio_LookupConfig() 和 XGpio_CfgInitialize() 这两个函数实现 GPIO 初始化,因此用户初始化只需要调用 XGpio_Initialize() 函数即可。
#include "xparameters.h"
#include "xgpio.h"#define GPIO_0 0x01
#define GPIO_CHANNEL 1
#define GPIO_DEVICE_ID XPAR_GPIO_0_DEVICE_IDint XGpio_Init(XGpio *GpioInstance, u16 DeviceId) {int Status;/* Initialize the GPIO driver */Status = XGpio_Initialize(GpioInstance, DeviceId);if (Status != XST_SUCCESS) {return XST_FAILURE;}/* Set the direction for all signals as inputs except the GPIO_0 output */XGpio_SetDataDirection(GpioInstance, GPIO_CHANNEL, ~GPIO_0);return XST_SUCCESS;
}