基礎知識
ARM體系架構的處理器中通常將低地址32字節作為中斷向量表,當中斷產生時會執行以下操作:
① 保存處理器當前狀態,設置中斷屏蔽位和各條件標志位
② 設置當前程序狀態寄存器CPSR中相應位
③ 將lr_mode寄存器設置成返回地址
④ 跳轉到中斷向量地址執行,從而跳轉到相應的中斷程序中執行
⑤ 執行中斷處理函數內容
⑥ 恢復被屏蔽的中斷屏蔽位
⑦ 返回到被中斷指令的下一條指令處繼續執行
zynq中低32字節作為中斷向量表,每個中斷占據4字節,這4字節通常存儲一個跳轉指令,從而跳轉到中斷解析程序中。這低32字節中斷向量表如:
選中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
-
ARM
+關注
關注
134文章
9104瀏覽量
367794 -
Zynq
+關注
關注
10文章
610瀏覽量
47193
發布評論請先 登錄
相關推薦
評論