要想正確地執(zhí)行2440的外部中斷,一般需要完成兩個(gè)部分內(nèi)容:中斷初始化和中斷處理函數(shù)。 在具體執(zhí)行中斷之前,要初始化好要用的中斷。2440的外部中斷引腳EINT與通用IO引腳F和G復(fù)用,要想使用中斷功能,就要把相應(yīng)的引腳配置成中斷模式,如我們想把端口F0設(shè)置成外部中斷,而其他引腳功能不變,則GPFCON=(GPFCON & ~0x3) | 0x2。配置完引腳后,還需要配置具體的中斷功能。我們要打開某一中斷的屏蔽,這樣才能響應(yīng)該中斷,相對(duì)應(yīng)的寄存器為INTMSK;還要設(shè)置外部中斷的觸發(fā)方式,如低電平、高電平、上升沿、下降沿等,相對(duì)應(yīng)的寄存器為EXTINTn。另外由于EINT4到EINT7共用一個(gè)中斷向量,EINT8到EINT23也共用一個(gè)中斷向量,而INTMSK只負(fù)責(zé)總的中斷向量的屏蔽,要具體打開某一具體的中斷屏蔽,還需要設(shè)置EINTMASK。上面介紹的是最基本的初始化,當(dāng)然還有一些其他的配置,如當(dāng)需要用到快速中斷時(shí),要使用INTMOD,當(dāng)需要配置中斷優(yōu)先級(jí)時(shí),要使用PRIORITY等。
中斷處理函數(shù)負(fù)責(zé)執(zhí)行具體的中斷指令,除此以外還需要把SRCPND和INTPND中的相應(yīng)的位清零(通過置1來清零),因?yàn)楫?dāng)中斷發(fā)生時(shí),2440會(huì)自動(dòng)把這兩個(gè)寄存器中相對(duì)應(yīng)的位置1,以表示某一中斷發(fā)生,如果不在中斷處理函數(shù)內(nèi)把它們清零,系統(tǒng)會(huì)一直執(zhí)行該中斷函數(shù)。另外還是由于前面介紹過的,有一些中斷是共用一個(gè)中斷向量的,而一個(gè)中斷向量只能有一個(gè)中斷執(zhí)行函數(shù),因此具體是哪個(gè)外部中斷,還需要EINTPEND來判斷,并同樣還要通過置1的方式把相應(yīng)的位清零。一般來說,使用__irq這個(gè)關(guān)鍵詞來定義中斷處理函數(shù),這樣系統(tǒng)會(huì)為我們自動(dòng)保存一些必要的變量,并能夠在中斷處理函數(shù)執(zhí)行完后正確地返回。還需要注意的是,中斷處理函數(shù)不能有返回值,也不能傳遞任何參數(shù)。
為了把這個(gè)中斷處理函數(shù)與在2440啟動(dòng)文件中定義的中斷向量表相對(duì)應(yīng)上,需要先定義中斷入口地址變量,該中斷入口地址必須與中斷向量表中的地址一致,然后把該中斷處理函數(shù)的首地址傳遞給該變量,即中斷入口地址。
下面就是一個(gè)外部中斷的實(shí)例。開發(fā)板上一共有四個(gè)按鍵,分別連到了EINT0,EINT1,EINT2和EINT4,我們讓這四個(gè)按鍵分別控制連接在B5~B8引腳上的四個(gè)LED:按一下鍵則LED亮,再按一下則滅:
#define _ISR_STARTADDRESS 0x33ffff00
#define U32 unsigned int
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))
#define pISR_EINT1 (*(unsigned *)(_ISR_STARTADDRESS+0x24))
#define pISR_EINT2 (*(unsigned *)(_ISR_STARTADDRESS+0x28))
#define pISR_EINT4_7 (*(unsigned *)(_ISR_STARTADDRESS+0x30))
#define rSRCPND (*(volatile unsigned *)0x4a000000) //Interrupt request status
#define rINTMSK (*(volatile unsigned *)0x4a000008) //Interrupt mask control
#define rINTPND (*(volatile unsigned *)0x4a000010) //Interrupt request status
#define rGPBCON (*(volatile unsigned *)0x56000010) //Port B control
#define rGPBDAT (*(volatile unsigned *)0x56000014) //Port B data
#define rGPBUP (*(volatile unsigned *)0x56000018) //Pull-up control B
#define rGPFCON (*(volatile unsigned *)0x56000050) //Port F control
#define rEXTINT0 (*(volatile unsigned *)0x56000088) //External interrupt control register 0
#define rEINTMASK (*(volatile unsigned *)0x560000a4) //External interrupt mask
#define rEINTPEND (*(volatile unsigned *)0x560000a8) //External interrupt pending
static void __irq Key1_ISR(void) //EINT1
{
int led;
rSRCPND = rSRCPND | (0x1<<1);
rINTPND = rINTPND | (0x1<<1);
led = rGPBDAT & (0x1<<5);
if (led ==0)
rGPBDAT = rGPBDAT | (0x1<<5);
else
rGPBDAT = rGPBDAT & ~(0x1<<5);
}
static void __irq Key2_ISR(void) //EINT4
{
int led;
rSRCPND = rSRCPND | (0x1<<4);
rINTPND = rINTPND | (0x1<<4);
if(rEINTPEND&(1<<4))
{
rEINTPEND = rEINTPEND | (0x1<<4);
led = rGPBDAT & (0x1<<6);
if (led ==0)
rGPBDAT = rGPBDAT | (0x1<<6);
else
rGPBDAT = rGPBDAT & ~(0x1<<6);
}
}
static void __irq Key3_ISR(void) //EINT2
{
int led;
rSRCPND = rSRCPND | (0x1<<2);
rINTPND = rINTPND | (0x1<<2);
led = rGPBDAT & (0x1<<7);
if (led ==0)
rGPBDAT = rGPBDAT | (0x1<<7);
else
rGPBDAT = rGPBDAT & ~(0x1<<7);
}
void __irq Key4_ISR(void) //EINT0
{
int led;
rSRCPND = rSRCPND | 0x1;
rINTPND = rINTPND | 0x1;
led = rGPBDAT & (0x1<<8);
if (led ==0)
rGPBDAT = rGPBDAT | (0x1<<8);
else
rGPBDAT = rGPBDAT & ~(0x1<<8);
}
void Main(void)
{
int light;
rGPBCON = 0x015550;
rGPBUP = 0x7ff;
rGPFCON = 0xaaaa;
rSRCPND = 0x17;
rINTMSK = ~0x17;
rINTPND =0x17;
rEINTPEND = (1<<4);
rEINTMASK = ~(1<<4);
rEXTINT0 = 0x20222;
light = 0x0;
rGPBDAT = ~light;
pISR_EINT0 = (U32)Key4_ISR;
pISR_EINT1 = (U32)Key1_ISR;
pISR_EINT2 = (U32)Key3_ISR;
pISR_EINT4_7 = (U32)Key2_ISR;
while(1)
;
}
/******************************************************************************************************************************************************************************************************/
1.中斷分兩大類:內(nèi)部中斷和外部中斷。
本文引用地址:
http://www.ex-cimer.com/article/201612/325056.htm2.外部中斷。24個(gè)外部中斷占用GPF0-GPF7(EINT0-EINT7),GPG0-GPG15(EINT8-EINT23)。用這些腳做中斷輸入,則必須配置引腳為中斷,并且不要上拉。具體參考datesheet數(shù)據(jù)手冊(cè)。
寄存器:EXTINT0-EXTINT2:三個(gè)寄存器設(shè)定EINT0-EINT23的觸發(fā)方式。
EINTFLT0-EINTFLT3:控制濾波時(shí)鐘和濾波寬度。
EINTPEND:這個(gè)是中斷掛起寄存器,清除時(shí)要寫1,后面還有幾個(gè)是寫1清除。當(dāng)一個(gè)外部中斷(EINT4-EINT23)發(fā)生后,那么相應(yīng)的位會(huì)被置1。為什么沒有EINT0-EINT3,呵呵,看看SRCPND就知道了,里面沒有EINT4-EINT23的位子(SRCPND第[3]位為EINT4-7組,第[4]位為EINT8-23組),所以有了EINTPENDx用以細(xì)化補(bǔ)充SRCPND。
EINTMASK:這個(gè)簡(jiǎn)單,是屏蔽中斷用的,也就是說位為1時(shí),此次中斷無效。
3.內(nèi)部中斷。內(nèi)部中斷有8個(gè)寄存器,下面逐一來看。
寄存器:SUBSRCPND:當(dāng)一個(gè)中斷發(fā)生后,那么相應(yīng)的位會(huì)被置1,表示一個(gè)中斷發(fā)生了。
INTSUBMSK:與上一個(gè)是一伙的,中斷屏蔽寄存器,具體屏蔽什么,自己看手冊(cè)去吧。
INTMOD:中斷的方式。一個(gè)中斷可以是普通中斷,也可以是快中斷,在這里設(shè)置,但只能有一個(gè)快中斷。
PRIORITY:優(yōu)先級(jí)寄存器,不說了。
SRCPND:當(dāng)一個(gè)中斷發(fā)生后,那么相應(yīng)的位會(huì)被置1,表示一個(gè)或一類中斷發(fā)生了。
INTMSK:中斷屏蔽寄存器。
INTPND:中斷發(fā)生后,SRCPND中會(huì)有位置1,可能好幾個(gè)(因?yàn)橥瑫r(shí)可能發(fā)生幾個(gè)中斷),這些中斷會(huì)由優(yōu)先級(jí)仲裁器選出一個(gè)最緊迫的,然后把INTPND中相應(yīng)位置1,所以同一時(shí)間只有一位是1。也就是說前面的寄存器置1是表示發(fā)生了,只有INTPND置1,CPU才會(huì)處理。
INTOFFSET:用來表示INTPND中哪一位置1了,好讓你查詢,普通中斷跳轉(zhuǎn)時(shí)查詢用。清除INTPND、SRCPND時(shí)自動(dòng)清除。
4.各寄存器關(guān)系:
下面看圖說明:
5.中斷過程。
a如果是不帶子中斷的內(nèi)部中斷:發(fā)生后SRCPND相應(yīng)位置1,如果沒有被INTMSK屏蔽,那么等待進(jìn)一步處理。
b如果是帶子中斷的內(nèi)部中斷:發(fā)生后SUBSRCPND相應(yīng)位置1,如果沒有被INTSUBMSK屏蔽,那么SRCPND相應(yīng)位置1,等待進(jìn)一步處理,幾個(gè)SUBSRCPND可能對(duì)應(yīng)同一個(gè)SRCPND,對(duì)應(yīng)表如下:
SRCPND SUBSRCPND
INT_UART0 INT_RXD0,INT_TXD0,INT_ERR0
INT_UART1 INT_RXD1,INT_TXD1,INT_ERR1
INT_UART2 INT_RXD2,INT_TXD2,INT_ERR2
INT_ADC INT_ADC_S, INT_TC
INT_CAM INT_CAM_C, INT_CAM_P
INT_WDT_AC97 INT_WDT, INT_AC97
c如果是外部中斷:EINT0-EINT3發(fā)生后SRCPND相應(yīng)位置1,如果沒有被INTMSK屏蔽,那么等待進(jìn)一步處理。EINT4-EINT23發(fā)生后EINTPEND相應(yīng)位置1,如果沒有被EINTMASK屏蔽,那么SRCPND相應(yīng)位EINT4-7或EINT8-23置1,如果沒有被INTMSK屏蔽,等待進(jìn)一步處理。幾個(gè)EINTPEND對(duì)應(yīng)同一個(gè)SRCPND,對(duì)應(yīng)表如下:
SRCPND EINTPEND
EINT0 EINT0
EINT1 EINT1
EINT2 EINT2
EINT3 EINT3
EINT4-7 EINT4 EINT5EINT6EINT7
EINT8-23 EINT8 EINT9EINT10EINT11……EINT23
三種中斷都等待進(jìn)一步處理了。接下來從SRCPND往下看,看INTMSK。如果中斷被屏蔽了,就不用說了。如果沒有被屏蔽,那么會(huì)進(jìn)一步到INTMOD。如果是快中斷,那么直接出來,進(jìn)入FIQ(即CPU進(jìn)入快中斷模式處理)。如果是普通中斷,那么SRCPND可以有多位為置1(FIQ只能有一個(gè)),這時(shí)就會(huì)經(jīng)過PRIORITY選出一個(gè)優(yōu)先級(jí)高的,然后把根據(jù)選出的中斷把INTPND相應(yīng)位置1(注意:只能選出一個(gè)),進(jìn)入IRQ,讓CPU處理。
6.中斷的開啟。
a.如果是不帶子中斷的內(nèi)部中斷,只需設(shè)置INTMSK,讓它不屏蔽中斷就可以了。
b如果是帶子中斷的內(nèi)部中斷,需設(shè)置INTSUBMSK和INTMSK,讓它們不屏蔽中斷就可以了。
c如果是外部中斷,對(duì)于EINT8-23需要設(shè)置EINTMASK和INTMSK。對(duì)于EINT0-EINT3只需設(shè)置INTMSK。
7.中斷的清除。
a.如果是不帶子中斷的內(nèi)部中斷,只需清除SRCPND,注意清除需位置1。
b如果是帶子中斷的內(nèi)部中斷,需清除SRCPND和SUBSRCPND,注意先清除SUBSRCPND,再清除SRCPND。因?yàn)?,如果你先清除SRCPND的話,然后在清除SUBSRCPND的過程中,SRCPND會(huì)以為又有中斷發(fā)生,又會(huì)置1。也就是說一次中斷會(huì)響應(yīng)兩次。所以必須先掐斷源頭。
c如果是外部中斷,對(duì)于EINT8-23需要清除EINTPEND和SRCPND(同樣注意順序)。對(duì)于EINT0-EINT3只需清除SRCPND。
本文詳細(xì)分析了S3C2440的中斷寄存器,對(duì)arm初學(xué)者有一定的幫助。
評(píng)論