1.开发背景
基于 PS 端 GPIO 的基础上,如何调用 PL 端 GPIO 的输入输出
2.开发需求
PL 端按键控制 PL 端 LED
3.开发环境
Zynq7020 + Vivado2017.4
4.实现步骤
4.1 设计配置
这里设置 PIO 数量 3 个
由于 PL 端不像 PS 端一样绑定 GPIO,所以需要对上面的 3 个 GPIO 绑定引脚 RTL IO
4.2 代码编辑
事实上通过 EMIO 复用和 MIO 使用方法一样,唯一需要注意的是 GPIO 的映射关系,所以GPIO从54 - 56
#define XGPIOPS_DEVICE_MAX_PIN_NUM_ZYNQMP (u32)174 /**< Max pins in the
* Zynq Ultrascale+ MP GPIO device
* 0 - 25, Bank 0
* 26 - 51, Bank 1
* 52 - 77, Bank 2
* 78 - 109, Bank 3
* 110 - 141, Bank 4
* 142 - 173, Bank 5
*/
#define XGPIOPS_DEVICE_MAX_PIN_NUM (u32)118 /**< Max pins in the Zynq GPIO device
* 0 - 31, Bank 0
* 32 - 53, Bank 1
* 54 - 85, Bank 2
* 86 - 117, Bank 3
*/
#include <xil_printf.h> // 包含 xil_printf()函数
#include "xparameters.h" // 器件参数信息 系统生成
#include "xstatus.h" // 包含 库的故障码 的宏定义
#include "xgpiops.h" // 包含 PS、PL GPIO 的函数声明
#include "xplatform_info.h" // 获取当前的平台信息
#include "sleep.h" // 睡眠延时接口
#include "xtime_l.h"
/* 重新定义 */
#define printf xil_printf
/* gpio 设备,不知为何为 0 */
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID // 0
/* GPIO 映射 */
#define BOARD_LED0 (7)
#define BOARD_KEY0 (12)
#define CORE_LED (0)
#define EMIO_LED0 (54)
#define EMIO_LED1 (55)
#define EMIO_KEY0 (56)
static XGpioPs s_psGpio = {0};
/* 毫秒延时 */
void msleep(int ms)
{
/* 64 bit 记录时间 */
XTime tEnd;
XTime tCur;
/* 获取当前时间 */
XTime_GetTime(&tCur);
/* 计算理论结束时间 */
tEnd = tCur + ((((XTime) ms) * COUNTS_PER_SECOND) / 1000);
/* 阻塞一直查询当前时间是否超时,一直占用 CPU */
do
{
XTime_GetTime(&tCur);
}while (tCur < tEnd);
}
/* main 入口 */
int main()
{
printf("%s XGetPlatform_Info = %d\r\n", __func__, XGetPlatform_Info());
/* 通过设备 ID 找到对应的配置指针 */
XGpioPs_Config *ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
/* 通过配置指针初始化GPIO */
int Status = XGpioPs_CfgInitialize(&s_psGpio, ConfigPtr,
ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS)
{
return XST_FAILURE;
}
/* 设置 GPIO 方向输出,这里为什么会共用一个 GPIO 结构体?参数一致? */
XGpioPs_SetDirectionPin(&s_psGpio, BOARD_LED0, 1);
XGpioPs_SetDirectionPin(&s_psGpio, CORE_LED, 1);
XGpioPs_SetDirectionPin(&s_psGpio, EMIO_LED0, 1);
XGpioPs_SetDirectionPin(&s_psGpio, EMIO_LED1, 1);
XGpioPs_SetDirectionPin(&s_psGpio, BOARD_KEY0, 0);
XGpioPs_SetDirectionPin(&s_psGpio, EMIO_KEY0, 0);
/* 使能 GPIO */
XGpioPs_SetOutputEnablePin(&s_psGpio, BOARD_LED0, 1);
XGpioPs_SetOutputEnablePin(&s_psGpio, CORE_LED, 1);
XGpioPs_SetOutputEnablePin(&s_psGpio, EMIO_LED0, 1);
XGpioPs_SetOutputEnablePin(&s_psGpio, EMIO_LED1, 1);
/* 点灯 1s改变一次电平 */
for (int i = 0; i < 3; i++)
{
XGpioPs_WritePin(&s_psGpio, BOARD_LED0, 0);
msleep(500);
XGpioPs_WritePin(&s_psGpio, BOARD_LED0, 1);
msleep(500);
}
/* 点灯 0.2s改变一次电平 */
for (int i = 0; i < 3; i++)
{
XGpioPs_WritePin(&s_psGpio, CORE_LED, 0);
XGpioPs_WritePin(&s_psGpio, EMIO_LED1, 0);
msleep(200);
XGpioPs_WritePin(&s_psGpio, CORE_LED, 1);
XGpioPs_WritePin(&s_psGpio, EMIO_LED1, 1);
msleep(200);
}
/* 定时读取电平控制对应灯的亮灭 */
unsigned int status = 0;
while (1)
{
msleep(10);
status = XGpioPs_ReadPin(&s_psGpio, BOARD_KEY0);
XGpioPs_WritePin(&s_psGpio, BOARD_LED0, status);
status = XGpioPs_ReadPin(&s_psGpio, EMIO_KEY0);
XGpioPs_WritePin(&s_psGpio, EMIO_LED0, status);
}
return 0;
}