新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應用 > Wince外部中斷控制LED詳解動態(tài)申請

Wince外部中斷控制LED詳解動態(tài)申請

作者: 時間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
本實例是基于S3C2440,WINCE5.0

1.中斷分兩大類:內(nèi)部中斷和外部中斷。

本文引用地址:http://m.butianyuan.cn/article/201611/318685.htm

外部中斷:由外部設(shè)備所引發(fā)的中斷,這些外部中斷都是通過GPIO中的中斷引腳產(chǎn)生的。S3C2440有24個外部中斷,相關(guān)的寄存器如下:

EXTINT0-EXTINT2:三個寄存器設(shè)定EINT0-EINT23的觸發(fā)方式。

EINTFLT0-EINTFLT3:控制濾波時鐘和濾波寬度。

EINTPEND:中斷掛起寄存器

EINTMASK:中斷屏蔽寄存器

內(nèi)部中斷:內(nèi)部中斷是有CPU內(nèi)部器件產(chǎn)生的中斷,如定時器中斷,USB中斷,UART中斷等。相關(guān)的寄存器如下:

SUBSRCPND:次級中斷掛起寄存器。

INTSUBMSK:次級中斷屏蔽寄存器。

INTMOD:中斷方式寄存器

PRIORITY :優(yōu)先級寄存器

SRCPND :中斷掛起寄存器

INTMSK :中斷屏蔽寄存器。

INTPND :中斷發(fā)生后,SRCPND中會有位置1,可能好幾個,這些中斷會由優(yōu)先級仲裁器選出一個優(yōu)先級最高的,然后INTPND中相應位置1,同一時間只有一位是1。

這里要注意一級中斷和次級中斷的區(qū)別,次級中斷的設(shè)置要比一級中斷復雜一些。
2.WINCE中斷機制:ISR和IST

WINCE中斷從大的方面分為ISR和IST兩部分,具體ISR,IST是什么這里就不詳說了,網(wǎng)上一搜一大把。簡單的說是ISR負責把IRQ轉(zhuǎn)化為邏輯中斷并返回給內(nèi)核;IST則負責中斷的邏輯處理。

3.WINCE中斷實例:外部按鍵中斷控制LED

(1)創(chuàng)建一個簡單的流驅(qū)動模板,這一步可以手動創(chuàng)建,也可以通過"Windows CE Developer Samples" -> "Windows CE 5.0 Embedded Development Labs" -> "DrvWiz.exe" 框架產(chǎn)生。建議采用后者,簡單快捷,不易出錯。這里工程命名為LED,即生產(chǎn)的DLL為LED_DLL。

(2)填充函數(shù)體。這里主要介紹與中斷相關(guān)的兩個函數(shù):

DWORD LED_Init( LPCTSTR pContext)//驅(qū)動初始化函數(shù),主要做內(nèi)存的分配和調(diào)用中斷初始化函數(shù)。

DWORD WINAPI LED_IST( LPVOID lpvParam ) //中斷處理線程,即IST,在這里進行中斷處理.

DWORD InitInterrupt( void ) //中斷初始化函數(shù),包括中斷寄存器的設(shè)置,事件和線程的創(chuàng)建,初始化等。

首先介紹DWORD InitInterrupt( void ),代碼如下:

DWORD InitInterrupt( void )
{
HANDLE g_htIST; //線程返回句柄
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);//打開中斷 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_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ù)線程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è)置線程的優(yōu)先級
int m_nISTPriority = 7;
if(!CeSetThreadPriority( g_htIST, m_nISTPriority))
{ return -1 }
// Initialize the interrupt
// 初始化中斷,將邏輯中斷號與事件關(guān)聯(lián),即中斷產(chǎn)生時觸發(fā)該事件
//在中斷服務(wù)線程IST中會等該事件的發(fā)生,即WaitForSingleObject(g_hevInterrupt, INFINITE);
//從而中斷發(fā)生就導致IST運行,處理中斷任務(wù)
if ( !InterruptInitialize(g_dwSysInt, g_hevInterrupt, NULL, 0) )
{return -1; }
ResumeThread( g_htIST );
printfmsg((TEXT("*leave the setup interrupt!!!rn")));

return 1;
}

簡單說一下初始化中斷的流程,首先是初始化相關(guān)的中斷寄存器,我這里采用的是外部中斷8。接下來是創(chuàng)建一個事件,用于關(guān)聯(lián)外部中斷8和IST線程。在IST中會通過dwStatus = WaitForSingleObject(g_hevInterrupt, INFINITE)來等待中斷的發(fā)生。然后利用KernelIoControl( IOCTL_HAL_TRANSLATE_IRQ,
&dwIrq, sizeof( dwIrq ), &g_dwSysInt, sizeof( g_dwSysInt ), NULL ); 將物理中斷IRQ轉(zhuǎn)換為邏輯中斷。這是給內(nèi)核用的。接著就要創(chuàng)建中斷服務(wù)線程了: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
// 初始化中斷,將邏輯中斷號與事件關(guān)聯(lián),即中斷產(chǎn)生時觸發(fā)該事件
//在中斷服務(wù)線程IST中會等該事件的發(fā)生,即WaitForSingleObject(g_hevInterrupt, INFINITE);
//從而中斷發(fā)生就導致IST運行,處理中斷任務(wù)
InterruptInitialize(g_dwSysInt, g_hevInterrupt, NULL, 0) 該函數(shù)就將物理中斷對應的邏輯中斷號和事件關(guān)聯(lián)起來了。

到這里整個初始化就做好了,這其中的函數(shù)調(diào)用順序不是唯一的,但只要理清各個函數(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;

}
這個函數(shù)是在驅(qū)動被加載的時候調(diào)用的,所以要把初始化的任務(wù)放在這里。

與中斷相關(guān)的部分就這么多,這是動態(tài)申請中斷的方法,比較復雜。其實完全可以不用動態(tài)申請的方法,而且不推薦采用此方法。靜態(tài)申請是一種很好的方法,比較簡單。在后面的文章會進一步講解。



評論


技術(shù)專區(qū)

關(guān)閉