目录
中断
中断简介
私有、共享和软中断
通用中断控制器GIC
复位和时钟
模块图
CPU中断信号直通
功能说明
软件生成的中断 SGI
CPU私有外设中断PPI
共享外围中断SPI
硬件系统
软件系统
私有定时器中断
函数API
参考
中断
中断简介
UG585 CH7 Interrupts
以下主要是翻译的文档。

中断通过GIC pl390连接CPU。
CPU接收的中断包括来自外围I/O和PL侧。主要包括下面关键点:
私有、共享和软中断
每个CPU都一组私有外设中断PPI,使用分组寄存器专用访问。PPI包括全局全局定时器、私有看梦定时器、私有定时器和PL侧的FIQ/IRQ。(是ARM的两种不同的中断模式)
软中断SGI被路由到一个或两个CPU。SGIs由通用中断控制器GIC的寄存器生成。
共享外设中断SPIs由各种I/O和PS和PL的内存控制器,被连接到一个或两个CPU。SPIs同时也被路由到PL侧。
(从上面的图,可以看到中断分为三类,SGI、PPI和SPI,其中SPI由包括PS和PL两部分)
通用中断控制器GIC
GIC是一个管理来自PS和PL中断的集中资源。当CPU接口接收下一个中断是,GIC使能、禁用、屏蔽和优先处理中断源并以编程方式发送中断给选定的CPU。
此外,GIC支持安全扩展以实现安全感知系统。
GIC基于ARM GIC v1.0 非矢量
为了快速读写响应,GIC通过私有总线访问寄存器,避免暂时阻塞或其他瓶颈。
GIC集中所有的中断资源进行调度,分发最该优先级的中断给各个CPU。
当一个中断面向多个CPU时,GIC确保一次只有一个CPU执行。
所有的中断源都有唯一的中断标识号。
所有的中断源都有自己的可配置的优先级和目标CPU列表。
(从上面的图可以看到,SGI、PPI和SPI都是发给GIC,通过IRQ/FIQ发送给CPU)
复位和时钟
GIC的复位由复位子系统控制,由系统级控制寄存器SLCR的A9_CPU_RST_CTRL寄存器的PERI_RST位.控制。该信号也复位CPU的私有定时器和私有看梦定时器AWDT。复位后,所有挂起或正在进行的中断全部被忽略。
GIC操作的时钟是CPU_3x2x(一半CPU的频率)。
模块图
SPIs由各种子系统生成,包括PS的I/O外设和PL的逻辑。

CPU中断信号直通
PL的中断可以路由到GIC作为PPI #4或#1中断,或者绕过GIC通过直通复用器。

两个CPU都可以使用。直通模式由mpcore.ICCICR寄存器控制。

功能说明
软件生成的中断 SGI
每个CPU能中断自身,另一个CPU或者两个CPU使用一个SGI。有16个软中断。中断的产生,通过写SGI中断号到ICDSGIR寄存器和指定目标CPU。通过CPU自己的私有总线。
每个CPU有自己的一组SGI寄存器来生成16个中断。通过读取ICCIAR寄存器(中断确认)或写1到ICDIPR(中断清挂起)寄存器相应位。
所有的SGI都是边沿触发,SGI的敏感类型是固定不可改变的;ICDIFR0寄存器是只读的,因为它指定了所有16个SGI敏感类型。

CPU私有外设中断PPI
每个CPU都有一组五个私有中断。
PPIs的敏感类型全是固定不可改变的,因此指定所有五个PPIs敏感类型的寄存器ICDICFR1是只读类型的。注意,来自的PL的快中断FIQ和中断IRQ信号被反转,然后再发送给中断控制器。因此,它们在PS-PL接口是高有效,但在ICDICFR1寄存器反映为低有效。

共享外围中断SPI
一组大约有60个来自各样模块的中断可以被路由到一个或两个CPUs或PL。中断控制器为CPU管理这些中断的优先级和接收。
除了IRQ#61到#68和#84到#91,所有的中断敏感类型都是由请求源固定不可改变的。必须对GIC编程以适应。引导ROM不编程这些寄存器,因此,SDK设备驱动必须编程GIC以适应这些敏感类型。
对于电平敏感类型中断,请求源必须提供一种机制以便中断处理程序在确认中断后的清除中断。这需求适用于任何具有高敏感类型的 IRQF2P[n](来自PL)。
对于上升沿触发的中断,请求源需要提供足够的脉宽供GIC捕获。这通常是2个CPU_2x3x周期。这需求适用于任何具有上升沿敏感类型的 IRQF2P[n](来自PL)。
寄存器ICDIFR2到ICDIFR5配置所有SPIs的中断类型。每个中断由2bit字段定制敏感类型和处理模型。


