一、ZYNQ中断概述
中断类型:私有外设中断(PPI):全局定时器、私有看门狗、私有定时器、PL部分产生的FIQ/IRQ;
看门狗:WDT, 看门狗定时器,有两个, 分别监视ARM-Cortex A9用的。 如果软件跑飞,无法清定时器,一段时间后,看门狗就复位。SWDT,系统级看门狗定时器, 这个看门狗的时钟和复位信号,都可以来自于芯片外部, 这样,即使系统有严重故障,比如时钟频率本身都有问题了, 仍然可以通过与系统无关的外部信号计数,计数满就复位。
FIQ/IRQ:ARM内核可以识别正常识别正常中断请求和快速中断请求两种类型的外部中断,中断的行为模式由中断控制器来设置。ARM内核只有2个外部中断输入信号nIRQ,nFIQ,在具体嵌入式系统中,需要用中断控制器管理多个外部中断源,选择其中一个中断,通过nIRQ或nFIQ想ARM内核发出中断请求。
共享外设中断(SPI):位于PS和PL的I/O及内存控制器产生的中断;
软件中断(SGI):对通用中断控制器读写产生的中断,通过写相关寄存器产生,中断CPU自身或其他CPU,所有CPU,每个CPU有自己的SGI寄存器组。
GIC——通用中断控制器:
允许、禁止中断和管理中断优先级;所有CPU均通过私有总线访问GIC。
中断信号传递:
三、中断编程模式:
中断优先级;
中断处理:GIC寄存器访问;分发器和CPU接口;GIC安全扩展的影响;PU接口寄存器;保存和存储控制器状态;
延迟中断和安全扩展:GIC只有IRQ会抢占;FIQ采用安全模式。
其余关于中断触发方式及寄存器等内容参考我另一篇博客,AXI INTC学习笔记。
四、独立按键中断
对应按键按下之后,FPGA 的对应管脚输入电平值应该为 0。
查看U585第231页,可以看到从PL部分输入的中断号为{[91:84],[68:61]}对应IRQ_F2P[15:0],在这里我PS部分使用的就是IRQ_F2P。
实现代码:
#include
#include "platform.h"
#include "xil_printf.h"
#include "xil_exception.h"
#include "xscugic.h"
#include "xgpio.h"
#define BTN_DEVICE_ID XPAR_GPIO_BTN_DEVICE_ID
#define LEDS_DEVICE_ID XPAR_GPIO_LEDS_DEVICE_ID
#define INTC_GPIO_INTERRUPT_ID XPAR_FABRIC_GPIO_BTN_IP2INTC_IRPT_INTR
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define INTC XScuGic
#define INTC_HANDLER XScuGic_InterruptHandler
#define BUTTON_INTERRUPT XGPIO_IR_CH1_MASK
#define LED_DELAY 1000000
static u16 GlobalIntrMask;
static volatile u32 IntrFlag;
int GpioIntrInitialize();
void GpioHandler(void *CallBackRef);
int GpioSetupIntrSystem(INTC *IntcInstancePtr, XGpio *InstancePtr,u16 DeviceId, u16 IntrId, u16 IntrMask);
void GpioDisableIntr(INTC *IntcInstancePtr, XGpio *InstancePtr,u16 IntrId, u16 IntrMask);
XGpio Gpio_BTN,Gpio_LEDS;
INTC Intc;
#ifndef TESTAPP_GEN
int main(void)
{
int Status;
Status= GpioIntrInitialize();
return XST_SUCCESS;
}
#endif
int GpioIntrInitialize(){
int Status;
u32 delay;
Status = XGpio_Initialize(&Gpio_BTN, BTN_DEVICE_ID);//初始化BTN的AXI_GPIO
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Status = XGpio_Initialize(&Gpio_LEDS, LEDS_DEVICE_ID);//初始化LED和SEG7的AXI_GPIO
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XGpio_SetDataDirection(&Gpio_BTN, 1, 0X0F); //设置独立按键通道全为输入
XGpio_SetDataDirection(&Gpio_LEDS, 1, 0); //设置LED通道全为输出
XGpio_SetDataDirection(&Gpio_LEDS, 2, 0); //设置SEG7通道全为输出
XGpio_DiscreteWrite(&Gpio_LEDS, 1, 0xFF);//先将LED灯全熄灭
XGpio_DiscreteWrite(&Gpio_LEDS, 2, 0xFF0000);//将7段数码管全熄灭
Status = GpioSetupIntrSystem(&Intc, &Gpio_BTN, BTN_DEVICE_ID,INTC_GPIO_INTERRUPT_ID,INTR_MASK);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
IntrFlag = 0;
delay = 0;
//4位中断信号依次从低位到高位为0
while(1){
switch(IntrFlag&0xF)
{
case 0xE:
XGpio_DiscreteWrite(&Gpio_LEDS, 1, 0xFC);
XGpio_DiscreteWrite(&Gpio_LEDS, 2, 0x000606);
break;
case 0xD:
XGpio_DiscreteWrite(&Gpio_LEDS, 1, 0xF3);
XGpio_DiscreteWrite(&Gpio_LEDS, 2, 0x005B5B);
break;
case 0xB:
XGpio_DiscreteWrite(&Gpio_LEDS, 1, 0xCF);
XGpio_DiscreteWrite(&Gpio_LEDS, 2, 0x004F4F);
break;
case 0x7:
XGpio_DiscreteWrite(&Gpio_LEDS, 1, 0x3F);
XGpio_DiscreteWrite(&Gpio_LEDS, 2, 0x006666);
break;
default:
//XGpio_DiscreteWrite(&Gpio_LEDS, LEDS_CHANNEL, LEDS_ALL_OFF);
//XGpio_DiscreteWrite(&Gpio_LEDS, SEG7_CHANNEL, SEG7_ALL_OFF);
break;
}
}
GpioDisableIntr(&Intc, &Gpio_BTN, INTC_GPIO_INTERRUPT_ID, INTR_MASK);
return Status;
}
int GpioSetupIntrSystem(INTC *IntcInstancePtr, XGpio *InstancePtr,
u16 DeviceId, u16 IntrId, u16 IntrMask)
{
int Result;
GlobalIntrMask = IntrMask;//中断掩码
XScuGic_Config *IntcConfig;
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);//找到GIC驱动的ID并初始化
if (NULL == IntcConfig) {
return XST_FAILURE;
}
Result = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);
if (Result != XST_SUCCESS) {
return XST_FAILURE;
}
XScuGic_SetPriorityTriggerType(IntcInstancePtr, IntrId,0xA0, 0x3);//设置中断触发方式和优先级
Result = XScuGic_Connect(IntcInstancePtr, IntrId,
(Xil_ExceptionHandler)GpioHandler, InstancePtr);
if (Result != XST_SUCCESS) {
return Result;
}
XScuGic_Enable(IntcInstancePtr, IntrId);//允许GPIO中断
//允许GPIO通道按键输入中断信号能被检测
XGpio_InterruptEnable(InstancePtr, IntrMask);
XGpio_InterruptGlobalEnable(InstancePtr);
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)INTC_HANDLER, IntcInstancePtr);//初始化异常中断表
/* 允许异常 */
Xil_ExceptionEnable();
return XST_SUCCESS;
}
void GpioHandler(void *CallbackRef)
{
XGpio *GpioPtr = (XGpio *)CallbackRef;
IntrFlag = XGpio_DicreteRead(&Gpio_BTN, 1);//读取按键产生的中断信号
/* 清除中断 */
XGpio_InterruptClear(GpioPtr, GlobalIntrMask);
}
void GpioDisableIntr(INTC *IntcInstancePtr, XGpio *InstancePtr,
u16 IntrId, u16 IntrMask)
{
XGpio_InterruptDisable(InstancePtr, IntrMask);
/* 断开中断连接 */
XScuGic_Disable(IntcInstancePtr, IntrId);
XScuGic_Disconnect(IntcInstancePtr, IntrId);
return;
}