GPIO之MIO中断
- GPIO的MIO中断功能
- 实验:使用GPIO的MIO中断功能,实现按键控制LED的亮灭。
GPIO的MIO中断功能
从MIO输入到GPIO的线路有一个通向中断检测模块的分支。
INT_TYPE寄存器表示中断类型。包括边沿和电平两种类型。
INT_POLARITY寄存器表示极性。包括正负极性。电平类型中断包括低电平触发(-)和高电平触发(+)。边沿类型中断包括上升沿极性(+)和下降沿极性(-)。
INT_ANY寄存器针对边沿触发类型的中断。若为1,则两种边沿变换都可触发中断。
INT State寄存器用来保存中断状态。清零端口连接INT_STAT。INT_STAT写1清除中断。
读INT_STAT可获知引脚当前中断状态,即是否有中断产生。
INT_MASK寄存器表示MIO的哪个引脚的中断被屏蔽。读取此寄存器可知哪些引脚的中断被屏蔽。
INT_DIS表示关闭使能,即屏蔽。(disable)
INT_EN表示中断使能。
若某个引脚检测到中断,且同时这个引脚的中断未被屏蔽,则与门输出高电平,即输出一个中断到GIC,即向GIC发送一个IRQ中断请求。GIC即为PS中的中断控制器。#52表示中断ID。
GIC可接收PS和PL的IRQ,通过中断ID获知是谁发起的请求。每个外设的ID都不同,对于GPIO,其中断号为52。
实验:使用GPIO的MIO中断功能,实现按键控制LED的亮灭。
#include "stdio.h"
#include "xparameters.h"
#include "xparameters_ps.h"
#include "xgpiops.h"
#include "xscugic.h"
#include "sleep.h"
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
// GPIO中断号(52)
#define GPIO_INTERRUPT_ID XPAR_XGPIOPS_0_INTR
// 核心板上PS端LED连接到MIO0
#define MIO0_LED 0
#define MIO12_KEY 12
#define GPIO_BANK XGPIOPS_BANK0 /* Bank 0 of the GPIO Device */
XGpioPs_Config * ConfigPtr;
XGpioPs Gpio;
// 中断控制器的驱动实例
XScuGic Intc;
// 中断控制器的配置实例
XScuGic_Config *IntcConfig;
XScuGic *GicInstancePtr;
XScuGic_Config *IntcConfig; /* Instance of the interrupt controller */
u32 key_press = 0;
u32 led_value = 0;
void SetupInterruptSystem(XScuGic *GicInstancePtr, XGpioPs *Gpio, u16 GpioIntrId);
void IntrHandler();
int main(){
printf("GPIO interrupt test!\n\r");
// 根据器件的ID,查找器件的配置信息
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
// 初始化GPIO驱动
XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);
// 把GPIO某个引脚的方向设置为输出(第二个参数为输出Pin的ID(0~117);第三个参数为方向指示:为0:输入;为1:输出)
XGpioPs_SetDirectionPin(&Gpio, MIO0_LED, 1);
// 设置输出使能,第三个参数为1:打开输出使能;为0:关闭输出使能
XGpioPs_SetOutputEnablePin(&Gpio, MIO0_LED, 1);
// 设置中断系统
SetupInterruptSystem(&Intc, &Gpio, GPIO_INTERRUPT_ID);
while(1){
if(key_press){
led_value = ~led_value;
key_press = 0;
XGpioPs_WritePin(&Gpio, MIO0_LED, led_value);
// 清除之前的中断状态
XGpioPs_IntrClearPin(&Gpio, MIO12_KEY);
// 延时消抖
usleep(200000);
// 再次使能按键中断
XGpioPs_IntrEnablePin(&Gpio, MIO12_KEY);
}
}
return 0;
}
void SetupInterruptSystem(XScuGic *GicInstancePtr, XGpioPs *Gpio,
u16 GpioIntrId)
{
// 查找中断控制器配置信息并进行初始化
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);
// 初始化ARM处理器异常句柄
Xil_ExceptionInit();
// 给IRQ异常注册处理程序
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
GicInstancePtr);
// 使能处理器中断
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
// 关联中断处理函数IntrHandler
XScuGic_Connect(GicInstancePtr, GpioIntrId,
(Xil_ExceptionHandler)IntrHandler,
(void *)Gpio);
// 将bank0中所有引脚都设置为下降沿中断
//XGpioPs_SetIntrType(Gpio, GPIO_BANK , 0x00, 0xFFFFFFFF, 0x00);
// 将MIO单个引脚(与按键相连的pin12)设置为下降沿中断
XGpioPs_SetIntrTypePin(Gpio, MIO12_KEY, XGPIOPS_IRQ_TYPE_EDGE_FALLING);
/* Enable the GPIO interrupts of Bank 0. */
//XGpioPs_IntrEnable(Gpio, GPIO_BANK, (1 << Input_Pin));
// 设置MIO单个引脚的中断使能(主动)
XGpioPs_IntrEnablePin(Gpio, MIO12_KEY);
// 设置GIC能够接收GPIO中断(被动)
XScuGic_Enable(GicInstancePtr, GpioIntrId);
}
void IntrHandler(){
// 中断处理程序:当检测到pin12出现下降沿时,触发中断,即将key_press变量赋值为1。
key_press = 1;
printf("interrupt detected!\n\r");
// 执行完中断处理函数后,将中断屏蔽掉
XGpioPs_IntrDisablePin(&Gpio, MIO12_KEY);
}