<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > WinCE 5.0邊做邊學(xué)(5)(6)

WinCE 5.0邊做邊學(xué)(5)(6)

作者: 時(shí)間:2011-02-25 來(lái)源:網(wǎng)絡(luò ) 收藏
對于實(shí)時(shí)系統,如何調試是一個(gè)很難解決的問(wèn)題,包括對系統內核的調試,對驅動(dòng)程序的調試,對應用程序的調試等。對于應用程序,通常各集成開(kāi)發(fā)環(huán)境都提供了常規的單步跟蹤等調試手段。而對于另兩個(gè)的調試,Platform Builder除了為我們提供了常規的斷點(diǎn)跟蹤等手段以外,還和系統的源程序配合使用了一種新的調試手段——Debug Zones調試區。
通常,我們都是利用OutpubDebugString函數來(lái)實(shí)現調試信息的輸出的,但是由于系統底層的調試信息非常繁多,如果這樣大量的調試信息用于實(shí)時(shí)輸出的話(huà)一定會(huì )影響到系統的性能和實(shí)時(shí)性,也就影響到了系統的運行。如果有一種方式能允許開(kāi)發(fā)人員自己選擇輸出哪些調試信息,不輸出哪些調試信息的話(huà),那么就可以讓開(kāi)發(fā)人員只看到關(guān)心的調試信息,而把諸如鍵盤(pán)按鍵、鼠標移動(dòng)等無(wú)用的調試信息隱去,則可以更好的提高開(kāi)發(fā)效率,迅速找到問(wèn)題所在。
調試區就是為了解決以上提出的問(wèn)題的,對某一個(gè)驅動(dòng)程序,它規定好自己向外輸出的調試信息的分類(lèi),比如初始化時(shí)的信息,出錯時(shí)的信息,釋放時(shí)的信息,激活時(shí)的信息等,然后分成幾個(gè)調試區,在現有的CE版本中最多允許16個(gè)調試區。開(kāi)發(fā)人員通過(guò)Platform Builder中Target菜單下的CE Debug Zones命令來(lái)決定想要得到哪一個(gè)或哪幾個(gè)調試區的信息,在驅動(dòng)程序中則可以根據開(kāi)發(fā)人員的選擇來(lái)輸出指定調試區的信息。這就是調試區大體上的工作原理。
接下來(lái),我們就來(lái)看一下調試區的定義,聲明,注冊及使用。
在程序中使用調試區之前必須先定義它們,一個(gè)程序的16個(gè)調試區編號分別為0-15。代碼樣例如下所示:
#ifdef DEBUG
//
// For debug builds, use the real zones.
//
#define ZONE_TEST DEBUGZONE(0)
#define ZONE_PARAMS DEBUGZONE(1)
#define ZONE_VERBOSE DEBUGZONE(2)
……
#define ZONE_WARN DEBUGZONE(14)
#define ZONE_ERROR DEBUGZONE(15)

#else
//
// For retail builds, use forced messages based on the zones turned on below.
//
#define ZONE_TEST 0
#define ZONE_PARAMS 0
#define ZONE_VERBOSE 0
……
#define ZONE_WARN 0
#define ZONE_ERROR 0

#endif

