接上一篇 xilinx zynq 7010/7020 中断/中断向量/GIC向量/GPIO中断
中断向量表和中断ISR和GIC的关系如上图所示
这里是整个中断系统的重点。
ISR表示各个中断源中断发生后,中断服务函数的实例。通过中断号作为HandlerTable的索引值跳转到具体的中断服务函数。
中断服务函数中根据外设的MASK 和状态来判断具体是哪个部分发生了中断。
GIC的输入是各个中断源的中断线,通过中断号来记录是哪个中断源发生了中断,这里是记录。
中断发生后,GIC根据配置把中断信号,给到对应的CPU,CPU接收到了中断后,由硬件进行中断跳转,跳转到VectorTable对应的中断服务函数。以GPIO为例,GIC会触发CPU 的IRQ中断,CPU就会通过VextorTABLE中IRQ中断的入口跳转到XScuGic_InterruptHandler.
所有的IRQ中断都会进入到XScuGic_InterruptHandler函数,XScuGic_InterruptHandler函数根据GIC中记录的中断号来判断,是哪个中断源发生了中断,进行软件跳转到ISR #n。这里和MCU (ARM cortex M3,M4)内核的中断有非常大的区别。
理清楚上面的关系后,就不难理解代码。代码中有多个函数的配置和关联,本质上就是上图信息流的配置。
代码如下,适配的是xilinx 官方zc702开发板 。SW13作为输入,LED DS11作为输出显示。
#include "xparameters.h"
#include "xgpiops.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xplatform_info.h"
#include <xil_printf.h>
#define INT_GPIO_KEY (14)
#define INT_GPIO_LED (8)
#define INTC_DEVICE_ID 0
#define XPS_GPIO_INT_ID 52U
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define GPIO_BANK XGPIOPS_BANK0 /* Bank 0 of the GPIO Device */
XGpioPs IntGpio;
XScuGic IntGIC; /* The Instance of the Interrupt Controller Driver */
/****************************************************************************/
/**
* This function is the user layer callback function for the bank 0 interrupts of
* the GPIO device. It checks if all the switches have been pressed to stop the
* interrupt processing and exit from the example.
*
* @param CallBackRef is a pointer to the upper layer callback reference.
* @param Status is the Interrupt status of the GPIO bank.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void IntrHandler(void *CallBackRef, u32 Bank, u32 Status)
{
XGpioPs *Gpio = (XGpioPs *)CallBackRef;
u32 DataRead;
/* Push the switch button */
DataRead = XGpioPs_ReadPin(Gpio, INT_GPIO_KEY);
XGpioPs_WritePin(Gpio, INT_GPIO_LED, DataRead);
}
int main(void)
{
int Status;
XGpioPs_Config *ConfigPtr;
XScuGic_Config *IntcConfig; /* Instance of the interrupt controller */
print("GPIO Interrupt test \r\n");
/*initial GPIO */
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
Status = XGpioPs_CfgInitialize(&IntGpio, ConfigPtr,ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*config GPIO output LED */
XGpioPs_SetDirectionPin(&IntGpio, INT_GPIO_LED, 1);
XGpioPs_SetOutputEnablePin(&IntGpio, INT_GPIO_LED, 1);
/*config Input Button*/
XGpioPs_SetDirectionPin(&IntGpio, INT_GPIO_KEY, 0x0);
/*initial GIC */
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(&IntGIC, IntcConfig,IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*config IRQ*/
/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
&IntGIC);
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
Status = XScuGic_Connect(&IntGIC, XPS_GPIO_INT_ID,
(Xil_ExceptionHandler)XGpioPs_IntrHandler,
(void *)&IntGpio);
if (Status != XST_SUCCESS) {
return Status;
}
/* Enable falling edge interrupts for all the pins in bank 0. */
XGpioPs_SetIntrType(&IntGpio, GPIO_BANK, 0x00, 0xFFFFFFFF, 0x00);
/* Set the handler for gpio interrupts. */
XGpioPs_SetCallbackHandler(&IntGpio, (void *)&IntGpio, IntrHandler);
/* Enable the GPIO interrupts of Bank 0. */
XGpioPs_IntrEnable(&IntGpio, GPIO_BANK, (1 << INT_GPIO_KEY));
/* Enable the interrupt for the GPIO device. */
XScuGic_Enable(&IntGIC, XPS_GPIO_INT_ID);
/* Enable interrupts in the Processor. */
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
return 0;
}