Wince外部中斷控制LED詳解動(dòng)態(tài)申請(qǐng)
1.中斷分兩大類(lèi):內(nèi)部中斷和外部中斷。
本文引用地址:http://m.butianyuan.cn/article/201611/318685.htm外部中斷:由外部設(shè)備所引發(fā)的中斷,這些外部中斷都是通過(guò)GPIO中的中斷引腳產(chǎn)生的。S3C2440有24個(gè)外部中斷,相關(guān)的寄存器如下:
EXTINT0-EXTINT2:三個(gè)寄存器設(shè)定EINT0-EINT23的觸發(fā)方式。
EINTFLT0-EINTFLT3:控制濾波時(shí)鐘和濾波寬度。
EINTPEND:中斷掛起寄存器
EINTMASK:中斷屏蔽寄存器
內(nèi)部中斷:內(nèi)部中斷是有CPU內(nèi)部器件產(chǎn)生的中斷,如定時(shí)器中斷,USB中斷,UART中斷等。相關(guān)的寄存器如下:
SUBSRCPND:次級(jí)中斷掛起寄存器。
INTSUBMSK:次級(jí)中斷屏蔽寄存器。
INTMOD:中斷方式寄存器
PRIORITY :優(yōu)先級(jí)寄存器
SRCPND :中斷掛起寄存器
INTMSK :中斷屏蔽寄存器。
INTPND :中斷發(fā)生后,SRCPND中會(huì)有位置1,可能好幾個(gè),這些中斷會(huì)由優(yōu)先級(jí)仲裁器選出一個(gè)優(yōu)先級(jí)最高的,然后INTPND中相應(yīng)位置1,同一時(shí)間只有一位是1。
這里要注意一級(jí)中斷和次級(jí)中斷的區(qū)別,次級(jí)中斷的設(shè)置要比一級(jí)中斷復(fù)雜一些。
2.WINCE中斷機(jī)制:ISR和IST
WINCE中斷從大的方面分為ISR和IST兩部分,具體ISR,IST是什么這里就不詳說(shuō)了,網(wǎng)上一搜一大把。簡(jiǎn)單的說(shuō)是ISR負(fù)責(zé)把IRQ轉(zhuǎn)化為邏輯中斷并返回給內(nèi)核;IST則負(fù)責(zé)中斷的邏輯處理。
3.WINCE中斷實(shí)例:外部按鍵中斷控制LED燈
(1)創(chuàng)建一個(gè)簡(jiǎn)單的流驅(qū)動(dòng)模板,這一步可以手動(dòng)創(chuàng)建,也可以通過(guò)"Windows CE Developer Samples" -> "Windows CE 5.0 Embedded Development Labs" -> "DrvWiz.exe" 框架產(chǎn)生。建議采用后者,簡(jiǎn)單快捷,不易出錯(cuò)。這里工程命名為LED,即生產(chǎn)的DLL為L(zhǎng)ED_DLL。
(2)填充函數(shù)體。這里主要介紹與中斷相關(guān)的兩個(gè)函數(shù):
DWORD LED_Init( LPCTSTR pContext)//驅(qū)動(dòng)初始化函數(shù),主要做內(nèi)存的分配和調(diào)用中斷初始化函數(shù)。
DWORD WINAPI LED_IST( LPVOID lpvParam ) //中斷處理線(xiàn)程,即IST,在這里進(jìn)行中斷處理.
DWORD InitInterrupt( void ) //中斷初始化函數(shù),包括中斷寄存器的設(shè)置,事件和線(xiàn)程的創(chuàng)建,初始化等。
首先介紹DWORD InitInterrupt( void ),代碼如下:
DWORD InitInterrupt( void )
{
HANDLE g_htIST; //線(xiàn)程返回句柄
BOOL fRetVal;
DWORD dwThreadID;
printfmsg((TEXT("come into the setup interrupt!!!rn")));
//初始化外部中斷8
s2440IO->rGPGCON &= ~(0X3);
s2440IO->rGPGCON |= 0X2;//設(shè)置為中斷模式
s2440IO->rEXTINT1 &= ~(0X0f);
s2440IO->rEXTINT1 |= 0XA; //下降沿觸發(fā),使能濾波器
s2440IO->rEINTMASK &= ~(1<<8);//打開(kāi)中斷 8
s2440IO->rEINTPEND |= (1<<8);//清除中斷
//GPIO 設(shè)置-LED
s2440IO->rGPBCON = (s2440IO->rGPBCON &~(3 << 14)) | (1<< 14); // GPB7 == OUTPUT.
s2440IO->rGPBCON = (s2440IO->rGPBCON &~(3 << 16)) | (1<< 16); // GPB8 == OUTPUT.
s2440INTR->rINTMSK &= ~(0x20); //取消外部中斷8的屏蔽
s2440INTR->rSRCPND |= (0x20); //清除外部中斷8
s2440INTR->rINTPND |=0X20; //清除外部中斷,即初始化
// Create an event
// 創(chuàng)建一個(gè)事件
g_hevInterrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
if(!g_hevInterrupt) return -10;
// Have the OAL Translate the IRQ to a system irq
//將物理中斷IRQ轉(zhuǎn)換為邏輯中斷
fRetVal = KernelIoControl( IOCTL_HAL_TRANSLATE_IRQ,
&dwIrq,
sizeof( dwIrq ),
&g_dwSysInt,
sizeof( g_dwSysInt ),
NULL );
if( !fRetVal )
{ return -1 }
// Create a thread that waits for signaling
// 創(chuàng)建中斷服務(wù)線(xiàn)程IST
g_htIST = CreateThread(NULL,// CE Has No Security
0, // No Stack Size
ThreadIST,// Interrupt Thread
NULL,// No Parameters
CREATE_SUSPENDED,// Create Suspended until we are done
&dwThreadID // Thread Id
);
if( !g_htIST )
{return -1 }
// Set the thread priority to real time
// 設(shè)置線(xiàn)程的優(yōu)先級(jí)
int m_nISTPriority = 7;
if(!CeSetThreadPriority( g_htIST, m_nISTPriority))
{ return -1 }
// Initialize the interrupt
// 初始化中斷,將邏輯中斷號(hào)與事件關(guān)聯(lián),即中斷產(chǎn)生時(shí)觸發(fā)該事件
//在中斷服務(wù)線(xiàn)程IST中會(huì)等該事件的發(fā)生,即WaitForSingleObject(g_hevInterrupt, INFINITE);
//從而中斷發(fā)生就導(dǎo)致IST運(yùn)行,處理中斷任務(wù)
if ( !InterruptInitialize(g_dwSysInt, g_hevInterrupt, NULL, 0) )
{return -1; }
ResumeThread( g_htIST );
printfmsg((TEXT("*leave the setup interrupt!!!rn")));
return 1;
}
簡(jiǎn)單說(shuō)一下初始化中斷的流程,首先是初始化相關(guān)的中斷寄存器,我這里采用的是外部中斷8。接下來(lái)是創(chuàng)建一個(gè)事件,用于關(guān)聯(lián)外部中斷8和IST線(xiàn)程。在IST中會(huì)通過(guò)dwStatus = WaitForSingleObject(g_hevInterrupt, INFINITE)來(lái)等待中斷的發(fā)生。然后利用KernelIoControl( IOCTL_HAL_TRANSLATE_IRQ,
&dwIrq, sizeof( dwIrq ), &g_dwSysInt, sizeof( g_dwSysInt ), NULL ); 將物理中斷IRQ轉(zhuǎn)換為邏輯中斷。這是給內(nèi)核用的。接著就要?jiǎng)?chuàng)建中斷服務(wù)線(xiàn)程了:g_htIST = CreateThread(NULL,// CE Has No Security
0, // No Stack Size
ThreadIST,// Interrupt Thread
NULL,// No Parameters
CREATE_SUSPENDED,// Create Suspended until we are done
&dwThreadID // Thread Id
);
這些都做好以后就可以初始化中斷了.
// Initialize the interrupt
// 初始化中斷,將邏輯中斷號(hào)與事件關(guān)聯(lián),即中斷產(chǎn)生時(shí)觸發(fā)該事件
//在中斷服務(wù)線(xiàn)程IST中會(huì)等該事件的發(fā)生,即WaitForSingleObject(g_hevInterrupt, INFINITE);
//從而中斷發(fā)生就導(dǎo)致IST運(yùn)行,處理中斷任務(wù)
InterruptInitialize(g_dwSysInt, g_hevInterrupt, NULL, 0) 該函數(shù)就將物理中斷對(duì)應(yīng)的邏輯中斷號(hào)和事件關(guān)聯(lián)起來(lái)了。
到這里整個(gè)初始化就做好了,這其中的函數(shù)調(diào)用順序不是唯一的,但只要理清各個(gè)函數(shù)的調(diào)用順序就行了。
DWORD TST_Init( LPCTSTR pContext)
{
printfmsg((TEXT("come into the init!!!rn")));
// GPIO Virtual alloc
s2440IO = (volatile IOPreg *) VirtualAlloc(0,sizeof(IOPreg),MEM_RESERVE, PAGE_NOACCESS);
if(s2440IO == NULL) {
printfmsg((TEXT("For s2440IO: VirtualAlloc faiLED!rn")));
}
else {
if(!VirtualCopy((PVOID)s2440IO,(PVOID)(IOP_BASE),sizeof(IOPreg),PAGE_READWRITE | PAGE_NOCACHE )) {
printfmsg((TEXT("For s2440IO: Virtualcopy faiLED!rn")));
}
}
s2440INTR = (volatile INTreg *) VirtualAlloc(0,sizeof(INTreg ),MEM_RESERVE, PAGE_NOACCESS);
if(s2440INTR == NULL) {
printfmsg((TEXT("For s2440INTR: VirtualAlloc faiLED!rn!rn")));
}
else {
if(!VirtualCopy((PVOID)s2440INTR,(PVOID)(INT_BASE),sizeof(INTreg),PAGE_READWRITE | PAGE_NOCACHE )) {
printfmsg((TEXT("For s2440INTR: Virtualcopy faiLED!rn!rn")));
}
InitInterrupt();
return 0x1234;
}
這個(gè)函數(shù)是在驅(qū)動(dòng)被加載的時(shí)候調(diào)用的,所以要把初始化的任務(wù)放在這里。
與中斷相關(guān)的部分就這么多,這是動(dòng)態(tài)申請(qǐng)中斷的方法,比較復(fù)雜。其實(shí)完全可以不用動(dòng)態(tài)申請(qǐng)的方法,而且不推薦采用此方法。靜態(tài)申請(qǐng)是一種很好的方法,比較簡(jiǎn)單。在后面的文章會(huì)進(jìn)一步講解。
評(píng)論