本文感謝 ce123 朋友

S3C2440一共有60個中斷源,其中有15個子中斷源,它們與SUBSRCPND寄存器中的每一位相對應,其他45個中斷源與SRCPND中的每一位相對應。要注意的是EINT4~7對應的是同一位SRCPND[4],而EINT8~23對應的也是SRCPND[5]一位。
中斷分兩大類:外部中斷和內部中斷。
24個外部中斷占用GPF0-GPF7(EINT0-EINT7),GPG0-GPG15(EINT8-EINT23)。用這些腳做中斷輸入,則必須配置引腳為中斷,並且不要上拉。具體可參考datesheet數據手冊。
寄存器:
EXTINT0-EXTINT2:分別設置EINT0—EINT7、EINT8—EINT15、EINT16—EINT23的觸發方式(高電平觸發、低電平觸發、下降沿觸發、上升沿觸發)。
EINTFLT0-EINTFLT3:控制濾波時鍾和濾波寬度。
EINTPEND:這個是中斷掛起寄存器,清除時要寫1,后面還有幾個是寫1清除。當一個外部中斷(EINT4-EINT23)發生后,那么相應的位會被置1。為什么沒有EINT0-EINT3,因為它們分別由SRCPND寄存器的后4位控制。
EINTMASK:這個簡單,是屏蔽中斷用的,也就是說位為1時,此次中斷無效。
內部中斷有8個寄存器。
寄存器:
SUBSRCPND:當一個中斷發生后,那么相應的位會被置1,表示一個中斷發生了。
INTSUBMSK:與上一個是一樣的,中斷屏蔽寄存器。
SRCPND:當一個中斷發生后,那么相應的位會被置1,表示一個或一類中斷發生了。
INTMSK:用來屏蔽SRCPND寄存器所標識的中斷。但只能屏蔽IRQ中斷,不能屏蔽FIQ中斷。
INTMOD:當INTMOD中某位被設置為1時,它對應的中斷被設為FIQ,CPU將進入快速中斷模式。
PRIORITY:用於設置IRQ中斷的優先級。具體使用方法可參考芯片手冊。
INTPND:中斷優先級仲裁器選出優先級最高中斷后,這個中斷在INTPND寄存器中的相應位被置1,隨后,CPU進入中斷模式處理它。同一時間內,此寄存器只有一位被置1。
INTOFFSET:用來表示INTPND寄存器中哪位被置1了,即記錄INTPND中位[x]為1的位x的值。清除INTPND、SRCPND時自動清除。
a 如果是不帶子中斷的內部中斷:發生后SRCPND相應位置1,如果沒有被INTMSK屏蔽,那么等待進一步處理。
b 如果是帶子中斷的內部中斷:發生后SUBSRCPND相應位置1,如果沒有被INTSUBMSK屏蔽,那么SRCPND相應位置1,等待進一步處理,幾個SUBSRCPND可能對應同一個SRCPND,對應表如下(P381):

a 如果是外部中斷:EINT0-EINT3發生后SRCPND相應位置1,如果沒有被INTMSK屏蔽,那么等待進一步處理。EINT4-EINT23發生后EINTPEND相應位置1,如果沒有被EINTMASK屏蔽,那么SRCPND相應位EINT4-7 或EINT8-23置1,如果沒有被INTMSK屏蔽,等待進一步處理,幾個EINTPEND對應同一個SRCPND,對應表如下:
三種中斷都等待進一步處理了。接下來從SRCPND往下看,看INTMSK。如果中斷被屏蔽了,就不用說了(注意:快中斷也能被屏蔽)。如果沒有被屏蔽,那么會進一步到INTMOD。如果是快中斷,那么直接出來,進入FIQ(即CPU進入快中斷模式處理)。如果是普通中斷,那么SRCPND可以有多為置1(FIQ只能有一個),這時就會經過PRIORITY選出一個優先級高的,然后把根據選出的中斷把INTPND相應位置1(注意:只能選出一個),進入IRQ,讓CPU處理。
a.如果是不帶子中斷的內部中斷,只需設置INTMSK,讓它不屏蔽中斷就可以了。
b 如果是帶子中斷的內部中斷,需設置INTSUBMSK和INTMSK,讓它們不屏蔽中斷就可以了。
c 如果是外部中斷,對於EINT8-23需要設置EINTMASK和INTMSK。對於EINT0-EINT3只需設置INTMSK。
a.如果是不帶子中斷的內部中斷,只需清除SRCPND,注意清除需位置1。
b 如果是帶子中斷的內部中斷,需清除SRCPND和SUBSRCPND,注意先清除SUBSRCPND,再清除SRCPND。因為,如果你先清除SRCPND的話,然后在清除SUBSRCPND的過程中,SRCPND會以為又有中斷發生,又會置1。也就是說一次中斷會響應兩次。所以必須先掐斷源頭。
c 如果是外部中斷,對於EINT8-23需要清除EINTPEND和SRCPND(同樣注意順序)。對於EINT0-EINT3只需清除SRCPND。
下面來看一段代碼:
void key_init() { rGPGCON &= ~(0x3 << 0); //設置GPGO—EINT[8] rGPGCON |= (0x2 << 0); //設置GPGO—EINT[8] rEXTINT1 &= ~(0xf << 0); //觸發方式為低電平有效 rEINTPEND |= (1 << 8); //清中斷 rEINTMASK &= ~(1 << 8); //允許外部中斷 pISR_EINT8_23 = (U32)Key_handler; //中斷服務程序 EnableIrq(BIT_EINT8_23); //允許中斷(INTMSK) } static void __irq key_handler() { if (rINTPND == BIT_EINT8_23) //INTPND同時只能有一位為1 ClearPending(BIT_EINT8_23); //清SRCPND、INTPND #define BIT_EINT8_23 (0x1 << 5) if (rEINTPEND & (1 << 8)) //清外部中斷EINTPEND rEINTPEND |= 1 << 8; ............ }
結合上面的圖,我們就很清楚的了解哪句代碼清哪個中斷或者設置哪個寄存器,關於底層的細節了解一下是非常有必要的,當然還有幾個寄存器(比如 INTOFFSET)會在后面介紹他們,follow....
設置外部中斷的一般方法是:
1、設置GPIO口功能(挑選GPx組),00:輸入,01:輸出,10:第二功能 P292
2、設置EXTINTx寄存器,設定中斷觸發類型(EXTINT0 — 2) P301
3、設置EINTPND,若發生中斷則某位置1,使用前先清零(寫1清零) P306
4、設置EINTMASK,0表示允許中斷,1表示禁止,默認禁止 P305
5、清IRQ中斷EXTINT8_23屬於IRQ中斷號5,ClearPending(BIT_EINT8_23);
6、設置中斷處理函數,pISR_EINT8_23 = (U32)Key_ISR;
7、允許中斷,EnableIrq(BIT_EINT8_23);
