基礎(chǔ)知識(shí)
ARM體系架構(gòu)的處理器中通常將低地址32字節(jié)作為中斷向量表,當(dāng)中斷產(chǎn)生時(shí)會(huì)執(zhí)行以下操作:
① 保存處理器當(dāng)前狀態(tài),設(shè)置中斷屏蔽位和各條件標(biāo)志位
② 設(shè)置當(dāng)前程序狀態(tài)寄存器CPSR中相應(yīng)位
③ 將lr_mode寄存器設(shè)置成返回地址
④ 跳轉(zhuǎn)到中斷向量地址執(zhí)行,從而跳轉(zhuǎn)到相應(yīng)的中斷程序中執(zhí)行
⑤ 執(zhí)行中斷處理函數(shù)內(nèi)容
⑥ 恢復(fù)被屏蔽的中斷屏蔽位
⑦ 返回到被中斷指令的下一條指令處繼續(xù)執(zhí)行
zynq中低32字節(jié)作為中斷向量表,每個(gè)中斷占據(jù)4字節(jié),這4字節(jié)通常存儲(chǔ)一個(gè)跳轉(zhuǎn)指令,從而跳轉(zhuǎn)到中斷解析程序中。這低32字節(jié)中斷向量表如:
本內(nèi)容部分修改自《Xilinx Zynq SoC與嵌入式Linux設(shè)計(jì)實(shí)戰(zhàn)指南——兼容ARM Cortex-A9的設(shè)計(jì)方法》
例程
vivado中ps部分配置如下圖:
選中Fabric Interrupts和IRQ_F2P[15:0]
連接如下圖:
其中Concat模塊只是簡(jiǎn)單的將多個(gè)信號(hào)合并為一個(gè)總線連接到zynq;而Utility Vector Logic則是執(zhí)行一些邏輯計(jì)算,這里選擇not邏輯計(jì)算。
#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例程
過(guò)程分析
查看U585第231頁(yè),可以看到從PL部分輸入的中斷號(hào)為{[91:84],[68:61]}對(duì)應(yīng)IRQ_F2P[15:0],這里使用IRQ_F2P[2:0],所以才有SW1_INT_ID到SW3_INT_ID定義為61到63。
分析中斷執(zhí)行要從中斷執(zhí)行開(kāi)始的中斷向量表開(kāi)始,查找.org 0,可以在BSP目錄下/ps7_cortexa9_0/libsrc/standalone_v5_2/src下asm_vectors.s文件中的第64行可以找到,其下便是中斷向量表,作為IRQ中斷,在中斷向量表中為第5條(地址:0x18)指令,對(duì)應(yīng)第77行B IRQHandler,跳轉(zhuǎn)到IRQHandler標(biāo)簽,其后第99行再次跳轉(zhuǎn)到IRQInterrupt,從BSP目錄下/ps7_cortexa9_0/libsrc/standalone_v5_2/src下vectors.c文件中可以找到IRQInterrupt函數(shù),其中調(diào)用XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Handler(XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Data);即IRQ中斷最終調(diào)用了XExc_VectorTable數(shù)組中第XIL_EXCEPTION_ID_IRQ_INT(即5)個(gè)成員的Handler函數(shù),并傳入Data作為參數(shù)。
回到以上例程中有Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&INTCInst);從BSP目錄下/ps7_cortexa9_0/libsrc/standalone_v5_2/src下xil_exception.c中可找到此函數(shù),其將(Xil_ExceptionHandler)XScuGic_InterruptHandler和&INTCInst賦值給XExc_VectorTable第XIL_EXCEPTION_ID_INT(即5)個(gè)成員的Handler和Data成員,結(jié)合上一段中說(shuō)明,則IRQ中斷最終執(zhí)行了: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中可找到此函數(shù),可以看到(其中InstancePtr對(duì)應(yīng)&INTCInst;Int_Id對(duì)應(yīng)SW1_INT_ID;Handler對(duì)應(yīng)SW_intr_Handler;CallBackRef對(duì)應(yīng)1,當(dāng)然其它中斷分別為2,3):
InstancePtr->Config->HandlerTable[Int_Id].Handler = Handler; // 即參數(shù)SW_intr_Handler InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = CallBackRef;// 即參數(shù)1
即將處理函數(shù)(SW_intr_Handler)及其參數(shù)(1)放到&INTCInst中,
再次回到IRQ中斷后會(huì)執(zhí)行的XScuGic_InterruptHandler函數(shù)(在BSP目錄下/ps7_cortexa9_0/libsrc/standalone_v5_2/src下xscugic_intr.c)中有以下語(yǔ)句:
TablePtr = &(InstancePtr->Config->HandlerTable[InterruptID]); if(TablePtr != NULL) { TablePtr->Handler(TablePtr->CallBackRef); }
即當(dāng)TablePtr不為空時(shí)就執(zhí)行了InstancePtr->Config->HandlerTable[InterruptID]->Handler(InstancePtr->Config->HandlerTable[InterruptID]->CallBackRef);結(jié)合上一段說(shuō)明即執(zhí)行了SW_intr_Handler(1)或參數(shù)為2、3。
綜上,IRQ中斷產(chǎn)生后跳轉(zhuǎn)到0x18執(zhí)行B IRQHandler執(zhí)行,在IRQHandler下執(zhí)行bl IRQInterrupt;在函數(shù)IRQInterrupt中XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Handler(XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Data);經(jīng)過(guò)Xil_ExceptionRegisterHandler函數(shù)后即XScuGic_InterruptHandler(&INTCInst)再經(jīng)過(guò)XScuGic_Connect函數(shù)這也即SW_intr_Handler(1)或參數(shù)為2、3。最終IRQ中斷執(zhí)行了SW_intr_Handler函數(shù)。
編輯:hfy
-
ARM
+關(guān)注
關(guān)注
134文章
9027瀏覽量
366484 -
Zynq
+關(guān)注
關(guān)注
9文章
607瀏覽量
47101
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論