__irq為一個(gè)標識,用來(lái)表示一個(gè)函數是否為中斷函數。對于不同的編譯器,__irq在函數名中的位置不一樣,例如:ADS編譯器中: void __irq IRQ_Eint0(void);
Keil編譯器中 : void IRQ_Eint0(void) __irq;
但是其意義一樣,它所完成的任務(wù)是標識該函數為中斷函數,在編譯器編譯是調用此函數時(shí),先保護函數入口現場(chǎng),然后執行中斷函數,函數執行完畢,恢復中斷現場(chǎng),這整個(gè)過(guò)程不需要用戶(hù)重新編寫(xiě)代碼來(lái)完成,由編譯器自動(dòng)完成。因而這也給不具備中斷嵌套功能的ARM系統帶來(lái)了問(wèn)題,若使用 __irq 時(shí)有中斷嵌套產(chǎn)生,這現場(chǎng)保護就會(huì )混亂。中斷嵌套處理可以自己編寫(xiě)中斷入口現場(chǎng)保護代碼,并不使用 __irq 標識符號。(小呆:具體如何編寫(xiě)可以嵌套的中斷這里暫時(shí)不做研究。
總結如下
1、若不想自己編寫(xiě)中斷入口現場(chǎng)保護代碼,而且使用中無(wú)中斷嵌套,在中斷函數中用 __irq 來(lái)標識我們的中斷函數,否則出錯;
2、若程序中要使用中斷嵌套,對于無(wú)中斷嵌套功能的ARM來(lái)說(shuō),一定要自己編寫(xiě)中斷入口現場(chǎng)保護代碼,而且不能用 __irq 標識我們的中斷函數,否則出錯。
__irq關(guān)鍵字
在A(yíng)DS編譯器中,“__irq”專(zhuān)門(mén)用來(lái)聲明IRQ中斷服務(wù)程序,如果用“__irq”來(lái)聲明一個(gè)函數,那么該函數表示一個(gè)IRQ中斷服務(wù)程序,編譯器便會(huì )自動(dòng)在該函數內部增加中斷現場(chǎng)保護的代碼。同樣一個(gè)函數,如果將關(guān)鍵字“__irq”去掉,那么編譯器便不會(huì )增加現場(chǎng)保護的代碼,而只是作為一個(gè)普通函數來(lái)處理。
現在大家應該對“__irq”關(guān)鍵字有了一定的了解,那么,是不是所有的IRQ中斷服務(wù)程序都需要使用“__irq”關(guān)鍵字聲明呢?其實(shí),這取決于獲取“中斷服務(wù)程序地址”的方法:
如果在執行中斷服務(wù)函數之前沒(méi)有對中斷現場(chǎng)進(jìn)行保護,那么中斷服務(wù)函數必須要使用“__irq”關(guān)鍵字進(jìn)行聲明。例如,在0x0000 0018處執行指令“LDR PC, [PC, #-0xff0]”,此時(shí)對應的中斷服務(wù)函數必須要使用“__irq”關(guān)鍵字進(jìn)行聲明;如果在執行中斷服務(wù)函數之前已經(jīng)對中斷現場(chǎng)進(jìn)行了保護,那么中斷服務(wù)函數不能使用“__irq”關(guān)鍵字進(jìn)行聲明。
本文引用地址:http://dyxdggzs.com/article/201611/321676.htm
//=========================================
// NAME: main.c
// DESC: 內部定時(shí)器4LED燈延時(shí)
//=========================================
#define U32 unsigned int
#define _ISR_STARTADDRESS 0x33ffff00
#define pISR_TIMER4(*(unsigned *)(_ISR_STARTADDRESS+0x58))
#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 rTCFG0(*(volatile unsigned *)0x51000000)//Timer 0 configuration
#define rTCFG1(*(volatile unsigned *)0x51000004)//Timer 1 configuration
#define rTCON(*(volatile unsigned *)0x51000008)//Timer control
#define rTCNTB4 (*(volatile unsigned *)0x5100003c)//Timer count buffer 4
#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
void led_init(void)
{
//板載LED為GPB[5:8]
rGPBCON = (rGPBCON & ~(0xff<<10)) | (0x55<<10);//rGPBCON為01 配置為輸出
rGPBUP= rGPBUP| (0xf<<5);//rGPBUP為1禁止上拉
rGPBDAT = rGPBDAT | (0xf<<5);//LED燈全關(guān)
}
void led_display(unsigned char data)
{
//0x0全滅 0xf全亮 0x01 0x02 0x04 0x80 各自燈亮
rGPBDAT = (rGPBDAT & ~(0xf<<5)) | ((~data) <<5);
}
void timer4_init(void)
{
rSRCPND = rSRCPND | (0x1<<14);//清空定時(shí)器4源請求
rINTPND = rINTPND | (0x1<<14); //清空定時(shí)器4中斷請求
rINTMSK =rINTMSK & ~(0x1<<14);//打開(kāi)定時(shí)器4中斷
//定時(shí)器配制寄存器0
//定時(shí)器輸入時(shí)鐘頻率 = PCLK / {預分頻值+1} / {分頻值}
//{預分頻值} = 0~255 {分頻值} = 2, 4, 8, 16
//25KHz:50MHz/(250*8)=50MHz/(2000)
rTCFG0 = (rTCFG0 & ~(0xff<<8)) | (249<<8);// prescaler1:249
rTCFG1 = (rTCFG1 & ~(0xf<<16)) | (0x2<<16);//divider:8,0b0010
rTCNTB4 = 25000;//讓定時(shí)器4每隔1秒中斷一次 25000=1*25000
rTCON = (rTCON & ~(0x7<<20)) | (0x7<<20);//自動(dòng)重載、手動(dòng)更新、啟動(dòng)定時(shí)器4
rTCON = (rTCON & ~(0x2<<20));//關(guān)閉手動(dòng)更新
}
void __irq timer4_ISR(void)
{
static int count;
rSRCPND = rSRCPND | (0x1<<14);
rINTPND = rINTPND | (0x1<<14);
//每隔0.5秒LED燈亮一次
if (count == 0)
{
led_display(0xf);//LED亮
count = 1;
}
else if (count == 1)
{
led_display(0x0);//LED滅
count = 0;
}
}
void Main(void)
{
led_init();
timer4_init();
pISR_TIMER4 = (U32)timer4_ISR;
while(1);
}
-------------------------------------
pISR_UNDEF=(unsigned)HaltUndef;
任何地址都可以看作變量的指針.pISR_UNDEF就相當于一個(gè)指針變量.pISR_UNDEF=(unsigned)HaltUndef;等于把函數HaltUndef的地址存到這個(gè)指針變量里.也就是說(shuō)_ISR_STARTADDRESS+0x4這個(gè)地址里存放著(zhù)HaltUndef的地址.這段代碼的目的是給中斷函數賦值.當發(fā)生中斷時(shí),系統會(huì )去pISR_UNDEF定義的地址里取出中斷函數的地址也就是HaltUndef的地址,然后執行.就相當于當發(fā)生中斷時(shí),執行HaltUndef函數.
評論