硬件系统
使用之前的版本。
软件系统
私有定时器中断
初始化中断控制器和私有定时器。打开私有定时器中断,连接中断操作。
/** main.c** Created on: 2020/3/21* Author: liny*/#include "intr_sys_timer.h"XScuTimer PriTimer; /* Cortex A9 SCU Private Timer Instance */
XScuGic Scugic ; /* Scu GIC */int main()
{int Status;xil_printf("SCU Timer Intr! \r\n");Status = init_intr_sys(&Scugic, &PriTimer);if (Status != XST_SUCCESS) {xil_printf("Intr failed...\r\n");return XST_FAILURE;}xil_printf("SCU Timer start \r\n");/* Start the Scu Private Timer device.*/PriTimer_Start(&PriTimer);while (1){;}// /* Stop the Scu Private Timer device.*/PriTimer_Stop(&PriTimer);Timer_Disable_Intr_System(&Scugic, TIMER_IRPT_INTR);xil_printf("SCU Timer Intr END! \r\n");return 0;
}
/** timer.h** Created on: 2020/3/21* Author: liny*/#ifndef SRC_INTR_SYS_TIMER_H_
#define SRC_INTR_SYS_TIMER_H_#include "xparameters.h"
#include "xscutimer.h"
#include "Xscugic.h"
#include "xil_exception.h"
#include "xil_printf.h"#define SCUGIC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define SCUGIC_BASE_ADDR XPAR_SCUGIC_0_CPU_BASEADDR
#define SCUGIC_DIST_BASE_ADDR XPAR_SCUGIC_0_DIST_BASEADDR
#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR// param
#define PRIVATE_TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID
// 1 Sec
#define TIMER_LOAD_VALUE XPAR_PS7_CORTEXA9_0_CPU_CLK_FREQ_HZ / 2 -1/************************** Function Prototypes ******************************/
// Private Timer
int PriTimer_Init(XScuTimer *TimerInstancePtr, u16 DeviceId, u32 LoadValue);
void PriTimer_Start(XScuTimer *TimerInstancePtr);
void PriTimer_Stop(XScuTimer *TimerInstancePtr);
void Timer_Intr_Enable(XScuTimer *TimerInstancePtr);
void Timer_Setup_Intr_System(XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr);
void Timer_Disable_Intr_System(XScuGic *IntcInstancePtr, u16 TimerIntrId);
void timer_callback(XScuTimer * TimerInstancePtr);
// GIC
int Init_Intr_System(XScuGic * IntcInstancePtr);
void Setup_Intr_Exception(XScuGic * IntcInstancePtr);int init_intr_sys(XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr) ;#endif /* SRC_INTR_SYS_TIMER_H_ */
/** timer.c** Created on: 2020/3/21* Author: liny*/#include "intr_sys_timer.h"/* Lookup , Initialize & Slef_Test*/
int PriTimer_Init(XScuTimer *TimerInstancePtr, u16 DeviceId, u32 LoadValue){int Status;XScuTimer_Config *ConfigPtr;ConfigPtr = XScuTimer_LookupConfig(DeviceId);Status = XScuTimer_CfgInitialize(TimerInstancePtr, ConfigPtr,ConfigPtr->BaseAddr);if (Status != XST_SUCCESS) {xil_printf("Scutimer Cfg initialization failed...\r\n");return XST_FAILURE;}elsexil_printf("Private Timer Initial Success! \n");Status = XScuTimer_SelfTest(TimerInstancePtr);if (Status != XST_SUCCESS) {xil_printf("Scutimer Self test failed...\r\n");return XST_SUCCESS;}elsexil_printf("Private Timer Initial Success! \n");/* Auto Reload mode. *///XScuTimer_DisableAutoReload(TimerInstancePtr);XScuTimer_EnableAutoReload(TimerInstancePtr);/* set the Load timer counter register value. */XScuTimer_LoadTimer(TimerInstancePtr, LoadValue);return XST_SUCCESS;
}void Timer_Setup_Intr_System(XScuGic *IntcInstancePtr,XScuTimer * TimerInstancePtr)
{Xil_ExceptionInit();XScuGic_DeviceInitialize(SCUGIC_DEVICE_ID);/** Connect the interrupt controller interrupt handler to the hardware* interrupt handling logic in the processor.*/Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,(Xil_ExceptionHandler)XScuGic_DeviceInterruptHandler,(void *)SCUGIC_DEVICE_ID);/** 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.*/XScuGic_Connect(IntcInstancePtr, TIMER_IRPT_INTR,(Xil_ExceptionHandler)timer_callback,(void *)TimerInstancePtr);
// XScuGic_RegisterHandler(SCUGIC_BASE_ADDR, TIMER_IRPT_INTR,
// (Xil_ExceptionHandler)timer_callback,
// (void *)TimerInstancePtr);/** Enable the interrupt for scu timer.*/XScuGic_Enable(IntcInstancePtr, TIMER_IRPT_INTR);
// XScuGic_EnableIntr(SCUGIC_DIST_BASE_ADDR, TIMER_IRPT_INTR);return ;
}
void Timer_Intr_Enable(XScuTimer *TimerInstancePtr)
{//Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);XScuTimer_EnableInterrupt(TimerInstancePtr);return;
}void Timer_Disable_Intr_System(XScuGic *IntcInstancePtr, u16 TimerIntrId)
{/** Disconnect and disable the interrupt for the Timer.*/XScuGic_Disconnect(IntcInstancePtr, TimerIntrId);
}
void PriTimer_Start(XScuTimer *TimerInstancePtr)
{XScuTimer_Start(TimerInstancePtr);return;
}void PriTimer_Stop(XScuTimer *TimerInstancePtr)
{XScuTimer_Stop(TimerInstancePtr);return;
}
void timer_callback(XScuTimer * TimerInstancePtr)
{xil_printf("Private Timer Intr Enable...\r\n");/* Clear Interrupt */XScuTimer_ClearInterruptStatus(TimerInstancePtr);
}
/**/
int Init_Intr_System(XScuGic * IntcInstancePtr)
{int Status;XScuGic_Config *IntcConfig;/** Initialize the interrupt controller driver so that it is ready to* use.*/IntcConfig = XScuGic_LookupConfig(SCUGIC_DEVICE_ID);if (NULL == IntcConfig) {return XST_FAILURE;}Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);if (Status != XST_SUCCESS) {return XST_FAILURE;}return XST_SUCCESS;
}
/**/
void Setup_Intr_Exception(XScuGic * IntcInstancePtr)
{/* Enable interrupts from the hardware */Xil_ExceptionInit();Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,(void *)IntcInstancePtr);// XScuGic_Connect(IntcInstancePtr, TIMER_IRPT_INTR,
// (Xil_ExceptionHandler)timer_callback,
// (void *)TimerInstancePtr);// XScuGic_Enable(IntcInstancePtr, TIMER_IRPT_INTR);Xil_ExceptionEnable();
}int init_intr_sys(XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr)
{int Status;/* Initialize the interrupt controller */Status = Init_Intr_System(IntcInstancePtr);if (Status != XST_SUCCESS) {xil_printf("Scutimer Cfg initialization failed...\r\n");return XST_FAILURE;}/* Initialize Private Timer */Status = PriTimer_Init(TimerInstancePtr, PRIVATE_TIMER_DEVICE_ID, TIMER_LOAD_VALUE);if (Status != XST_SUCCESS) {xil_printf("Scutimer Cfg initialization failed...\r\n");return XST_FAILURE;}/* Enable interrupts from the hardware */Setup_Intr_Exception(IntcInstancePtr);/* Set up timer Interrupt */Timer_Setup_Intr_System(IntcInstancePtr, TimerInstancePtr);/* Enable Timer interrupts */Timer_Intr_Enable(TimerInstancePtr);return XST_SUCCESS;
}
函数API
中断使用的库函数由xscugic.h和xscugic_hw.h和xil_exception.h两个。
函数库xscugic.h和xscugic_hw.h提供通用中断控制器的操作函数
s32 XScuGic_Connect(XScuGic *InstancePtr, u32 Int_Id,
Xil_InterruptHandler Handler, void *CallBackRef);
连接中断源的中断号和中断程序
void XScuGic_Enable(XScuGic *InstancePtr, u32 Int_Id);
使能中断控制器关联的中断号中断。
函数库xil_exception.h提供异常处理的操作函数
extern void Xil_ExceptionInit(void);
初始化异常处理程序
extern void Xil_ExceptionRegisterHandler(u32 Exception_id,
Xil_ExceptionHandler Handler,
void *Data);
注册异常处理程序
Xil_ExceptionEnable();
使能IRQ异常
参考
UG585:Zynq-7000 SoC Technical Reference Manual







![vivado 仿真报错:ERROR: [VRFC 10-2987] ‘xxxxx‘ is not compiled in library ‘xil_defaultlib‘](https://img-blog.csdnimg.cn/ddc42048c6a24cb0a0756b7c8145efb6.png)
![仿真出现[VRFC 10-2263] Analyzing Verilog fileinto library xil_defaultlib](https://img-blog.csdnimg.cn/2f3e466be6fd45df81f6f904a77516e9.png)








