1.开发背景
基于上一个篇章 GPIO 使用,引入中断的使用。
2.开发需求
PS 和 PL 按键输入中断,并输出对应的日志打印
3.开发环境
Zynq7020 + Vivado2017.4
4.实现步骤
4.1 设计配置
PL Key0 56
PS key0 12
PS key1 11
4.2 代码编写
GPIO 配置
#ifndef MSP_GPIO_H
#define MSP_GPIO_H
#include "xgpiops.h"
/* PS GPIO 映射 */
#define BOARD_LED0 (7)
#define BOARD_KEY0 (12)
#define BOARD_KEY1 (11)
#define CORE_LED (0)
/* PL GPIO 映射 */
#define EMIO_LED0 (54)
#define EMIO_LED1 (55)
#define EMIO_KEY0 (56)
int mspGpio_Init(void);
void mspGpio_SetOutput(unsigned char gpioId, unsigned char state);
unsigned char mspGpio_GetInput(unsigned char gpioId);
XGpioPs* mspGpio_GetPsHandle(void);
#endif
#include "mspGpio.h"
/* gpio 设备,不知为何为 0 */
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID // 0
static XGpioPs s_psGpio = {0};
/* GPIO 初始化 */
int mspGpio_Init(void)
{
/* 通过设备 ID 找到对应的配置指针 */
XGpioPs_Config *ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
/* 通过配置指针初始化GPIO */
int Status = XGpioPs_CfgInitialize(&s_psGpio, ConfigPtr,
ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS)
{
return -1;
}
/* 设置 GPIO 方向输出,这里为什么会共用一个 GPIO 结构体?参数一致? */
XGpioPs_SetDirectionPin(&s_psGpio, CORE_LED, 1);
XGpioPs_SetDirectionPin(&s_psGpio, BOARD_LED0, 1);
XGpioPs_SetDirectionPin(&s_psGpio, BOARD_KEY0, 0);
XGpioPs_SetDirectionPin(&s_psGpio, BOARD_KEY1, 0);
XGpioPs_SetDirectionPin(&s_psGpio, EMIO_LED0, 1);
XGpioPs_SetDirectionPin(&s_psGpio, EMIO_LED1, 1);
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);
return 0;
}
/* 设置输出 */
void mspGpio_SetOutput(unsigned char gpioId, unsigned char state)
{
XGpioPs_WritePin(&s_psGpio, gpioId, state);
}
/* 获取输入 */
unsigned char mspGpio_GetInput(unsigned char gpioId)
{
return XGpioPs_ReadPin(&s_psGpio, gpioId);
}
/* 获取 PS GPIO 句柄 */
XGpioPs* mspGpio_GetPsHandle(void)
{
return &s_psGpio;
}
中断配置
#include "mspExit.h"
#include "xscugic.h"
#include "mspCore.h"
#include "mspGpio.h"
#include "mspTimer.h"
static XScuGic intc = {0}; //通用中断控制器驱动实例
//以下常量映射到xparameters.h文件
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID //PS端GPIO器件ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID //通用中断控制器ID
#define GPIO_INTERRUPT_ID XPAR_XGPIOPS_0_INTR //PS端GPIO中断ID
static void intr_handler(void *callback_ref);
/* 初始化中断接口 */
int setup_interrupt_system(XScuGic *gic_ins_ptr, XGpioPs *gpio, u16 GpioIntrId)
{
int status;
XScuGic_Config *IntcConfig; //中断控制器配置信息
//查找中断控制器配置信息并初始化中断控制器驱动
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfig)
{
return XST_FAILURE;
}
status = XScuGic_CfgInitialize(gic_ins_ptr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (status != XST_SUCCESS)
{
return XST_FAILURE;
}
//设置并使能中断异常
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler) XScuGic_InterruptHandler, gic_ins_ptr);
Xil_ExceptionEnable();
//为中断设置中断处理函数
status = XScuGic_Connect(gic_ins_ptr, GpioIntrId,
(Xil_ExceptionHandler) intr_handler, (void *) gpio);
if (status != XST_SUCCESS)
{
return status;
}
//使能来自于Gpio器件的中断
XScuGic_Enable(gic_ins_ptr, GpioIntrId);
//设置KEY按键的中断类型为下降沿中断
XGpioPs_SetIntrTypePin(gpio, BOARD_KEY0, XGPIOPS_IRQ_TYPE_EDGE_FALLING);
XGpioPs_SetIntrTypePin(gpio, BOARD_KEY1, XGPIOPS_IRQ_TYPE_EDGE_FALLING);
XGpioPs_SetIntrTypePin(gpio, EMIO_KEY0, XGPIOPS_IRQ_TYPE_EDGE_FALLING);
//使能按键KEY中断
XGpioPs_IntrEnablePin(gpio, BOARD_KEY0);
XGpioPs_IntrEnablePin(gpio, BOARD_KEY1);
XGpioPs_IntrEnablePin(gpio, EMIO_KEY0);
return XST_SUCCESS;
}
/* 中断初始化 */
int mspExit_Init(void)
{
setup_interrupt_system(&intc, mspGpio_GetPsHandle(), XPAR_XGPIOPS_0_INTR);
return 0;
}
/* 中断处理 */
void intr_handler(void *callback_ref)
{
/* 强行延时 */
// mspTimer_DelayMs(100);
XGpioPs *gpio = (XGpioPs *) callback_ref;
//读取KEY按键引脚的中断状态,判断是否发生中断
if (XGpioPs_IntrGetStatusPin(gpio, BOARD_KEY1))
{
printf("key = %d\r\n", BOARD_KEY1);
XGpioPs_IntrClearPin(gpio, BOARD_KEY1); //清除按键KEY中断
}
else if (XGpioPs_IntrGetStatusPin(gpio, BOARD_KEY0))
{
printf("key = %d\r\n", BOARD_KEY0);
XGpioPs_IntrClearPin(gpio, BOARD_KEY0); //清除按键KEY中断
}
else if (XGpioPs_IntrGetStatusPin(gpio, EMIO_KEY0))
{
printf("key = %d\r\n", EMIO_KEY0);
XGpioPs_IntrClearPin(gpio, EMIO_KEY0); //清除按键KEY中断
}
}