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);
}



