這樣,就可以程序的DEBUG版本中使用調試區了,而在RELEASE版本中則將其全部定義為0,調試信息即不再輸出。
在程序中,除了以上的定義以外,還要聲明幾個(gè)專(zhuān)用的調試信息輸出函數,這些函數與OutputDebugString函數的區別就在于在調用時(shí)需要指定對應的調試區,這些函數以及以上用到的DEBUGZONE宏的定義都在DbgApi.h頭文件中,因此只要在源程序中包含此頭文件即可。除此以外,還需要一個(gè)全局的DEBPARAM類(lèi)型的變量命名為dpCurSettings,以供集成開(kāi)發(fā)環(huán)境和調試信息輸出函數使用。其代碼樣例如下:
#ifdef DEBUG
DBGPARAM dpCurSettings = {
TEXT("WaveDriver"), {
TEXT("Test") // 0
,TEXT("Params") // 1
,TEXT("Verbose") // 2
,TEXT("Interrupt") // 3
,TEXT("WODM") // 4
,TEXT("WIDM") // 5
,TEXT("PDD") // 6
,TEXT("MDD") // 7
,TEXT("Regs") // 8
,TEXT("Misc") // 9
,TEXT("Init") // 10
,TEXT("IOcontrol") // 11
,TEXT("Alloc") // 12
,TEXT("Function") // 13
,TEXT("Warning") // 14
,TEXT("Error") // 15
}
,
(1 15) // Errors
| (1 14) // Warnings
};
#endif
此例中還把ERROR和WARN調試區作為默認被開(kāi)發(fā)人員選中的調試區。
要想使用調試區,還需要做的最后一件準備的事情就是在程序中進(jìn)行注冊,也就是在程序啟動(dòng)時(shí)通知集成開(kāi)發(fā)環(huán)境本程序中要使用調試區,這個(gè)注冊很簡(jiǎn)單,只要在程序的入口處使用DEBUGREGISTER宏即可,樣例如下:
DllEntry (
HANDLE hinstDLL,
DWORD Op,
LPVOID lpvReserved
)
{
switch (Op) {

case DLL_PROCESS_ATTACH :
DEBUGREGISTER((HINSTANCE)hinstDLL);
break;
……
至于調試區的使用,完全是幾個(gè)宏的使用而已,我想做程序的人都會(huì )用的,常用的宏如下:
DEBUGMSG(),DEBUGLED(),RETAILMSG(),RETAILLED(),ERRORMSG(),DEBUGCHK()

好了,調試區就概要的說(shuō)了這么多,如此復雜的機制在自己的程序中寫(xiě)起來(lái)是煩瑣了點(diǎn),不過(guò)如果你需要的話(huà),可以從CE現有的例程序中復制過(guò)來(lái),這樣就省了很多麻煩事,也不會(huì )出錯。下圖是在PB中使用調試區的截圖,當選中某一個(gè)調試區后,如果該調試區有調試信息則會(huì )在DEBUG窗口輸出的。自己試試吧!


在學(xué)習驅動(dòng)程序之前,我們還有很多東西要了解。想來(lái)想去,可能最重要的還是中斷了,所以,這次我們花點(diǎn)時(shí)間來(lái)了解一下在Windows CE中的中斷機制。
凡是學(xué)過(guò)計算機原理的人都知道中斷是什么東西,所以這些基本知識我們就不再詳述了,我們下面就先看一下CE對中斷的整體處理流程,以方便從全局上有個(gè)整體的認識。
下圖是CE中中斷處理的流程圖示


我們分布來(lái)解釋上圖中的流程:
1、硬件設備向Kernel發(fā)送中斷異常的代碼,如果檢測到這個(gè)中斷異常,就會(huì )被Kernel層的異常處理所截獲;
2、中斷服務(wù)調度程序會(huì )調用OAL例程中的OEMInterruptDisable函數,這個(gè)函數會(huì )通知硬件在處理完這一中斷前關(guān)閉特殊的中斷,但其他的中斷仍然處于開(kāi)放狀態(tài);
3、中斷服務(wù)例程ISR被調用以決定如何來(lái)處理這一中斷;
4、Kernel接收到ISR的返回值以得知如何處理這一中斷。它的響應結果之一是忽略掉這一中斷不作處理(SYSINTR_NOP),另一結果是準備執行IST。
5、Kernel引發(fā)中斷服務(wù)調度程序來(lái)喚醒中斷服務(wù)線(xiàn)程去工作。IST是常規的Win32線(xiàn)程,一旦啟動(dòng)后,它會(huì )創(chuàng )建必要的EVENT然后等待該EVENT被激發(fā)。中斷服務(wù)調度通過(guò)調用PulseEvent函數來(lái)激發(fā)EVENT,從而喚醒IST線(xiàn)程運行;
6、當喚醒以后,IST會(huì )對中斷進(jìn)行必要的處理如將數據移動(dòng)到緩沖區或其他有意義的事;
7、如果需要的話(huà),IST會(huì )借助于I/O支持例程訪(fǎng)問(wèn)硬件設備;
8、當IST處理完成后,它會(huì )調用InterruptDone函數通知Kernel;
9、Kernel調用OEMInterruptDone函數完成此次中斷的處理過(guò)程,OAL例程通知硬件設備重新啟用中斷。
以上就是中斷在CE中簡(jiǎn)要的處理過(guò)程。這其中還涉及到幾個(gè)函數的使用,包括:
1、供OAL調用的ISR函數
HookInterrupt函數在OEMInit函數中被調用以關(guān)聯(lián)IRQ和ISR;
UnhookInterrupt函數用來(lái)終止IRQ和ISR的關(guān)聯(lián)。
2、供驅動(dòng)程序調用的IST函數
InterruptInitialize函數用來(lái)將EVENT對象和邏輯中斷號關(guān)聯(lián)并允許中斷;
InterruptDone函數用來(lái)通知中斷處理的結束;
InterruptDisable函數被驅動(dòng)程序調用以關(guān)閉中斷同時(shí)取消被InterruptInitialize初始化的EVENT對象。
下面我們再分別來(lái)看一下最重要的兩部分,ISR和IST。
ISR屬于OAL層,通常是用匯編語(yǔ)言編寫(xiě)的,它可以將CPU寄存器中的數據移動(dòng)到內存緩沖區中,但是它不能做更多的工作,其中一個(gè)原因就是它不能訪(fǎng)問(wèn)到用戶(hù)態(tài)的存儲區,它要把這些工作交給IST來(lái)完成。它做的另一項工作是進(jìn)行物理中斷號和邏輯中斷號的映射。一個(gè)物理設備比如鍵盤(pán)在一種平臺上可能產(chǎn)生4號中斷,在另一種平臺上可能產(chǎn)生15號中斷,經(jīng)過(guò)ISR以后,它就會(huì )把這一物理中斷轉換成CE中標準的SYSINTR_KEYBOARD邏輯中斷。Kernel就會(huì )根據這個(gè)邏輯中斷值找到對應的EVENT從而喚醒IST。
ISR有兩種,一種是單ISR模式, 即全局只有一個(gè)ISR,它適用于不支持多中斷的CPU,在這種情況下,OAL會(huì )提供一個(gè)OEMInterruptHandler的命令I(lǐng)SR。另一種是多ISR模式,即CPU有多個(gè)硬件中斷的情況,OAL通過(guò)HookInterrupt函數為每一個(gè)中斷調用ISR。
IST是驅動(dòng)程序中的用戶(hù)態(tài)線(xiàn)程,它來(lái)執行中斷的處理工作。在啟動(dòng)后它會(huì )空閑等待EVENT的激發(fā)狀態(tài),激發(fā)后處理真正的中斷處理過(guò)程,最后調用InterruptDone函數標識中斷處理完成。它通常通過(guò)CeSetThreadPriority函數設置在較高的優(yōu)先級狀態(tài)。
以上是對中斷的簡(jiǎn)要了解,在WINCE5的驅動(dòng)程序中,很大的變化就是把很多過(guò)程化的東西變成了面向對象的方式,即進(jìn)行了以類(lèi)為基礎的封裝,這樣代碼變得非常層次化,如果你想了解以上這些中斷在具體驅動(dòng)程序中的實(shí)現,建議還是先來(lái)看看CE4中的代碼,似乎更明顯一些。
好了,此次的內容不多,但是較空洞,最好配合查閱驅動(dòng)程序的源程序如串口的,鍵盤(pán)的,比如鍵盤(pán)的驅動(dòng)中就有非常明顯的IST,很容易看到它是如何設置優(yōu)先級的,如果等待EVENT的,如何處理鍵盤(pán)消息的以及如何完成中斷的,代碼附后,這樣才能加強理解。即使自己寫(xiě)驅動(dòng),也不一定完全從頭編寫(xiě),在以在別人的架構上修改以縮短開(kāi)發(fā)周期。
BOOL
KeybdIstLoop(
PKEYBD_IST pKeybdIst
)
{
SETFNAME(_T("KeybdIstLoop"));

UINT32 rguiScanCode[16];
BOOL rgfKeyUp[16];
UINT cEvents;

DEBUGCHK(pKeybdIst->hevInterrupt != NULL);
DEBUGCHK(pKeybdIst->pfnGetKeybdEvent != NULL);
DEBUGCHK(pKeybdIst->pfnKeybdEvent != NULL);

SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);

wait_for_keybd_interrupt:
if (WaitForSingleObject(pKeybdIst->hevInterrupt, INFINITE) == WAIT_OBJECT_0)
{
cEvents = (*pKeybdIst->pfnGetKeybdEvent)
(pKeybdIst->uiPddId, rguiScanCode, rgfKeyUp);

for (UINT iEvent = 0; iEvent cEvents; iEvent) {
(*pKeybdIst->pfnKeybdEvent)(pKeybdIst->uiPddId,
rguiScanCode[iEvent], rgfKeyUp[iEvent]);
}
// cEvents could be 0 if this was a partial scan code, like 0xE0

InterruptDone(pKeybdIst->dwSysIntr_Keybd);
}

goto wait_for_keybd_interrupt;

ERRORMSG(1, (TEXT("KeybdIstLoop: Keyboard driver thread terminating.rn")));
return TRUE;
}

linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)


評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>