總結Zynq-7000的PL發送給PS一個中斷請求,為FreeRTOS中斷做准備。
UG585的P225顯示了系統的中斷框圖,如下圖所示。
圖:ZYNQ器件的中斷框圖
UG585的P227畫出來中斷控制器的框圖,如下圖所示。PL 到 PS 部分的中斷經過 ICD 控制器分發器后同時進入 CPU1 和 CPU0。
圖:中斷控制器示意圖
UG585的P57,PL 到 PS 部分一共有 20 個中斷可以使用。 其中 4 個是快速中斷。 如下表所示。
表:PL的中斷信號
ZYNQ的每一個CPU還有16個軟件中斷,Software Generated Interrupts (SGI) ,UG585的P229顯示了SGI,如下圖所示。
表:ZYNQ的軟件中斷SGI
文檔在P229,描述了CPU私有端口中斷CPU Private Peripheral Interrupts (PPI) 和共享中斷Shared Peripheral Interrupts (SPI) ,這些中斷都是固定死的, 不能修改。 PPI中有 2 個 PL 到 每個CPU 的快速中斷 nFIQ ,ID號為28和31(nIRQ)。共享中斷就是 PL 的中斷可以發送給 PS 處理。 這里不再貼圖。
PS的設置如下圖。
Block Design如下圖。
黑金AX7010 開發板的 PL 部分板載了 4 個用戶按鍵(KEY1~KEY4), 按鍵的信號連接到 ZYNQ的 BANK34 和 BANK35 的 IO 上。 按鍵都為低電平有效, 沒有按下時,信號為高;按鍵按下時,信號為低。 4 個用戶按鍵的原理圖如下圖所示。
圖:黑金開發板按鍵原理圖
代碼:
#include <stdio.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 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 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; // 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); // Enable SW1~SW3 interrupts in the controller XScuGic_Enable(&INTCInst, SW1_INT_ID); XScuGic_Enable(&INTCInst, SW2_INT_ID); return XST_SUCCESS; } int main(void) { print("PL int test\n\r"); IntcInitFunction(INTC_DEVICE_ID); while(1); return 0; }