天天看點

zynq中斷之gpio中斷,emio按鍵中斷詳解(解決重複中斷)

一.概要

    zynq有三種中斷:軟中斷(software interrtpts),私有外設中斷(private peripheral)和共享外設中斷(shared perlpherals)。差別在于私有外設中斷和共享外設中斷含有PL測引入的中斷。*每個中斷都有自己ID号。*有一個中斷控制器(generic interrupt controller)管理着這些中斷的使能,分類,配置設定和優先級。框圖如下圖所示:

zynq中斷之gpio中斷,emio按鍵中斷詳解(解決重複中斷)

①軟中斷:

zynq中斷之gpio中斷,emio按鍵中斷詳解(解決重複中斷)

②私有外設中斷:

    私有外設中斷包括global timer,private time,watchdog。

③共享外設中斷

zynq中斷之gpio中斷,emio按鍵中斷詳解(解決重複中斷)
zynq中斷之gpio中斷,emio按鍵中斷詳解(解決重複中斷)

二.emio按鍵中斷

    中斷初始化有兩種格式,第一種是按照sdk給出的例程的格式,第二種是做了一點小的修改,個人覺得第二種更好用。

1)根據sdk例程的中斷初始化

//初始化異常管理
	Xil_ExceptionInit();
//初始化中斷控制器
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	XScuGic_CfgInitialize(&GicInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);
//連接配接中斷控制器到CPU
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
				(Xil_ExceptionHandler)XScuGic_InterruptHandler,
				&GicInstancePtr);
//連接配接中斷控制器到中斷服務函數(這個很重要,下面要用到)
	XScuGic_Connect(&GicInstancePtr, GpioIntrId,
				(Xil_ExceptionHandler)XGpioPs_IntrHandler,
				&Gpio);
//設定中斷類型
	XGpioPs_SetIntrType(&Gpio, GPIO_BANK, 0x00, 0x00000000, 0x00);
//設定中斷服務函數位址到gpio執行個體資料中
	XGpioPs_SetCallbackHandler(&Gpio, (void *)&Gpio, IntrHandler);
//使能gpio的中斷
	XGpioPs_IntrEnable(&Gpio, GPIO_BANK, (1 << 0));

//使能中斷控制器中的gpio中斷
	XScuGic_Enable(&GicInstancePtr, GpioIntrId);
//使能異常處理
	Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
           

中斷服務函數的位址是通過上面的XGpioPs_SetCallbackHandler()函數添加到GPIO的執行個體資料的,當經過emio的一個按鍵按下觸發中斷時,CPU會轉到下面的函數中參數的Xil_ExceptionHandler)XGpioPs_IntrHandler中去(經過單步調試可以知道)

XScuGic_Connect(&GicInstancePtr, GpioIntrId,
				(Xil_ExceptionHandler)XGpioPs_IntrHandler,
				&Gpio);
           

XGpioPs_IntrHandler函數是塞琳思已經寫好的,内部如下所示

zynq中斷之gpio中斷,emio按鍵中斷詳解(解決重複中斷)

進入XGpioPs_IntrHandler函數以後,又會通過上圖紅色框中的語句跳到中斷服務函數去,中斷服務函數就是這樣被調用的。但是從XGpioPs_IntrHandler函數進入中斷服務函數會有一些小問題,就是中斷服務函數會重複執行好幾次。原因是因為:

zynq中斷之gpio中斷,emio按鍵中斷詳解(解決重複中斷)

如上圖所示,XGpioPs_IntrHandler函數中有有個for 循壞會檢測GPIO的4個bank的中斷狀态,不知道為什麼他這裡的bank0和1的中斷狀态不是0的,是以他就會連續進入好幾次中斷服務函數。為了解決這個問題,我們需要在中斷服務函數中讀取gpio中斷pin的中斷狀态,隻有在對應中斷pinc觸發了才會執行if裡面的語句,示例代碼如下圖所示:

zynq中斷之gpio中斷,emio按鍵中斷詳解(解決重複中斷)

注意:上面if裡面程式我用usleep()代替了按鍵消抖,這裡我想說的是必須要先消抖才能執行下面的中斷清0和屏蔽函數,反過來的話可能會導緻中斷清0失敗。

2)第二種中斷初始化格式

    第二種中斷初始化是把第一種中斷初始化中的XGpioPs_SetCallbackHandler(&Gpio, (void *)&Gpio, IntrHandler)删去,然後把XScuGic_Connect(&GicInstancePtr, GpioIntrId,

(Xil_ExceptionHandler)XGpioPs_IntrHandler,

&Gpio)中的XGpioPs_IntrHandler改為自定義的中斷服務函數的位址。如下圖所示:

zynq中斷之gpio中斷,emio按鍵中斷詳解(解決重複中斷)

這樣中斷觸發的時候,就會直接調用中斷服務函數IntrHandler(),避免了第一種觸發中斷後進入XGpioPs_IntrHandler()中去檢測GPIO的4個bank的中斷狀态,進而導緻連續進入中斷服務函數好幾次。😎