电子说
基础知识
ARM体系架构的处理器中通常将低地址32字节作为中断向量表,当中断产生时会执行以下操作:
① 保存处理器当前状态,设置中断屏蔽位和各条件标志位
② 设置当前程序状态寄存器CPSR中相应位
③ 将lr_mode寄存器设置成返回地址
④ 跳转到中断向量地址执行,从而跳转到相应的中断程序中执行
⑤ 执行中断处理函数内容
⑥ 恢复被屏蔽的中断屏蔽位
⑦ 返回到被中断指令的下一条指令处继续执行
zynq中低32字节作为中断向量表,每个中断占据4字节,这4字节通常存储一个跳转指令,从而跳转到中断解析程序中。这低32字节中断向量表如:
本内容部分修改自《Xilinx Zynq SoC与嵌入式Linux设计实战指南——兼容ARM Cortex-A9的设计方法》
例程
vivado中ps部分配置如下图:
选中Fabric Interrupts和IRQ_F2P[15:0]
连接如下图:
其中Concat模块只是简单的将多个信号合并为一个总线连接到zynq;而Utility Vector Logic则是执行一些逻辑计算,这里选择not逻辑计算。
#include#include "platform.h" #include "xscugic.h" #include "xil_exception.h" #define INT_CFG0_OFFSET 0x00000C00 // Parameter definitions #define SW1_INT_ID 61 #define SW2_INT_ID 62 #define SW3_INT_ID 63 #define INTC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID #define INT_TYPE_RISING_EDGE 0x03 #define INT_TYPE_HIGHLEVEL 0x01 #define INT_TYPE_MASK 0x03 static XScuGic INTCInst; static void SW_intr_Handler(void *param); static int InterruptSystemSetup(XScuGic *XScuGicInstancePtr); static int IntcInitFunction(u16 DeviceId); static void SW_intr_Handler(void *param) { int sw_id = (int)param; printf("SW%d int/n/r", sw_id); } void IntcTypeSetup(XScuGic *InstancePtr, int intId, int intType) { int mask; intType &= INT_TYPE_MASK; mask = XScuGic_DistReadReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4); mask &= ~(INT_TYPE_MASK << (intId%16)*2); mask |= intType << ((intId%16)*2); XScuGic_DistWriteReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4, mask); } int IntcInitFunction(u16 DeviceId) { XScuGic_Config *IntcConfig; int status; // Interrupt controller initialisation IntcConfig = XScuGic_LookupConfig(DeviceId); status = XScuGic_CfgInitialize(&INTCInst, IntcConfig, IntcConfig->CpuBaseAddress); if(status != XST_SUCCESS) return XST_FAILURE; // Call to interrupt setup Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &INTCInst); Xil_ExceptionEnable(); // Connect SW1~SW3 interrupt to handler status = XScuGic_Connect(&INTCInst, SW1_INT_ID, (Xil_ExceptionHandler)SW_intr_Handler, (void *)1); if(status != XST_SUCCESS) return XST_FAILURE; status = XScuGic_Connect(&INTCInst, SW2_INT_ID, (Xil_ExceptionHandler)SW_intr_Handler, (void *)2); if(status != XST_SUCCESS) return XST_FAILURE; status = XScuGic_Connect(&INTCInst, SW3_INT_ID, (Xil_ExceptionHandler)SW_intr_Handler, (void *)3); if(status != XST_SUCCESS) return XST_FAILURE; // Set interrupt type of SW1~SW3 to rising edge IntcTypeSetup(&INTCInst, SW1_INT_ID, INT_TYPE_RISING_EDGE); IntcTypeSetup(&INTCInst, SW2_INT_ID, INT_TYPE_RISING_EDGE); IntcTypeSetup(&INTCInst, SW3_INT_ID, INT_TYPE_RISING_EDGE); // Enable SW1~SW3 interrupts in the controller XScuGic_Enable(&INTCInst, SW1_INT_ID); XScuGic_Enable(&INTCInst, SW2_INT_ID); XScuGic_Enable(&INTCInst, SW3_INT_ID); return XST_SUCCESS; } int main(void) { init_platform(); print("PL int test/n/r"); IntcInitFunction(INTC_DEVICE_ID); while(1); cleanup_platform(); return 0; }
例程修改自z-turn例程
过程分析
查看U585第231页,可以看到从PL部分输入的中断号为{[91:84],[68:61]}对应IRQ_F2P[15:0],这里使用IRQ_F2P[2:0],所以才有SW1_INT_ID到SW3_INT_ID定义为61到63。
分析中断执行要从中断执行开始的中断向量表开始,查找.org 0,可以在BSP目录下/ps7_cortexa9_0/libsrc/standalone_v5_2/src下asm_vectors.s文件中的第64行可以找到,其下便是中断向量表,作为IRQ中断,在中断向量表中为第5条(地址:0x18)指令,对应第77行B IRQHandler,跳转到IRQHandler标签,其后第99行再次跳转到IRQInterrupt,从BSP目录下/ps7_cortexa9_0/libsrc/standalone_v5_2/src下vectors.c文件中可以找到IRQInterrupt函数,其中调用XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Handler(XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Data);即IRQ中断最终调用了XExc_VectorTable数组中第XIL_EXCEPTION_ID_IRQ_INT(即5)个成员的Handler函数,并传入Data作为参数。
回到以上例程中有Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&INTCInst);从BSP目录下/ps7_cortexa9_0/libsrc/standalone_v5_2/src下xil_exception.c中可找到此函数,其将(Xil_ExceptionHandler)XScuGic_InterruptHandler和&INTCInst赋值给XExc_VectorTable第XIL_EXCEPTION_ID_INT(即5)个成员的Handler和Data成员,结合上一段中说明,则IRQ中断最终执行了:XScuGic_InterruptHandler(&INTCInst)。
再看以上例程有status = XScuGic_Connect(&INTCInst,SW1_INT_ID,(Xil_ExceptionHandler)SW_intr_Handler,(void *)1);,可以从BSP目录下/ps7_cortexa9_0/libsrc/standalone_v5_2/src下xscugic.c中可找到此函数,可以看到(其中InstancePtr对应&INTCInst;Int_Id对应SW1_INT_ID;Handler对应SW_intr_Handler;CallBackRef对应1,当然其它中断分别为2,3):
InstancePtr->Config->HandlerTable[Int_Id].Handler = Handler; // 即参数SW_intr_Handler InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = CallBackRef;// 即参数1
即将处理函数(SW_intr_Handler)及其参数(1)放到&INTCInst中,
再次回到IRQ中断后会执行的XScuGic_InterruptHandler函数(在BSP目录下/ps7_cortexa9_0/libsrc/standalone_v5_2/src下xscugic_intr.c)中有以下语句:
TablePtr = &(InstancePtr->Config->HandlerTable[InterruptID]); if(TablePtr != NULL) { TablePtr->Handler(TablePtr->CallBackRef); }
即当TablePtr不为空时就执行了InstancePtr->Config->HandlerTable[InterruptID]->Handler(InstancePtr->Config->HandlerTable[InterruptID]->CallBackRef);结合上一段说明即执行了SW_intr_Handler(1)或参数为2、3。
综上,IRQ中断产生后跳转到0x18执行B IRQHandler执行,在IRQHandler下执行bl IRQInterrupt;在函数IRQInterrupt中XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Handler(XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Data);经过Xil_ExceptionRegisterHandler函数后即XScuGic_InterruptHandler(&INTCInst)再经过XScuGic_Connect函数这也即SW_intr_Handler(1)或参数为2、3。最终IRQ中断执行了SW_intr_Handler函数。
编辑:hfy
全部0条评论
快来发表一下你的评论吧 !