GIC掌管整个中断系统。
前面我们已经分析了PS的两个中断源,GPIO输入源和TIMER中断源。
最灵活的中断是SPIntr,既可以是PL发送给PS,也可以是PS发送给PL。
GIC一共有96个中断源,即,IRQ_ID是从0#95。具体分配如下:
IRQ#0~IRQ#15,分配给了SGIntr.
IRQ#16~IRQ#31,分配给了PPIntr。
IRQ#32~IRQ#95,分配给了SPIntr。
其中,就有我们熟悉的IRQ#52,这是GPIO的中断号。
SPIntr,如果在配置PS7时,配置了中断,那么就会有一组PORT出现在PS和PL的边界上。
PS发送给PL的中断,信号名为IRQP2F[28:0]。
PL发送给PS的中断,信号名为IRQF2P[15:0]。
PL_PS的中断,大体流程与TIMER类似。只到FhSISR就结束了。
BSP中,并没有提供PL_PS的中断模块例程,所以需要我们自己来编写中断模块。
基于SOD设计思想,首先我们需要定义结构体。
先来看一个最简单的例子。
typedef struct{
int i;
char* desc;
}PL0_Intr_ID61;
定义了IRQ#61的RDB。
int PL0_init(PL0_Intr_ID61* ptr, char* s)
{
ptr->i=0;
ptr->desc= s;
return 1;
}
这个函数填充了IRQ#61的RDB。
static void PL0_IntrHandler(void *CallBackRef)
{
PL0_Intr_ID61* IntrID61ptr;
IntrID61ptr= (PL0_Intr_ID61*)CallBackRef;
printf("%s : %d\n",IntrID61ptr->desc,IntrID61ptr->i++);
}
void PL0_Setup_Intr(XScuGic *GicInstancePtr, PL0_Intr_ID61* PL0_Intr_ID61ptr)
{
XScuGic_Connect(GicInstancePtr, 61,
(Xil_ExceptionHandler)PL0_IntrHandler,//set up the PL0 interrupt
(void *)PL0_Intr_ID61ptr);
XScuGic_Enable(GicInstancePtr, 61);//enable the interrupt for the Timer at GIC
XScuGic_SetPriorityTriggerType(GicInstancePtr, 61, 0X90 , 3) ;
}
定义了IRQ#61的IntrHandler,并在GIC中注册这个HandlerVectorEntry。
static XScuGic GIC; //GIC
static PL0_Intr_ID61 PL0_Intr_ID61_inst;
static char PL0_desc[] = "This is PL0 up key " ;
int main()
{
init_platform();
print("Hello World\n\r");
Init_GIC(&GIC);
PL0_init(&PL0_Intr_ID61_inst,PL0_desc);
PL0_Setup_Intr( &GIC,&PL0_Intr_ID61_inst);
//Timer_Setup_Intr(&GIC,&Timer,TIMER_IRPT_INTR);
Exception_Init_Register_Enable();
//XScuTimer_Start(&Timer);
while(1) ;
cleanup_platform();
return 0;
}
这个例子,实现了最基本的中断响应机制。用于EventTrigger。
PL利用这个中断,仅仅是向PS发送一个事件Event,并没有更多的数据。
对于一个良好的SOD程序架构而言,这些并不足够。
我们可以仿照TIMER的设计架构,设计出IRQ#61的模块。
typedef struct{
IRQF2P_ID61_Config intr61_config;
u32 isReady;
char* desc;
}XIRQF2P_ID61;
typedef struct{
u16 DeviceId; /**< Unique ID of device */
u32 BaseAddr; /**< Base address of the device */
}XIRQF2P_ID61_Config;
我们定义了RCB和RDB。
XIRQF2P_ID61_Config* XIRQF2P_ID61_LookupConfig(u16 DeviceId);
s32 XIRQF2P_ID61_CfgInitialize(XIRQF2P_ID61 *InstancePtr,
XIRQF2P_ID61_Config *ConfigPtr, u32 EffectiveAddress);
s32 XIRQF2P_ID61_setRegisterValue(XIRQF2P_ID61 *InstancePtr,
u32 RegisterOffset, u32 Value);
s32 XIRQF2P_ID61_getRegisterValue(XIRQF2P_ID61 *InstancePtr,
u32 RegisterOffset, u32* Value);
根据不同的需要,我们可以补充定义RCB和RDB,也可以补充新的操作函数。