,,http://www.bjzhda.cnzh-cn曙海教育集團(tuán)論壇http://www.bjzhda.cnRss Generator By Dvbbs.Netofficeoffice@126.comimages/logo.gif曙海教育集團(tuán)論壇wince下usb驅(qū)動(dòng)攻堅(jiān)戰(zhàn)http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1833&Page=1wangxinxin2010-11-26 14:08:26HeadPtr-->ED-->ED-->ED-->ED
ED-->TD-->TD-->TD...

    根據(jù)OHCI spec:每個(gè)ED(Endpoint Descriptor)描述USB設(shè)備的一個(gè)端點(diǎn)的所有數(shù)據(jù)傳輸,所有的ED被連接在一起;而TD(Transfer Descriptor)描述的才是最終要在USB總線上傳輸?shù)臄?shù)據(jù)包,屬于同一個(gè)USB設(shè)備端點(diǎn)的TD被連接在一起,并掛在相應(yīng)的ED上。
1)ohcd.c
該文件在platform下,可替代wince自帶的system.c文件(在public/common/oak/drivers/usb/hcd/ohc/下)。該文件中的函數(shù)被hcddrv.c文件中的HCD_流形式接口函數(shù)調(diào)用。
2)hcddrv.cpp
該文件在public/common/oak/drivers/usb/hcd/common下面,文件中的具體設(shè)置函數(shù):
HcdMdd_CreateMemoryObject
HcdMdd_CreateHcdObject
HcdMdd_DestroyMemoryObject
HcdMdd_DestroyHcdObject
HcdMdd_PowerOn
HcdMdd_PowerDown
HcdMdd_SetCapability
又被ohcd.c中的函數(shù)調(diào)用
CUHcd-->CHW-->CHcd(繼承關(guān)系,CUHcd的實(shí)例被創(chuàng)建)
 
初始化函數(shù)調(diào)用流程
1)HCD_Init()[hcddrv.cpp]
2)HcdPdd_Init()[ohcd.c]
3)InitializeOHCI()[ohcd.c]
配置IOBASE,IRQ。可讀取注冊(cè)表,也可以通過(guò)程序自配
4)HcdMdd_CreateMemoryObject();HcdMdd_CreateHcdObject()[hcddrv.cpp]
HcdMdd_CreateMemoryObject()==>CPhysMem->InittedOK()[usb/hcd/common/cphysmem.hpp]
HcdMdd_CreateHcdObject()==>CHcd->DeviceInitialize()[usb/hcd/ohcd2/cuhcd.cpp]
 
CHcd::DeviceInitialize()過(guò)程
1)CDeviceGlobal::Initialize()[usb/hcd/common/cdevice.cpp]
加載usbd.dll,并調(diào)用其中的HcdAttach()[usb/usbd/usbddrv.cpp]用hcddrv.cpp中的gc_HcdFuncs來(lái)設(shè)置usbd層的功能函數(shù)[pHcd->pHcdFuncs]
2)CHW::Initialize()[usb/hcd/ohcd2/chw.cpp]
初始化硬件,控制器寄存器,并創(chuàng)建線程用于處理HC的IST,并調(diào)用SignalCheckForDoneTransfer()來(lái)偵聽(tīng)傳輸?shù)耐瓿?br/>3)CHCCArea::Initialize()[usb/hcd/ohcd2/cpipe.cpp]
初始化CPipe的靜態(tài)變量,建立一個(gè)禎鏈表的空調(diào)度,同時(shí)建立中斷Queue Head樹(shù),創(chuàng)建線程用于處理傳輸完成。
 
IoPortBase = USB_BASE 以及Sys_Irq的初始化流程
1)HcdPdd_Init()[ohcd.c]
2)InitializeOHCI()[ohcd.c]
3)ConfigureOHCICard()[ohcd.c]:在此配置;HcdMdd_CreateHcdObject()[hcddrv.cpp]
4)CreateHCDObject()[cuhcd.cpp]:在此new CUhcd并初始化其父類CHW,在CHW初始化時(shí)初始化其成員變量m_portBase[chw.cpp]
 
Transfer流程
所有的IssueTransfer最終都要調(diào)用CPipe::IssueTransfer()[cpipe.cpp]
1)new STransfer并配置
2)拷貝client buffer到out transfer
3)AddTransfer:設(shè)置TDs鏈表并加到相應(yīng)的ED下
4)ScheduleTransfer
5)CHW::ListControl()
 
[以下以bulk為例]
1)在CHW::Initialize()中有
CHW::m_pBulkHead = &m_portBase->HcBulkHeadED;
2)在各pipe類的::OpenPipe()中有
*(CHW::m_pBulkHead) = (pa)m_pED;
 
故此:傳輸過(guò)程由HC根據(jù)各ED值來(lái)讀寫指定內(nèi)存,具體數(shù)據(jù)在各ED下的TDS鏈表中的各TD中,過(guò)程由HcControl和HcCommandStatus寄存器的各相應(yīng)位來(lái)控制。
]]>
WinCE中串口驅(qū)動(dòng)及接口函數(shù)介紹http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1832&Page=1wangxinxin2010-11-26 14:01:54  

       串口驅(qū)動(dòng)本身分為MDD層和PDD層。MDD層對(duì)上層的Device Manager提供了標(biāo)準(zhǔn)的流設(shè)備驅(qū)動(dòng)接口(COM_xxx),PDD層實(shí)現(xiàn)了HWOBJ結(jié)構(gòu)及結(jié)構(gòu)中若干針對(duì)于串口硬件操作的函數(shù)指針,這些函數(shù)指針將指向PDD層中的串口操作函數(shù)。DDSI是指MDD層與PDD層的接口,在串口驅(qū)動(dòng)中實(shí)際上就是指HWOBJ,PDD層會(huì)傳給MDD層一個(gè)HWOBJ結(jié)構(gòu)的指針,這樣MDD層就可以調(diào)用PDD層的函數(shù)來(lái)操作串口。

       微軟針對(duì)于串口驅(qū)動(dòng)提供了參考源代碼,可以在下面的目錄下找到:”\WINCE600\PUBLIC\COMMON\OAK\DRIVERS\SERIAL”。

   串口驅(qū)動(dòng)的結(jié)構(gòu)也就是這樣了,下面介紹相關(guān)的驅(qū)動(dòng)中的接口。

1. HWOBJ結(jié)構(gòu)

    在串口驅(qū)動(dòng)中,HWOBJ結(jié)構(gòu)中的函數(shù)實(shí)現(xiàn)了對(duì)串口硬件的操作,并在MDD層被調(diào)用。可以說(shuō),該結(jié)構(gòu)描述了串口設(shè)備的所有特性,先來(lái)介紹一下該結(jié)構(gòu),具體定義如下:
typedef struct __HWOBJ
{  
    ULONG BindFlags;  
    DWORD dwIntID;  
    PHW_VTBL pFuncTbl;
} HWOBJ, *PHWOBJ;
BindFlags:用于控制MDD層如何來(lái)處理IST,具體值如下:           

                       THREAD_IN_PDD:MDD層不處理,中斷在PDD層處理。            

                       THREAD_AT_INIT:在驅(qū)動(dòng)初始化的時(shí)候,MDD層啟動(dòng)IST。            

                       THREAD_AT_OPEN:在驅(qū)動(dòng)被Open的時(shí)候,MDD層啟動(dòng)IST。

dwInitID: 系統(tǒng)的中斷號(hào) pFuncTbl: 指向一個(gè)PHW_VTBL結(jié)構(gòu),該結(jié)構(gòu)中包含一個(gè)函數(shù)指針列表,這些函數(shù)指針指向串口硬件操作函數(shù),用于操作串口。

view plaincopy to clipboardprint?
typedef struct __HW_VTBL   
  
    {   
  
    PVOID (*HWInit)(ULONG Identifier, PVOID pMDDContext);   
  
    ULONG (*HWDeinit)(PVOID pHead);   
  
    BOOL (*HWOpen)(PVOID pHead);   
  
    ULONG (*HWClose)(PVOID pHead);   
  
    ULONG (*HWGetBytes)(PVOID pHead, PUCHAR pTarget, PULONG pBytes);   
  
    PVOID (*HWGetRxStart)(PVOID pHead);   
  
    INTERRUPT_TYPE (*HWGetIntrType)(PVOID pHead);   
  
    VOID (*HWOtherIntrHandler)(PVOID pHead);   
  
    VOID (*HWLineIntrHandler)(PVOID pHead);   
  
    ULONG (*HWGetRxBufferSize)(PVOID pHead);   
  
    VOID (*HWTxIntrHandler)(PVOID pHead);   
  
    ULONG (*HWPutBytes)(PVOID pHead, PUCHAR pSrc, ULONG NumBytes, PULONG pBytesSent);   
  
    BOOL (*HWPowerOff)(PVOID pHead);   
  
    BOOL (*HWPowerOn)(PVOID pHead);   
  
    VOID (*HWClearDTR)(PVOID pHead);   
  
    VOID (*HWSetDTR)(PVOID pHead);   
  
    VOID (*HWClearRTS)(PVOID pHead);   
  
    VOID (*HWSetRTS)(PVOID pHead);   
  
    BOOL (*HWEnableIR)(PVOID pHead, ULONG BaudRate);   
  
    BOOL (*HWDisableIR)(PVOID pHead);   
  
    VOID (*HWClearBreak)(PVOID pHead);   
  
    VOID (*HWSetBreak)(PVOID pHead);   
  
    BOOL (*HWXmitComChar)(PVOID pHead, UCHAR ComChar);   
  
    ULONG (*HWGetStatus)(PVOID pHead, LPCOMSTAT lpStat);   
  
    VOID (*HWReset)(PVOID pHead);   
  
    VOID (*HWGetModemStatus)(PVOID pHead, PULONG pModemStatus);   
  
    VOID (*HWGetCommProperties)(PVOID pHead, LPCOMMPROP pCommProp);   
  
    VOID (*HWPurgeComm)(PVOID pHead, DWORD fdwAction);   
  
    BOOL (*HWSetDCB)(PVOID pHead, LPDCB pDCB);   
  
    BOOL (*HWSetCommTimeouts)(PVOID pHead, LPCOMMTIMEOUTS lpCommTO);   
  
    BOOL (*HWIoctl)(PVOID pHead, DWORD dwCode,PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut,DWORD dwLenOut,PDWORD pdwActualOut);   
  
} HW_VTBL, *PHW_VTBL;  

typedef struct __HW_VTBL

{

  PVOID (*HWInit)(ULONG Identifier, PVOID pMDDContext);

   ULONG (*HWDeinit)(PVOID pHead);

   BOOL (*HWOpen)(PVOID pHead);

   ULONG (*HWClose)(PVOID pHead);

   ULONG (*HWGetBytes)(PVOID pHead, PUCHAR pTarget, PULONG pBytes);

   PVOID (*HWGetRxStart)(PVOID pHead);

   INTERRUPT_TYPE (*HWGetIntrType)(PVOID pHead);

   VOID (*HWOtherIntrHandler)(PVOID pHead);

   VOID (*HWLineIntrHandler)(PVOID pHead);

   ULONG (*HWGetRxBufferSize)(PVOID pHead);

   VOID (*HWTxIntrHandler)(PVOID pHead);

   ULONG (*HWPutBytes)(PVOID pHead, PUCHAR pSrc, ULONG NumBytes, PULONG pBytesSent);

   BOOL (*HWPowerOff)(PVOID pHead);

   BOOL (*HWPowerOn)(PVOID pHead);

   VOID (*HWClearDTR)(PVOID pHead);

   VOID (*HWSetDTR)(PVOID pHead);

   VOID (*HWClearRTS)(PVOID pHead);

   VOID (*HWSetRTS)(PVOID pHead);

   BOOL (*HWEnableIR)(PVOID pHead, ULONG BaudRate);

   BOOL (*HWDisableIR)(PVOID pHead);

   VOID (*HWClearBreak)(PVOID pHead);

   VOID (*HWSetBreak)(PVOID pHead);

   BOOL (*HWXmitComChar)(PVOID pHead, UCHAR ComChar);

   ULONG (*HWGetStatus)(PVOID pHead, LPCOMSTAT lpStat);

   VOID (*HWReset)(PVOID pHead);

   VOID (*HWGetModemStatus)(PVOID pHead, PULONG pModemStatus);

   VOID (*HWGetCommProperties)(PVOID pHead, LPCOMMPROP pCommProp);

   VOID (*HWPurgeComm)(PVOID pHead, DWORD fdwAction);

   BOOL (*HWSetDCB)(PVOID pHead, LPDCB pDCB);

   BOOL (*HWSetCommTimeouts)(PVOID pHead, LPCOMMTIMEOUTS lpCommTO);

   BOOL (*HWIoctl)(PVOID pHead, DWORD dwCode,PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut,DWORD dwLenOut,PDWORD pdwActualOut);

} HW_VTBL, *PHW_VTBL; 這些函數(shù)將在PDD層實(shí)現(xiàn),用于實(shí)際的串口硬件操作。


2. MDD層API

MDD層向上提供了流設(shè)備接口,這部分代碼微軟已經(jīng)實(shí)現(xiàn),用于管理串口。雖然我們不需要實(shí)現(xiàn)這部分,但是還是對(duì)相應(yīng)的接口做個(gè)簡(jiǎn)單介紹。

2.1HANDLE COM_Init(ULONG Identifier):

       初始化串口設(shè)備,該函數(shù)通過(guò)讀取注冊(cè)表獲得串口設(shè)備號(hào),并獲得相應(yīng)的HWOBJ的結(jié)構(gòu)指針,通過(guò)該指針調(diào)用PDD層的硬件初始化函數(shù)初始化串口。

Identifier:如果驅(qū)動(dòng)被設(shè)備管理器加載,那么這個(gè)參數(shù)將包含一個(gè)注冊(cè)表鍵值在” HKEY_LOCAL_MACHINE\Drivers\Active”路徑下。如果驅(qū)動(dòng)是通過(guò)調(diào)用RegisterDevice函數(shù)來(lái)加載的,那么這個(gè)值等于dwInfo的值。在COM_Init中,會(huì)先打開(kāi)該鍵值,用返回的句柄來(lái)查詢DeviceArrayIndex值,并根據(jù)該值獲得PDD層的HWOBJ結(jié)構(gòu)指針。

2.2 BOOL COM_Deinit(void):

       卸載串口設(shè)備,該函數(shù)中主要做了一些釋放資源的操作。也可以被DeregisterDevice函數(shù)調(diào)用。

2.3 HANDLE COM_Open(HANDLE pContext, DWORD AccessCode, DWORD ShareMode):

       打開(kāi)串口設(shè)備。應(yīng)用程序調(diào)用CreateFile函數(shù)打開(kāi)串口時(shí),該函數(shù)會(huì)被調(diào)用。

       pContext:COM_Init函數(shù)返回的Handle。

       AccessCode:設(shè)置訪問(wèn)模式,比如共享讀或者是讀寫模式。

       ShareMode:在參數(shù)從應(yīng)用程序中的CreateFile函數(shù)中傳來(lái),表示是否支持獨(dú)自占有。

2.4 BOOL COM_Close(DWORD pContext):

       關(guān)閉串口設(shè)備。應(yīng)用程序調(diào)用CloseHandle函數(shù)關(guān)閉串口時(shí),該函數(shù)會(huì)被調(diào)用。

       pContext:該參數(shù)為COM_Open函數(shù)返回的Handle。

2.5 ULONG COM_Read(HANDLE pContext, PUCHAR pTargetBuffer, ULONG BufferLength, PULONG pBytesRead):

       讀串口數(shù)據(jù)。應(yīng)用程序調(diào)用ReadFile函數(shù)讀串口的時(shí)候,該函數(shù)被調(diào)用。

       pContext:COM_Open函數(shù)返回的Handle。

       pTargetBuffer:指向一個(gè)用于存放讀到數(shù)據(jù)的Buffer。

       BufferLength:pTargetBuffer指向的Buffer的大小。

       pBytesRead:實(shí)際讀到的數(shù)據(jù)的大小。

2.6 ULONG COM_Write(HANDLE pContext, PUCHAR pSourceBytes, ULONG NumberOfBytes):

       寫串口數(shù)據(jù)。應(yīng)用程序調(diào)用WriteFile函數(shù)寫串口的時(shí)候,該函數(shù)被調(diào)用。

       pContext:COM_Open函數(shù)返回的Handle。

       pSourceBytes:指向一個(gè)Buffer,該Buffer包含要寫入串口的數(shù)據(jù)。

       NumberOfBytes:要寫入串口的數(shù)據(jù)的大小。

2.7 BOOL COM_PowerUp(HANDLE pContext):

       該函數(shù)主要用于串口設(shè)備從suspend模式恢復(fù)到正常模式。

       pContext:串口設(shè)備的Handle。

2.8 BOOL COM_PowerDown(HANDLE pContext):

       該函數(shù)主要用于串口設(shè)備從正常模式進(jìn)入suspend狀態(tài)。

       pContext:串口設(shè)備的Handle。]]>
WinCE驅(qū)動(dòng)程序的分類http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1831&Page=1wangxinxin2010-11-26 13:56:33最近有一些同學(xué)發(fā)郵件問(wèn)我,驅(qū)動(dòng)調(diào)試助手到底能動(dòng)態(tài)加載哪些驅(qū)動(dòng),為什么在加載USB設(shè)備驅(qū)動(dòng)時(shí)總是失敗。要解釋這個(gè)問(wèn)題,首先得弄清楚WinCE中驅(qū)動(dòng)的相關(guān)概念。本文將主要介紹WinCE下驅(qū)動(dòng)程序的分類。

       驅(qū)動(dòng)程序是介于操作系統(tǒng)和設(shè)備之間的一 個(gè)代碼層,它的主要作用是為操作系統(tǒng)提供一個(gè)接口,以操作不同的硬件,包括物理的和虛擬的設(shè)備。雖然驅(qū)動(dòng)程序有很多種,但從編程的角度來(lái)看,無(wú)非是往一個(gè) 固定的框架中添加相應(yīng)的代碼。這里的框架指的是一個(gè)接口,面向操作系統(tǒng)。代碼實(shí)現(xiàn)的宗旨是,在正確的時(shí)間往正確的寄存器中寫正確的值。

       驅(qū)動(dòng)程序的分類,從不同的角度有不同的 分法。拿串口驅(qū)動(dòng)來(lái)說(shuō),你可以說(shuō)它是一個(gè)分層驅(qū)動(dòng),你也可以說(shuō)它是一個(gè)流驅(qū)動(dòng),你還可以說(shuō)它是開(kāi)機(jī)時(shí)自動(dòng)加載的驅(qū)動(dòng)……這似乎有點(diǎn)亂。如果你也這么認(rèn)為, 那建議往下看。如果這些你都了如指掌,那就不浪費(fèi)時(shí)間了,當(dāng)然,您愿意找茬,我會(huì)很感謝!

       先說(shuō)本地驅(qū)動(dòng)(Native Drivers)和流驅(qū)動(dòng)(Stream Drivers)WinCE下的驅(qū)動(dòng)都可以歸類到這兩個(gè)里面,二者必居其一。這是從驅(qū)動(dòng)程序提供給操作系統(tǒng)的接口來(lái)區(qū)分的。流驅(qū)動(dòng)為操作系統(tǒng)提供了流接口函數(shù),如XXX_Init()XXX_Open()XXX_Read()XXX_Write()XXX_Close()等等。這一類的驅(qū)動(dòng)由Device Manager來(lái)管理,它調(diào)用ActivateDeviceEx()函數(shù)來(lái)加載流驅(qū)動(dòng)。ActivateDeviceEx()的參數(shù)是注冊(cè)表中相應(yīng)的鍵,用來(lái)設(shè)定加載流驅(qū)動(dòng)的屬性,如IndexOrderPrefix等等。流驅(qū)動(dòng)的注冊(cè)表配置信息一般存放在[HKEY_LOCAL_MACHINE\Drivers\BuiltIn]下。流驅(qū)動(dòng)加載成功后,應(yīng)用程序通過(guò)調(diào)用CreateFile()ReadFile()WirteFile()等來(lái)訪問(wèn)流驅(qū)動(dòng)的設(shè)備。流驅(qū)動(dòng)可以動(dòng)態(tài)管理,驅(qū)動(dòng)調(diào)試助手就是用來(lái)幫助調(diào)試這一類驅(qū)動(dòng)的。

與流驅(qū)動(dòng)相反,本地驅(qū)動(dòng)提供給操作系統(tǒng)的不是標(biāo)準(zhǔn)的流接口,而是事先約定好的特定接口。不同的設(shè)備,接口也不一樣。WinCE中,常見(jiàn)的本地驅(qū)動(dòng)有LCD顯示驅(qū)動(dòng)、觸摸屏驅(qū)動(dòng)、鼠標(biāo)和鍵盤驅(qū)動(dòng)及打印機(jī)驅(qū)動(dòng)等。可以看到,本地驅(qū)動(dòng)主要是人機(jī)界面相關(guān)的驅(qū)動(dòng)。它們由GWES管理,在系統(tǒng)啟動(dòng)時(shí)加載。他們?cè)谧?cè)表中也有各自相應(yīng)的配置信息。如鍵鼠的注冊(cè)表配置如下:

[HKEY_LOCAL_MACHINE"System"CurrentControlSet"Control"Layouts"00000409]

"Layout File"="kbdmouse.dll"

"Layout Text"="US"

"PS2_AT"="kbdmouse.dll"

"Matrix"="kbdmouse.dll"

本地驅(qū)動(dòng)由操作系統(tǒng)調(diào)用,應(yīng)用程序不能訪問(wèn)。對(duì)于這類驅(qū)動(dòng),驅(qū)動(dòng)調(diào)試助手是無(wú)能為力的,只能老老實(shí)實(shí)的編譯、下載、驗(yàn)證。

WinCE驅(qū)動(dòng)中經(jīng)常會(huì)聽(tīng)到MDD(Model Device Driver)PDD(Platform Dependent Driver)的概念,這是從驅(qū)動(dòng)代碼實(shí)現(xiàn)的結(jié)構(gòu)來(lái)區(qū)分的。WinCE的驅(qū)動(dòng)可以是單層的,也可以是PDD+MDD。這沒(méi)有硬性規(guī)定,一個(gè)驅(qū)動(dòng)程序可以采用分層結(jié)構(gòu),也可以采用單層結(jié)構(gòu)。一般來(lái)說(shuō),單層結(jié)構(gòu)的驅(qū)動(dòng)執(zhí)行效率更高,而分層結(jié)構(gòu)的驅(qū)動(dòng)方便代碼維護(hù)和移植。拿串口驅(qū)動(dòng)來(lái)說(shuō),完全可以采用單層結(jié)構(gòu)。而把它分為PDDMDD,作為一般的開(kāi)發(fā)者,我們只需實(shí)現(xiàn)PDD層就可以了,MDD層由微軟實(shí)現(xiàn)。這樣,驅(qū)動(dòng)開(kāi)發(fā)的工作量少很多,而代碼的可靠性則有了更好的保證。至于采用哪一種結(jié)構(gòu)的驅(qū)動(dòng),主要看你的需求。

WinCE 6.0引入了內(nèi)核態(tài)驅(qū)動(dòng)和用戶態(tài)驅(qū)動(dòng)的概念。在WinCE5.0及先前的版本中,驅(qū)動(dòng)工作在用戶態(tài)。從代碼方面看,內(nèi)核態(tài)驅(qū)動(dòng)和用戶態(tài)驅(qū)動(dòng)沒(méi)太大差別。如果驅(qū)動(dòng)中沒(méi)有采用什么特別的技術(shù),內(nèi)核態(tài)驅(qū)動(dòng)和用戶態(tài)驅(qū)動(dòng)甚至是二進(jìn)制兼容的。我曾經(jīng)試過(guò)將一個(gè)DLL分 別加載到內(nèi)核態(tài)和用戶態(tài),都工作得很好。內(nèi)核態(tài)驅(qū)動(dòng)被加載到內(nèi)核空間,用戶態(tài)驅(qū)動(dòng)被加載到特定的用戶進(jìn)程空間中。從執(zhí)行效率來(lái)看,內(nèi)核態(tài)的驅(qū)動(dòng)效率比用戶 態(tài)的驅(qū)動(dòng)高。從穩(wěn)定性方面考慮,用戶態(tài)的驅(qū)動(dòng)不會(huì)對(duì)系統(tǒng)產(chǎn)生致命影響,而內(nèi)核態(tài)的驅(qū)動(dòng)相對(duì)危險(xiǎn)。同樣,采用哪一種類型的驅(qū)動(dòng),也是看你的需求。

從驅(qū)動(dòng)加載的時(shí)間來(lái)看,可分為兩種:系統(tǒng)啟動(dòng)時(shí)加載和需要時(shí)加載。一般來(lái)說(shuō)本地驅(qū)動(dòng)都是在啟動(dòng)時(shí)加載的,所以這里說(shuō)的主要是流驅(qū)動(dòng)。如果想要驅(qū)動(dòng)在系統(tǒng)啟動(dòng)時(shí)加載,只需將它的注冊(cè)表配置信息放到[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\]下,如[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Battery],系統(tǒng)啟動(dòng)時(shí),Device Manager會(huì)自動(dòng)加載它。需要時(shí)加載,顧名思義,就是想加載就加載,想卸載就卸載,很靈活。這里很有必要說(shuō)一下USB設(shè)備的驅(qū)動(dòng)加載,如USB攝像頭驅(qū)動(dòng),它也屬于需要時(shí)加載的驅(qū)動(dòng)。從驅(qū)動(dòng)的接口來(lái)看,它屬于流驅(qū)動(dòng),但相對(duì)普通的流驅(qū)動(dòng),它增加了幾個(gè)函數(shù):USBDeviceAttach()USBInstallDriver()USBUnInstallDriver()等。USB攝像頭驅(qū)動(dòng)的加載在USBDeviceAttach()中完成。所以,它無(wú)須,也不能,用驅(qū)動(dòng)調(diào)試助手加載。需要時(shí)加載的驅(qū)動(dòng)還有一個(gè)作用,在無(wú)法修改系統(tǒng)的情況下,應(yīng)用程序中動(dòng)態(tài)加載該驅(qū)動(dòng),以完成對(duì)硬件的操作。

......

]]>
基于FM2010和WinCE平臺(tái)的回音消除驅(qū)動(dòng)設(shè)計(jì)http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1830&Page=1wangxinxin2010-11-26 13:52:271 開(kāi)發(fā)平臺(tái)與基本概念介紹
WinCE是Microsoft公司推出的功能強(qiáng)大、緊湊高效、可伸縮的32位嵌入式操作系統(tǒng),主要面對(duì)各種各樣的嵌入式系統(tǒng)和產(chǎn)品。該系統(tǒng)所具有的多線程、多任務(wù)、完全搶占式的特點(diǎn)是專為各種具有嚴(yán)格資源限制的硬件系統(tǒng)所設(shè)計(jì)的。
FM2010是ForteMedia公司推出的一款語(yǔ)音處理器,具有迷你型尺寸、單芯片解決方案、高性能、低功耗,以及優(yōu)良的回聲消除和噪聲抑制功能,利用創(chuàng)新的SAM(小型陣列麥克風(fēng))技術(shù)與波束形成能力使其功率消耗僅為25 mW。FM2010具有提高電池壽命、降低功耗和節(jié)省芯片尺寸等優(yōu)點(diǎn),可滿足便攜式手持掌上電腦、筆記本電腦、平板電腦和手機(jī)的嚴(yán)格要求。


2 回聲產(chǎn)生的原理與消除方法
2.1 回聲的基本概念和產(chǎn)生原理
通常意義上的回聲可以分為電學(xué)回聲和聲學(xué)回聲,前一種是由于服務(wù)提供商的線路質(zhì)量所致,而后一種則是由于用戶端設(shè)備的質(zhì)量所致。
2.1.1 電學(xué)回聲
在PSTN (Public Switched Telephone Network,公共交換電話網(wǎng)絡(luò))中,為了降低電話中心局與電話用戶之間電話線的價(jià)格,用戶線間的連接采用兩線制,而電話中心局之間連接采用四線制。在這樣采用混合線制的電路中,由于阻抗的失配,會(huì)不可避免地產(chǎn)生電流泄漏。電流泄漏使得一部分信號(hào)的能量反射回信號(hào)源,這種反射和信道延遲結(jié)合在一起,使講話者聽(tīng)到自己的聲音,即為電學(xué)回聲。
2.1.2 聲學(xué)回聲
聲學(xué)回聲是指揚(yáng)聲器播出的聲音在被受話方聽(tīng)到的同時(shí),也通過(guò)多種路徑被麥克風(fēng)拾取到,傳輸?shù)秸f(shuō)話方的一端,從而形成聲音回路。當(dāng)回聲返回時(shí)間超過(guò)10 ms時(shí),人耳就可聽(tīng)到明顯的回聲了。多路徑反射的結(jié)果產(chǎn)生了不同延時(shí)的回聲,包括直接回聲和間接回聲。
①直接回聲是指由揚(yáng)聲器播出的聲音未經(jīng)任何反射直接進(jìn)入麥克風(fēng)。這種回聲的延時(shí)最短,它同遠(yuǎn)端說(shuō)話者的語(yǔ)音能量,揚(yáng)聲器與麥克風(fēng)之間的距離、角度,揚(yáng)聲器的播放音量,麥克風(fēng)的拾取靈敏度等因素直接相關(guān)。
②間接回聲是指由揚(yáng)聲器播出的聲音經(jīng)過(guò)不同的路徑(如房屋或房屋內(nèi)的任何物體)的一次或多次反射后,進(jìn)入麥克風(fēng)所產(chǎn)生的回聲的集合。房屋內(nèi)的任何物體的任何變動(dòng)都會(huì)改變回聲的通道,因此,這種回聲的特點(diǎn)是多路徑的、時(shí)變的。
對(duì)于電學(xué)回聲的消除,通常由服務(wù)提供商提供解決方案。本文研究的重點(diǎn)是聲學(xué)回聲的消除機(jī)制,為了防止聲音回路的產(chǎn)生,通常需要在硬件和軟件設(shè)計(jì)中采取一定的解決方案。
如圖1所示,雙方在使用PDA或者手機(jī)進(jìn)行通話時(shí),假設(shè)B是主話方,A是受話方:

圖片點(diǎn)擊可在新窗口打開(kāi)查看

①B說(shuō)話的聲音經(jīng)過(guò)電信或者移動(dòng)路徑傳輸?shù)紸的設(shè)備上;
②聲音經(jīng)過(guò)揚(yáng)聲器發(fā)出,由于硬件和機(jī)構(gòu)設(shè)計(jì)上的局限性,會(huì)有部分聲音滲透到A的麥克風(fēng);
③滲透出的聲音又傳輸回到B,導(dǎo)致B能聽(tīng)到自己的聲音。
這樣,便形成了聲音回路,即產(chǎn)生了回聲。
PDA或者手機(jī)內(nèi)部結(jié)構(gòu)聲音回路示意圖如圖2所示。在全雙工的情況下,揚(yáng)聲器和麥克風(fēng)之間至少要保持4 cm以上的距離,才能比較好地避免回聲問(wèn)題。在實(shí)際情況下,絕大部分的回聲回路形成于機(jī)構(gòu)內(nèi)部,而由機(jī)構(gòu)外部揚(yáng)聲器回流到麥克風(fēng)的聲音,由于距離較長(zhǎng),基本可以忽略。

圖片點(diǎn)擊可在新窗口打開(kāi)查看

由于硬件和機(jī)構(gòu)設(shè)計(jì)上的局限性,在機(jī)構(gòu)內(nèi)部不可能完全隔離聲音的傳播,因此從揚(yáng)聲器出來(lái)的聲音會(huì)有一部分會(huì)滲透到麥克風(fēng),從而產(chǎn)生回聲。
2.2 基于FM2010的回聲消除原理
FM2010使用的是自適應(yīng)回聲抵消原理,它的基本思想是:估計(jì)回聲路徑的特征參數(shù),產(chǎn)生一個(gè)模擬的回聲路徑,得出模擬回聲信號(hào),從接收信號(hào)中減去該信號(hào),實(shí)現(xiàn)回聲抵消。以圖3所示的受話端通話流程為例,圖中左上方的MIC IN是麥克風(fēng)進(jìn)入的信號(hào),即用戶的聲音輸入信號(hào),其中包含由本機(jī)揚(yáng)聲器漏進(jìn)去的部分主話端的語(yǔ)音信號(hào);右下方的Line IN接入是主話端的語(yǔ)音信號(hào),即由本機(jī)揚(yáng)聲器輸出的信號(hào)直接接入到FM2010回音消除芯片的Line IN輸入端。在FM2010內(nèi)部會(huì)經(jīng)過(guò)DSP芯片的運(yùn)算處理對(duì)兩者進(jìn)行比較,消除MIC IN信號(hào)中與LineIN端相同的信號(hào)(即回聲音頻信號(hào)),使用自適應(yīng)回聲抵消原理達(dá)到消除回聲的目的。MIC IN和Line OUT之間路徑上的寄存器需要進(jìn)行配置和調(diào)試,DSP使用這些配置的數(shù)據(jù)作為特征參數(shù)來(lái)進(jìn)行運(yùn)算處理。

圖片點(diǎn)擊可在新窗口打開(kāi)查看

3 基于FM2010的回音消除驅(qū)動(dòng)設(shè)計(jì)
3.1 硬件架構(gòu)設(shè)計(jì)

圖4是硬件架構(gòu)示意圖。CPU 通過(guò)I2C總線 來(lái)控制回音消除芯片讀/寫回音消除參數(shù)(echo parameter)。錄音信號(hào)先經(jīng)過(guò)回音消除芯片處理后經(jīng)移動(dòng)信道傳輸?shù)綄?duì)方接收設(shè)備,經(jīng)過(guò)對(duì)方音頻編解碼器處理后再通過(guò)揚(yáng)聲器或者耳機(jī)輸出。

圖片點(diǎn)擊可在新窗口打開(kāi)查看

3.2 音頻設(shè)備機(jī)構(gòu)設(shè)計(jì)
音頻設(shè)備是否產(chǎn)生回聲,很大程度上取決于機(jī)構(gòu)的設(shè)計(jì)是否合理。不合理的機(jī)構(gòu)設(shè)計(jì)會(huì)大大增加出現(xiàn)回聲的概率,而且出現(xiàn)的回聲會(huì)比較嚴(yán)重,難于消除。我們改進(jìn)了音頻設(shè)備機(jī)構(gòu)上的設(shè)計(jì),在設(shè)計(jì)之初就盡可能避免回音的產(chǎn)生,而且揚(yáng)聲器和麥克風(fēng)的距離盡可能保持一定遠(yuǎn)的距離,如圖5所示。實(shí)踐中發(fā)現(xiàn),揚(yáng)聲器和麥克風(fēng)之間的距離保持在10 cm以上,效果會(huì)比較好。

圖片點(diǎn)擊可在新窗口打開(kāi)查看

為了盡可能減少揚(yáng)聲器和麥克風(fēng)之間的聲音傳播,可以采用以下2種設(shè)計(jì)方案:方案一是把麥克風(fēng)隔離開(kāi)來(lái),如圖5(a)所
示;方案二是把揚(yáng)聲器隔離開(kāi)來(lái),如圖5(b)所示。當(dāng)然,為了達(dá)到更好的效果,可以把揚(yáng)聲器和麥克風(fēng)分別隔離開(kāi);但是鑒于成本的考慮,使用其中的一種即可達(dá)到比較好的效果。具體的實(shí)現(xiàn)方法分別是:
①用橡膠套密封揚(yáng)聲器的邊緣,盡可能避免聲音從機(jī)構(gòu)內(nèi)部回流到麥克風(fēng);同時(shí)把麥克風(fēng)密封在一個(gè)腔體之內(nèi),以隔離外
部噪聲的進(jìn)入。
②把揚(yáng)聲器密封在一個(gè)腔體之內(nèi),以盡可能隔離揚(yáng)聲器的聲音向外部傳播;同時(shí)使用橡膠套密封麥克風(fēng)的邊緣,以避免揚(yáng)聲器發(fā)出的聲音進(jìn)入。
另外,揚(yáng)聲器和麥克風(fēng)在設(shè)置的方向上也有講究,如圖6所示。兩者最好是相差180°,90°也可以接受;但是如果兩者的方向相同,如圖6(c)所示,則出現(xiàn)回聲的概率和程度都很大。

圖片點(diǎn)擊可在新窗口打開(kāi)查看

3.3 軟件架構(gòu)設(shè)計(jì)與實(shí)現(xiàn)
軟件架構(gòu)示意圖如圖7所示。

圖片點(diǎn)擊可在新窗口打開(kāi)查看

回音消除驅(qū)動(dòng)的開(kāi)發(fā)需要完成以下幾步:
①給回音消除芯片上電,并初始化其相關(guān)的寄存器和GPIO;
②初始化I2C總線,并配置I2C速率等的寄存器,使其處于正常運(yùn)行狀態(tài);
③檢查I2C總線是否已準(zhǔn)備好;
④通過(guò)I2C總線讀取回音消除參數(shù);
⑤等待回音消除芯片處于可讀/寫狀態(tài),然后把參數(shù)寫入到芯片里,使配置的參數(shù)生效。
3.3.1 FM2010上電時(shí)序
當(dāng)對(duì)FM2010初始化時(shí),比較重要的一點(diǎn)是要按照其規(guī)格說(shuō)明書(shū)定義的上電時(shí)序進(jìn)行,否則可能會(huì)導(dǎo)致錄音聲音時(shí)有時(shí)無(wú)的情況發(fā)生。具體的要求如圖8所示。在初始化FM2010時(shí),PWD high的狀態(tài)必須要在RESET high狀態(tài)之前設(shè)定,兩者之間相差5 ms。

圖片點(diǎn)擊可在新窗口打開(kāi)查看

3.3.2 讀/寫Echo parameter
FM2010芯片的初始化比較簡(jiǎn)單,只要按照上述的時(shí)序進(jìn)行初始化即可。下面重點(diǎn)剖析回音消除驅(qū)動(dòng)的開(kāi)發(fā)要點(diǎn),即如何讀/寫回音消除參數(shù)(詳見(jiàn)代碼中的①和④)、設(shè)置回音消除芯片的工作模式(詳見(jiàn)②處),以及配置I2C總線(詳見(jiàn)③處)。

圖片點(diǎn)擊可在新窗口打開(kāi)查看

圖片點(diǎn)擊可在新窗口打開(kāi)查看

圖片點(diǎn)擊可在新窗口打開(kāi)查看
結(jié) 語(yǔ)
本文在分析語(yǔ)音通話中回聲產(chǎn)生的機(jī)理的基礎(chǔ)上,詳細(xì)研究了回聲消除的原理、基本聲學(xué)回聲產(chǎn)生根源,提出了改進(jìn)的PDA或者手機(jī)等音頻設(shè)備的機(jī)構(gòu)設(shè)計(jì)方案;針對(duì)FM2010芯片的特點(diǎn),給出了回聲消除驅(qū)動(dòng)開(kāi)發(fā)的軟硬件設(shè)計(jì)方案,并且給出了回音消除驅(qū)動(dòng)程序關(guān)鍵代碼的實(shí)現(xiàn)。本文設(shè)計(jì)的軟硬件解決方案已經(jīng)在基于WinCE操作系統(tǒng)平臺(tái)和FM2010硬件平臺(tái)上得以實(shí)現(xiàn),在實(shí)際項(xiàng)目開(kāi)發(fā)中得到采用,并且獲得了良好的應(yīng)用效果。

]]>
WinCE流驅(qū)動(dòng)開(kāi)發(fā)流程http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1829&Page=1wangxinxin2010-11-26 13:43:25PDD:Platform Dependence Driver,平臺(tái)相關(guān)驅(qū)動(dòng)

MDD:Model Device Driver,模型設(shè)備驅(qū)動(dòng)

DDSI:Device Driver Service Provider Interface,DDSI函數(shù)

單體驅(qū)動(dòng):

顧名思義,所有的驅(qū)動(dòng)程序代碼——包括中斷處理、I/O操作及硬件控制都被放在了一起。這也是比較傳統(tǒng)的驅(qū)動(dòng)程序編寫方法。單體驅(qū)動(dòng)程序的代碼直接與硬件交互,因此它包含與特定的某款硬件相關(guān)聯(lián)的代碼。通常,單體驅(qū)動(dòng)程序會(huì)暴露DDI接口(Device Driver Interface)給操作系統(tǒng),DDI函數(shù)是操作系統(tǒng)與驅(qū)動(dòng)程序交互的接口協(xié)議。因?yàn)閱误w驅(qū)動(dòng)程序?qū)︱?qū)動(dòng)程序的代碼不做分層處理,因此驅(qū)動(dòng)程序的代碼相對(duì)緊湊,對(duì)于一些效率要求較高的場(chǎng)合,選用單體驅(qū)動(dòng)程序會(huì)提高驅(qū)動(dòng)的性能,同時(shí),對(duì)于一些較簡(jiǎn)單的硬件設(shè)備驅(qū)動(dòng),使用單體驅(qū)動(dòng)程序模型,可更加清晰明了。

附單體驅(qū)動(dòng)和分層驅(qū)動(dòng)圖如下:


原博主正文如下:

首先是wince驅(qū)動(dòng)的分類問(wèn)題。按照書(shū)上講的說(shuō)CE下驅(qū)動(dòng)分成單體驅(qū)動(dòng)和分層驅(qū)動(dòng),而看到另一種說(shuō)法是本機(jī)驅(qū)動(dòng)和流式驅(qū)動(dòng)。經(jīng)過(guò)microsun大哥的指點(diǎn),把這兩種分類法分開(kāi)了。在這里引用一下:
   “單體與分層只是從代碼的形式上做的分類.分層驅(qū)動(dòng)代碼上分為PDD與MDD,一般的微軟已經(jīng)實(shí)現(xiàn)了MDD,可能也實(shí)現(xiàn)了PDD,我們只需要對(duì)PDD做些修改就能使用,比如音頻的驅(qū)動(dòng),顯示的驅(qū)動(dòng)。單層驅(qū)動(dòng)是把PDD與MDD寫在一起,沒(méi)有做嚴(yán)格的區(qū)分,通常這種驅(qū)動(dòng)比較簡(jiǎn)單,比如:ATADISK。至于本地驅(qū)動(dòng)和流式驅(qū)動(dòng)是從驅(qū)動(dòng)與系統(tǒng)其它模塊(調(diào)用者)的接口形式上做的分類.其實(shí),本地驅(qū)動(dòng)這個(gè)名稱不大恰當(dāng),可能叫專用驅(qū)動(dòng)或其它名字更為合適.它是指調(diào)用它的模塊給它有特定的接口,比如電源驅(qū)動(dòng)和通用LED驅(qū)動(dòng)。而串口,網(wǎng)卡等就是流接口驅(qū)動(dòng)程序. 所以,一個(gè)驅(qū)動(dòng)程序可以是單體的流式驅(qū)動(dòng),例如:ATADISK.也可以是分層的流式: 如OHCI ” 
    按照我的理解,單體和分層是驅(qū)動(dòng)實(shí)現(xiàn)方式上的分類,而本地和流式則是驅(qū)動(dòng)模型上的分類,所謂本地驅(qū)動(dòng)就是操作系統(tǒng)有保留專門的接口,所謂流式是指編寫的DLL文件里可以導(dǎo)出各種流式接口函數(shù)。 
    第二點(diǎn):驅(qū)動(dòng)的功能屬性。設(shè)備驅(qū)動(dòng)程序是操作系統(tǒng)內(nèi)核和硬件的接口,操作系統(tǒng)定義了一組標(biāo)準(zhǔn)的接口,編寫驅(qū)動(dòng)的過(guò)程也就是實(shí)現(xiàn)這些接口。從應(yīng)用程序到具體硬件間有如下這些環(huán)節(jié)起作用:應(yīng)用程序-調(diào)用OS函數(shù)-操作系統(tǒng)-驅(qū)動(dòng)接口-驅(qū)動(dòng)程序-硬件操作函數(shù)-硬件。在wince里驅(qū)動(dòng)都以用戶態(tài)的DLL存在,需要通過(guò)進(jìn)程加載到slot里。共有三類系統(tǒng)進(jìn)程用來(lái)加載:Device.exe,GWES.exe,FileSys.exe.絕大多數(shù)設(shè)備驅(qū)動(dòng)都是通過(guò)Device.exe加載的。需要注意的是,不同的OS保留的設(shè)備驅(qū)動(dòng)接口是不一樣的,如桌面windows和wince就不同。
     第三點(diǎn):wince下設(shè)備的初始化分為兩個(gè)階段:Device.exe的初始化;外設(shè)的枚舉和加載。其流程是:上電-啟動(dòng)bootloader-啟動(dòng)NK-啟動(dòng)注冊(cè)表init鍵(Device.exe啟動(dòng))-初始化數(shù)據(jù)結(jié)構(gòu),I/O,電源管理等-加載BusEnum.dll(總線枚舉器)-枚舉注冊(cè)表下Driver/buildin的所有子鍵。這里的枚舉過(guò)程就是循環(huán)調(diào)用ActivateDeviceEx()函數(shù)加載驅(qū)動(dòng)的過(guò)程。在OS啟動(dòng)完畢后,我們可以用PB的Remote Registry Tool查看H_L_M/drivers/active包含的子鍵,看哪些驅(qū)動(dòng)隨啟動(dòng)而加載 。
     第四點(diǎn):流接口驅(qū)動(dòng)的概念。暴露流式接口函數(shù)的驅(qū)動(dòng)即是流驅(qū)動(dòng),它把外設(shè)抽象成一個(gè)文件。過(guò)程是:應(yīng)用程序使用文件API對(duì)設(shè)備進(jìn)行訪問(wèn),OS接受API調(diào)用FileSys.exe,轉(zhuǎn)到device.exe,調(diào)用流接口,與硬件交互。所謂流接口函數(shù)有十個(gè),包括XXX_Init、XXX_Deinit、XXX_Open、XXX_Close、XXX_Read、XXX_Write、XXX_PowerUp、XXX_PowerDown、XXX_Seek、XXX_IOControl,在wince5.0中增加le了XXX_PreClose,XXX_PreDeinit.而我們?cè)趹?yīng)用程序里對(duì)應(yīng)的文件API有CreateFile、DeviceIoControl、 ReadFile、 WriteFile,CloseHandle,SetFilePointer.  
     第五點(diǎn):編寫流驅(qū)動(dòng)的步驟。有兩種實(shí)現(xiàn)途徑:1。寫DLL,做成Project,加入到OS里。2。改BSP,把驅(qū)動(dòng)寫在BSP里,再選擇那個(gè)BSP做OS。第一種方法步驟是在PB中新建一個(gè)DLL項(xiàng)目,編寫一些輸入函數(shù),寄存器,外設(shè)的聲明,寫DLLENTRY函數(shù);實(shí)現(xiàn)流接口函數(shù);編寫DLL的導(dǎo)出函數(shù)文件.DEF;為驅(qū)動(dòng)程序?qū)懭胱?cè)表項(xiàng),還需要修改bib文件。 第二種方法就是在platform/BSP/drivers下新建一個(gè)目錄,然后在drivers目錄中的dirs文件中加入新建的目錄名。在新建的目錄下,新建你的源代碼文件,在其中實(shí)現(xiàn)DLL函數(shù)。新建名稱分別為sources, makefile, ***.def的文件;修改platform.reg和platform.bib文件。

]]>
WinCE平臺(tái)USB攝像頭驅(qū)動(dòng)開(kāi)發(fā)流程http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1828&Page=1wangxinxin2010-11-26 13:42:30  前段時(shí)間,公司委派我負(fù)責(zé)一個(gè)嵌入式項(xiàng)目,項(xiàng)目要求是在WinCE平臺(tái)上集成USB攝像頭驅(qū)動(dòng)和視頻采集程序。這個(gè)項(xiàng)目的關(guān)鍵是要集成USB攝像頭驅(qū)動(dòng),并高效的把攝像頭設(shè)備進(jìn)行初始化以取得一幅完整的圖像。幸好我以前開(kāi)發(fā)過(guò)WinCEUSB的主從設(shè)備的驅(qū)動(dòng)程序。但雖然如此,我還是花了一些時(shí)間來(lái)調(diào)整系統(tǒng)的穩(wěn)定性和可靠性。在這里我分享在這次項(xiàng)目實(shí)踐中得到的經(jīng)驗(yàn)和教訓(xùn),希望大家能少走彎路。

  一.什么是USB設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)?

  隨著USB設(shè)備的普及,USB設(shè)備驅(qū)動(dòng)開(kāi)發(fā)在嵌入式系統(tǒng)變得越來(lái)越重要了。為了支持不同類型的硬件可以連接到WinCE平臺(tái)上,微軟提供了具有定制接口的流接口驅(qū)動(dòng)程序模型。WinCE的USB外圍設(shè)備一般是使用流接口驅(qū)動(dòng)程序。流接口驅(qū)動(dòng)程序是指通過(guò)系統(tǒng)提供的文件系統(tǒng)API與應(yīng)用程序交互;WinCE內(nèi)核系統(tǒng)會(huì)通過(guò)設(shè)備管理器來(lái)完成對(duì)流接口驅(qū)動(dòng)程序的加載、卸載等管理工作;而流接口驅(qū)動(dòng)程序則會(huì)通過(guò)調(diào)用USBD模塊提供的接口函數(shù)實(shí)現(xiàn)與底層USB設(shè)備通信。因此,在進(jìn)行USB設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)之前,我們必須先了解USB設(shè)備驅(qū)動(dòng)的結(jié)構(gòu)和分類。

  (1)主機(jī)與USB攝像頭的通訊結(jié)構(gòu)

  USB攝像頭驅(qū)動(dòng)程序主要是利用系統(tǒng)提供的底層接口配置設(shè)備和攝像頭設(shè)備進(jìn)行通訊。因此,WinCE的USB攝像頭驅(qū)動(dòng)分為兩層:USBClient設(shè)備驅(qū)動(dòng)程序和底層的WinCE函數(shù)實(shí)現(xiàn)層。而底層的函數(shù)層本身又由兩部分組成,即通用串行總線驅(qū)動(dòng)程序(USBD)模塊和較低層的主控制器驅(qū)動(dòng)程序(HCD)模塊。HCD負(fù)責(zé)最底層的處理,USBD模塊實(shí)現(xiàn)較高的USBD函數(shù)接口。因此,USB攝像頭驅(qū)動(dòng)主要是利用USBD接口函數(shù)和外圍USB攝像頭打交道。

  一般來(lái)說(shuō),主機(jī)和USB外設(shè)之間的通訊是由在主機(jī)端通過(guò)USBD模塊和HCD模塊使用的PIPE訪問(wèn)一個(gè)通用的邏輯設(shè)備來(lái)完成。也就是說(shuō),USBD和HCD是一組抽象出來(lái)用于訪問(wèn)USB設(shè)備的邏輯接口,它們主要是負(fù)責(zé)管理USB外設(shè)的連接、加載、移除、數(shù)據(jù)傳輸和通用的配置。其中HCD是由主機(jī)控制和驅(qū)動(dòng)的,是為USBD提供底層的功能訪問(wèn)服務(wù)。而USBD則是由USB總線驅(qū)動(dòng)的,位于HCD的上層,是利用HCD的服務(wù)提供較高層次抽象的功能。

  由于HCD和USBD都是面向一致的邏輯設(shè)備接口,因此如果嵌入式系統(tǒng)中擁有多種USB物理外設(shè)的話,那么就需要有唯一對(duì)應(yīng)的外設(shè)驅(qū)動(dòng)程序,也就是要有最上層的PIPE所連接的物理設(shè)備和USB設(shè)備驅(qū)動(dòng)程序。有了對(duì)這個(gè)結(jié)構(gòu)的認(rèn)識(shí),那么我們?cè)谶M(jìn)行USB設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)時(shí)首先要寫的就是最上端的USB攝像頭客戶端驅(qū)動(dòng)程序,在WinCE的樣例程序中它也被稱為USBClientDriver。它是工作于USBD之上,所以實(shí)際上我們的工作就變成了利用USBD提供的接口針對(duì)特定的物理設(shè)備來(lái)完成USB設(shè)備驅(qū)動(dòng)程序。(見(jiàn)圖)

  (2)流驅(qū)動(dòng)程序的分類和函數(shù)結(jié)構(gòu)

  WinCE驅(qū)動(dòng)程序是介于內(nèi)核系統(tǒng)和物攝像頭驅(qū)動(dòng)理設(shè)備之間的一個(gè)代碼層,它的主要作用是為內(nèi)核系統(tǒng)提供一個(gè)接口用來(lái)操作不同的外圍設(shè)備,包括物理設(shè)備和虛擬設(shè)備。驅(qū)動(dòng)程序提供給內(nèi)核系統(tǒng)的接口一般可以分為:本地驅(qū)動(dòng)(NativeDrivers)和流驅(qū)動(dòng)(StreamDrivers)。我從這次項(xiàng)目實(shí)踐中得到的經(jīng)驗(yàn)是,WinCE下的所有驅(qū)動(dòng)都可以歸類到這兩個(gè)里面,二者必居其一。

  流驅(qū)動(dòng)是指通過(guò)為內(nèi)核系統(tǒng)提供流接口函數(shù)來(lái)實(shí)現(xiàn)驅(qū)動(dòng)外圍設(shè)備,如XXX_Init()、XXX_Open()、XXX_Read()、XXX_Write()、XXX_Close()等。這一類的驅(qū)動(dòng)由DeviceManager來(lái)管理,它是通過(guò)調(diào)用ActivateDeviceEx()函數(shù)來(lái)實(shí)現(xiàn)加載流驅(qū)動(dòng)的。ActivateDeviceEx()的參數(shù)是注冊(cè)表中相應(yīng)的鍵,用來(lái)設(shè)定加載流驅(qū)動(dòng)的屬性,如Index、Order、Prefix等等。流驅(qū)動(dòng)加載成功后,應(yīng)用程序就可以通過(guò)調(diào)用CreateFile()、ReadFile()、WirteFile()等函數(shù)來(lái)訪問(wèn)流驅(qū)動(dòng)設(shè)備了。而與流驅(qū)動(dòng)相反,軟裝,本地驅(qū)動(dòng)提供給內(nèi)核系統(tǒng)的不是標(biāo)準(zhǔn)的流接口,而是事先約定好的特定接口。因此不同的本地驅(qū)動(dòng)設(shè)備,接口也是不一樣的。在WinCE中,常見(jiàn)的本地驅(qū)動(dòng)有LCD顯示驅(qū)動(dòng)、觸摸屏驅(qū)動(dòng)、鼠標(biāo)和鍵盤驅(qū)動(dòng)及打印機(jī)驅(qū)動(dòng)等。從這里可以看出,本地驅(qū)動(dòng)主要是涉及與人機(jī)界面相關(guān)的驅(qū)動(dòng)。它們是由GWES來(lái)管理的,由于他們?cè)谧?cè)表中有各自相應(yīng)的配置信息,因此它們會(huì)在系統(tǒng)啟動(dòng)時(shí)自動(dòng)加載。簡(jiǎn)單的說(shuō),就是本地驅(qū)動(dòng)是由內(nèi)核系統(tǒng)操作和調(diào)用的,一般的應(yīng)用程序是不能訪問(wèn)和調(diào)用的

]]>
wince驅(qū)動(dòng)開(kāi)發(fā)3http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1827&Page=1wangxinxin2010-11-26 11:16:356、驅(qū)動(dòng)中注意的要點(diǎn)

1:CE下同名設(shè)備不能大于10

CE5.0中已經(jīng)沒(méi)有這個(gè)問(wèn)題了,以前的版本可以這樣做:只給上層輸出一個(gè)設(shè)備,然后用一個(gè)IOCTL去打開(kāi)一個(gè)個(gè)的物理設(shè)備這樣就可以做到不受任何限制了。

 

2:MDD與PDD
一個(gè)驅(qū)動(dòng)程序通常會(huì)被分成硬件相關(guān)(PDD)與硬件無(wú)關(guān)(MDD)層兩部分。
當(dāng)然,這種分層不是必須的,只是采用這種分層以后可以少寫很多代碼,因?yàn)槲④浱峁┝撕芏囹?qū)動(dòng)程序的MDD。即使CE中沒(méi)有我們所寫的驅(qū)動(dòng)程序的樣例,采用這種結(jié)構(gòu)以后,當(dāng)需要寫第二個(gè)程序時(shí),就可以重用它的代碼,就可以提高開(kāi)發(fā)效率。

 

MDD是提供同類型的設(shè)備(比如串口)都會(huì)有的功能,這樣PDD基本上就只有寄存器操作了。

像串口的中斷處理,Read/Write函數(shù),其大部分代碼都是在MDD中實(shí)現(xiàn)的,不同的串口實(shí)現(xiàn)中只需要提供一些實(shí)際操作寄存器的函數(shù)。不同的驅(qū)動(dòng)程序,其MDD與PDD的接口不盡相同,

 

3:XXX_Init函數(shù)的返回句柄
通常,這個(gè)句柄是驅(qū)動(dòng)程序自己保存數(shù)據(jù)的一個(gè)指針,我們?cè)贗nit返回時(shí)告訴上層程序,以后上層調(diào)用其它函數(shù)(例如Open)時(shí),會(huì)將這個(gè)值傳入,這樣,我們就可以訪問(wèn)自己的一些私有數(shù)據(jù)。

當(dāng)然,也可以返回一個(gè)任意的非0值對(duì)于一個(gè)設(shè)備驅(qū)動(dòng)程序,系統(tǒng)不用的層會(huì)有不同的句柄。我們?cè)赬XX_Init中返回的句柄保存在設(shè)備管理器中,別的程序中應(yīng)該是看不到的,而用CreateFile也會(huì)得到一個(gè)文件句柄,這個(gè)保存在哪我不知道,但和前者是不一樣的。也就是說(shuō)不同層的軟件所關(guān)心的句柄也會(huì)不一樣

4:DEBUGMSG與RETAILMSG的區(qū)別
它們都是輸出調(diào)試信息用的,區(qū)別是:
DEBUGMSG只在DEBUG版中有效,RELEASE版中它被定義成了NULL
RETAILMSG在DEBUG和RELEASE版中都可以輸出,
而且DEBUGMSG可以在運(yùn)行時(shí)刻用DEBUZONE控制要不要輸出信息。

 

在ship build 時(shí),RETAILMSG 和DEBUGMSG都無(wú)效。

 

5調(diào)試區(qū)與dpCurSettings

我們都是利用OutpubDebugString函數(shù)來(lái)實(shí)現(xiàn)調(diào)試信息的輸出的,但是由于系統(tǒng)底層的調(diào)試信息非常繁多,如果這樣大量的調(diào)試信息用于實(shí)時(shí)輸出的話一定會(huì)影響到系統(tǒng)的性能和實(shí)時(shí)性,也就影響到了系統(tǒng)的運(yùn)行。如果有一種方式能允許開(kāi)發(fā)人員自己選擇輸出哪些調(diào)試信息,不輸出哪些調(diào)試信息的話,那么就可以讓開(kāi)發(fā)人員只看到關(guān)心的調(diào)試信息,而把諸如鍵盤按鍵、鼠標(biāo)移動(dòng)等無(wú)用的調(diào)試信息隱去,則可以更好的提高開(kāi)發(fā)效率。

 

調(diào)試區(qū)就是為了解決以上提出的問(wèn)題的,對(duì)某一個(gè)驅(qū)動(dòng)程序,它規(guī)定好自己向外輸出的調(diào)試信息的分類,比如初始化時(shí)的信息,出錯(cuò)時(shí)的信息,釋放時(shí)的信息,激活時(shí)的信息等,然后分成幾個(gè)調(diào)試區(qū),在現(xiàn)有的CE版本中最多允許16個(gè)調(diào)試區(qū)。

 

開(kāi)發(fā)人員通過(guò)Platform Builder中Target菜單下的CE Debug Zones命令來(lái)決定想要得到哪一個(gè)或哪幾個(gè)調(diào)試區(qū)的信息,在驅(qū)動(dòng)程序中則可以根據(jù)開(kāi)發(fā)人員的選擇來(lái)輸出指定調(diào)試區(qū)的信息。這就是調(diào)試區(qū)大體上的工作原理。

 

調(diào)試區(qū)的定義,聲明,注冊(cè)及使用。
在程序中使用調(diào)試區(qū)之前必須先定義它們,一個(gè)程序的16個(gè)調(diào)試區(qū)編號(hào)分別為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版本中使用調(diào)試區(qū)了,而在RELEASE版本中則將其全部定義為0,調(diào)試信息即不再輸出。
在程序中,除了以上的定義以外,還要聲明幾個(gè)專用的調(diào)試信息輸出函數(shù),這些函數(shù)與OutputDebugString函數(shù)的區(qū)別就在于在調(diào)用時(shí)需要指定對(duì)應(yīng)的調(diào)試區(qū),這些函數(shù)以及以上用到的DEBUGZONE宏的定義都在DbgApi.h頭文件中,因此只要在源程序中包含此頭文件即可。除此以外,還需要一個(gè)全局的DEBPARAM類型的變量命名為dpCurSettings,以供集成開(kāi)發(fā)環(huán)境和調(diào)試信息輸出函數(shù)使用。其代碼樣例如下:
#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調(diào)試區(qū)作為默認(rèn)被開(kāi)發(fā)人員選中的調(diào)試區(qū)。
要想使用調(diào)試區(qū),還需要做的最后一件準(zhǔn)備的事情就是在程序中進(jìn)行注冊(cè),也就是在程序啟動(dòng)時(shí)通知集成開(kāi)發(fā)環(huán)境本程序中要使用調(diào)試區(qū),這個(gè)注冊(cè)很簡(jiǎn)單,只要在程序的入口處使用DEBUGREGISTER宏即可,樣例如下:
DllEntry (
HANDLE hinstDLL,
DWORD Op,
LPVOID lpvReserved
)
{
switch (Op) {

case DLL_PROCESS_ATTACH :
DEBUGREGISTER((HINSTANCE)hinstDLL);
break;
……

 

]]>
wince6.0驅(qū)動(dòng)開(kāi)發(fā)http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1826&Page=1wangxinxin2010-11-26 11:14:16

1、基礎(chǔ)知識(shí):

1)系統(tǒng)調(diào)用是操作系統(tǒng)內(nèi)核和應(yīng)用程序之間的接口,設(shè)備驅(qū)動(dòng)程序是操作系統(tǒng)內(nèi)核和機(jī)器硬件之間的接

口。設(shè)備驅(qū)動(dòng)程序?yàn)閼?yīng)用程序屏蔽了硬件細(xì)節(jié),在應(yīng)用程序看來(lái)硬件只是一個(gè)設(shè)備文件,應(yīng)用程序可以

像操作普通文件一樣對(duì)硬件設(shè)備進(jìn)行操作。設(shè)備驅(qū)動(dòng)是內(nèi)核的一部分。

2)驅(qū)動(dòng)程序完成以下功能:
——對(duì)設(shè)備初始化和釋放;
——把數(shù)據(jù)從內(nèi)核傳送到硬件和從硬件讀取數(shù)據(jù);
——讀取應(yīng)用程序傳送給設(shè)備文件的數(shù)據(jù)和回送應(yīng)用程序請(qǐng)求的數(shù)據(jù);
——檢測(cè)和處理設(shè)備出現(xiàn)的錯(cuò)誤。

3)上層應(yīng)用程序運(yùn)行在用戶模式(非特權(quán)模式,Ring 3),代碼被嚴(yán)格約束執(zhí)行。如不能執(zhí)行硬件IO指

令。所有的這些被阻止的操作如果想運(yùn)行必須通過(guò)陷阱門來(lái)請(qǐng)求操作系統(tǒng)內(nèi)核。

4)操作系統(tǒng)內(nèi)核運(yùn)行在內(nèi)核模式(特權(quán)模式,Ring 0),可以執(zhí)行所有有效的CPU指令。包括IO操作,

可訪問(wèn)任何內(nèi)存區(qū)。

5)整個(gè)硬件系統(tǒng)資源在驅(qū)動(dòng)程序面前是赤裸裸的,驅(qū)動(dòng)可以使用所有系統(tǒng)資源,編寫驅(qū)動(dòng)程序時(shí)我們必

須格外小心驅(qū)動(dòng)代碼的邊界條件,確保它們不會(huì)損壞整個(gè)操作系統(tǒng)。

2、Windows支持的驅(qū)動(dòng):
           1)虛擬設(shè)備驅(qū)動(dòng)程序(Virtual Device Driver):Windows3.1(Windows95/98/Me)
           2)內(nèi)核模式驅(qū)動(dòng)程序(Kernel Mode Driver):Windows NT
           3)Win32驅(qū)動(dòng)程序模型(Win32 Driver Mode):從Windows98開(kāi)始使用。
其中WDM是目前主流,然而在WinCE系統(tǒng)中,由于硬件資源有限和嵌入式系統(tǒng)的特點(diǎn),對(duì)其的支持非常有

限。

3、WinCE系統(tǒng)驅(qū)動(dòng)簡(jiǎn)介:

1)WinCE畢竟是一個(gè)嵌入式系統(tǒng),有其自身的特殊性,為了提高運(yùn)行效率,所有驅(qū)動(dòng)皆為動(dòng)態(tài)鏈接庫(kù),

驅(qū)動(dòng)實(shí)現(xiàn)中可以調(diào)用所有標(biāo)準(zhǔn)的API。而在其他Windows系統(tǒng)中可能的驅(qū)動(dòng)文件還有.vxd, .sys和動(dòng)態(tài)鏈

接庫(kù)。
2)WinCE驅(qū)動(dòng)從結(jié)構(gòu)上講分為本地驅(qū)動(dòng)(Native Driver)和流接口驅(qū)動(dòng)(Stream Driver)。

——本地驅(qū)動(dòng)主要用于低級(jí)、內(nèi)置的設(shè)備。實(shí)現(xiàn)它們的接口并不統(tǒng)一,而是針對(duì)不同類型的設(shè)備相應(yīng)設(shè)

計(jì)。因此開(kāi)發(fā)過(guò)程相對(duì)復(fù)雜,沒(méi)有固定的模式,一般做法是通過(guò)移植、定制現(xiàn)有的驅(qū)動(dòng)樣例來(lái)實(shí)現(xiàn)。
——流接口驅(qū)動(dòng)是最基本的一種驅(qū)動(dòng)結(jié)構(gòu),它的接口是一組固定的流接口函數(shù),具有很高的通用性,

WinCE的所有驅(qū)動(dòng)程序都可以通過(guò)這種方式來(lái)實(shí)現(xiàn)。流接口驅(qū)動(dòng)程序通過(guò)文件系統(tǒng)調(diào)用從設(shè)備管理器和應(yīng)

用程序接收命令。該驅(qū)動(dòng)程序封裝了將這些命令轉(zhuǎn)換為它所控制的設(shè)備上的適當(dāng)操作所需的全部信息。

           流接口驅(qū)動(dòng)是動(dòng)態(tài)鏈接庫(kù),由一個(gè)叫做設(shè)備管理程序的特殊應(yīng)用程序加載、管理和卸載。與本地

驅(qū)動(dòng)程序相比,所有流接口驅(qū)動(dòng)程序使用同一組接口函數(shù)集,包括實(shí)現(xiàn)函數(shù):XXX_Init、XXX_Deinit、

XXX_Open、XXX_Close、XXX_Read、XXX_Write、XXX_PowerUp、XXX_PowerDown、XXX_Seek、

XXX_IOControl,這些函數(shù)與硬件打交道。用戶函數(shù):CreateFile、DeviceIoControl、 ReadFile、

WriteFile,這些函數(shù)方便用戶使用驅(qū)動(dòng)程序。

3)WinCE下驅(qū)動(dòng)的加載方式:

——通過(guò)GWES(Graphics, Windowing, and Events Subsystem):主要加載與顯示和輸入有關(guān)的驅(qū)動(dòng),

如鼠標(biāo)、鍵盤驅(qū)動(dòng)等。這些驅(qū)動(dòng)一般為本地驅(qū)動(dòng)。
——通過(guò)設(shè)備管理器:兩種結(jié)構(gòu)的驅(qū)動(dòng)都加載,加載的本地驅(qū)動(dòng)主要由PCMCIA Host Controller,USB

Host Controller driver,主要是總線類的驅(qū)動(dòng);流接口驅(qū)動(dòng)主要有音頻驅(qū)動(dòng),串并口驅(qū)動(dòng)。
——?jiǎng)討B(tài)加載:前兩者都是系統(tǒng)啟動(dòng)時(shí)加載的,動(dòng)態(tài)加載則允許設(shè)備掛載上系統(tǒng)時(shí)將驅(qū)動(dòng)調(diào)入內(nèi)核,主

要有外接板卡驅(qū)動(dòng),USB設(shè)備驅(qū)動(dòng)等。

4、流接口驅(qū)動(dòng)函數(shù)介紹:
1)DWORD XXX_Init(LPCTSTR pContext, LPCVOID lpvBusContext);
pContext:指向一個(gè)字符串,包含注冊(cè)表中該流接口活動(dòng)鍵值的路徑
lpvBusContext:
該函數(shù)是驅(qū)動(dòng)掛載后第一個(gè)被執(zhí)行的。主要負(fù)責(zé)完成對(duì)設(shè)備的初始化操作和驅(qū)動(dòng)的安全性檢查。由

ActiveDeviceEx通過(guò)設(shè)備管理器調(diào)用。其返回值一般是一個(gè)數(shù)據(jù)結(jié)構(gòu)指針,作為函數(shù)參數(shù)傳遞給其他流

接口函數(shù)。

2)BOOL XXX_Deinit(DWORD hDeviceContext);
hDeviceContext:XXX_Init的返回值。
整個(gè)驅(qū)動(dòng)中最后執(zhí)行。用來(lái)停止和卸載設(shè)備。由DeactivateDevice觸發(fā)設(shè)備管理器調(diào)用。成功返回TRUE



3)DWORD XXX_Open(DWORD hDeviceContext, DWORD AccessCode ,        DWORD ShareMode);
hDeviceContext:XXX_Init的返回值。
AccessCode:訪問(wèn)模式標(biāo)志,讀、寫或其他。
ShareMode:驅(qū)動(dòng)的共享方式標(biāo)志。

打開(kāi)設(shè)備,為后面的操作初始化數(shù)據(jù)就夠,準(zhǔn)備相應(yīng)的資源。應(yīng)用程序通過(guò)CreateFile函數(shù)間接調(diào)用之

。返回一個(gè)結(jié)構(gòu)指針,用于區(qū)分哪個(gè)應(yīng)用程序調(diào)用了驅(qū)動(dòng),這個(gè)值還作為參數(shù)傳遞給其他接口函數(shù)

XXX_Read、XXX_Write、XXX_Seek、XXX_IOControl。

4)BOOL XXX_Close(DWORD hOpenContext);
hOpenContext:XXX_Open返回值。
關(guān)閉設(shè)備,釋放資源。由CloseHandle函數(shù)間接調(diào)用。


5)DWORD XXX_Read(DWORD hOpenContext, LPVOID pBuffer, DWORD Count);
hOpenContext:XXX_Open返回值。
pBuffer:緩沖區(qū)指針,接收數(shù)據(jù)。
Count:緩沖區(qū)長(zhǎng)度。
由ReadFile函數(shù)間接調(diào)用,用來(lái)讀取設(shè)備上的數(shù)據(jù)。返回讀取的實(shí)際數(shù)據(jù)字節(jié)數(shù)。


6)DWORD XXX_Write(DWORD hOpenContext, LPCVOID pBuffer, DWORD Count);
hOpenContext:XXX_Open返回值。
pBuffer:緩沖區(qū)指針,接收數(shù)據(jù)。
Count:緩沖區(qū)長(zhǎng)度。
由WriteFile函數(shù)間接調(diào)用,把數(shù)據(jù)寫到設(shè)備上,返回實(shí)際寫入的數(shù)據(jù)數(shù)。

7)BOOL XXX_IOControl(DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn,      DWORD dwLenIn, PBYTE

pBufOut, DWORD dwLenOut,        PDWORD pdwActualOut);
hOpenContext:XXX_Open返回值。
dwCode:控制命令字。
pdwActualOut:實(shí)際輸出數(shù)據(jù)長(zhǎng)度。

用于向設(shè)備發(fā)送命令,應(yīng)用程序通過(guò)DeviceIoControl調(diào)用來(lái)實(shí)現(xiàn)該功能。要調(diào)用這個(gè)接口還需要在應(yīng)用

層和驅(qū)動(dòng)之間建立一套相同的命令,通過(guò)宏定義CTL_CODE(DeviceType, Function, Method, Access來(lái)實(shí)

現(xiàn)。如:

#define IOCTL_INIT_PORTS \ CTL_CODE

(FILE_DEVICE_UNKNOWN,0X801,METHOD_BUFFERED,FILE_ANY_ACCESS)

8)void XXX_PowerDown(DWORD hDeviceContext);

hDeviceContext:XXX_Init的返回值。

]]>
WinCE下驅(qū)動(dòng)開(kāi)發(fā)入門記錄(一)http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1825&Page=1wangxinxin2010-11-26 11:11:21        首先說(shuō)明一下,我可能仍然是個(gè)門外漢,因?yàn)橐郧盎緵](méi)做過(guò)和硬件相關(guān)的東西,這方面知識(shí)缺乏的要命,現(xiàn)在公司要求做個(gè)驅(qū)動(dòng)出來(lái),也只有硬著頭皮上了,學(xué)習(xí)研究了兩天,基本掌握了一些有用的信息,所以認(rèn)為自己入門了,但僅從自己的感覺(jué)出發(fā)都可以說(shuō)我只是窺見(jiàn)了冰山之一角,還有很多很多都不懂。上次的帖子里面介紹了一些當(dāng)時(shí)收集到的比較有用的資料,那個(gè)PB我也試著下了,下了一兩天沒(méi)多少,公司網(wǎng)太破,那個(gè)ftp又不支持?jǐn)帱c(diǎn)續(xù)傳,可害苦了我了,一個(gè)個(gè)的文件包100多M,一掉線就得重來(lái),最后我干脆放棄了。那個(gè)弟兄有的,干脆打個(gè)包把代碼發(fā)給我好了,謝謝了先。
         好,怎們切入正題。首先介紹一下我的驅(qū)動(dòng)目標(biāo),目的是為了使在pda上運(yùn)行的應(yīng)用程序能夠通過(guò)USB口和我們這個(gè)外設(shè)通訊,可以發(fā)送指令給外設(shè),也要求從外設(shè)獲取數(shù)據(jù),因此我把它定位在流接口上,這就引出第一個(gè)概念,流接口,應(yīng)該說(shuō)這里所說(shuō)的流接口是Wince上驅(qū)動(dòng)的一種,象串口啊這樣的可以用CreateFile打開(kāi)的都屬于這個(gè)范疇。其關(guān)鍵在于1)實(shí)現(xiàn)xxx_系列的函數(shù)2)注冊(cè)表中定義Prefix和Dll。其中xxx就是注冊(cè)表中Prefix的值,比如串口就是“COM”。而注冊(cè)表中的DLL就是你的驅(qū)動(dòng)程序dll(wince下的驅(qū)動(dòng)就是一個(gè)dll),加載驅(qū)動(dòng)的時(shí)候,會(huì)到你的dll中去找xxx_系列的函數(shù),所以你的dll一定要導(dǎo)出這些函數(shù)符號(hào)。
XXX_Init
XXX_Deinit
XXX_Open
XXX_Close
XXX_Read
XXX_Write
XXX_Seek
XXX_IOControl
XXX_PowerDown
XXX_PowerUp
經(jīng)過(guò)測(cè)試,其中前六個(gè)是必須實(shí)現(xiàn)且導(dǎo)出的,否則是不能夠成功加載的。

         好,先介紹了一些關(guān)于流接口驅(qū)動(dòng)的相關(guān)知識(shí),這部分在網(wǎng)上還是能夠找到不少資料的,我就不多說(shuō),回到我要開(kāi)發(fā)的驅(qū)動(dòng)上,說(shuō)到底我這個(gè)還首先是個(gè)USB設(shè)備,被識(shí)別之后才能將它驅(qū)動(dòng)成一個(gè)流設(shè)備
        說(shuō)到USB驅(qū)動(dòng),就要先介紹一下USB驅(qū)動(dòng)加載過(guò)程了。當(dāng)usb設(shè)備接到主機(jī)(usb host,因此你的pda必須是能夠作為usb host使用的)上時(shí),系統(tǒng)就會(huì)根據(jù)它的信息去從注冊(cè)表里查找它的驅(qū)動(dòng)相關(guān)信息,在HKLM\Drivers\Usb\LoadClients下面會(huì)有一些主鍵Group1_ID\Group2_ID\Group3_ID\DeviceID,而DeviceID下面有一個(gè)字符串Dll=DriverFile.dll
注意,其中Group1_ID,Group2_ID,Group3_ID分別表示什么,以及其匹配的優(yōu)先級(jí)別,可以在《WindowsCE 驅(qū)動(dòng)開(kāi)發(fā)指南》一書(shū)中USB驅(qū)動(dòng)開(kāi)發(fā)一章去詳細(xì)研究。
         如果找到匹配的注冊(cè)表信息,系統(tǒng)就會(huì)加載DriverFile.dll,否則就會(huì)提示用戶輸入一個(gè)驅(qū)動(dòng)名稱。
         那么加載dll的時(shí)候會(huì)有些什么動(dòng)作呢?驅(qū)動(dòng)程序DLL和普通的DLL是否具備不同的入口點(diǎn)呢?
         先回答第二個(gè)問(wèn)題,答案是否定的,其入口點(diǎn)和普通的dll沒(méi)有區(qū)別。但是加載的過(guò)程就不那么簡(jiǎn)單了。你可以理解系統(tǒng)已經(jīng)作了一些事情,使得你可以用一個(gè)普通的dll來(lái)作為驅(qū)動(dòng)程序,但是顯然,你必須實(shí)現(xiàn)系統(tǒng)所要求的接口函數(shù)。
         對(duì)于USB驅(qū)動(dòng)程序來(lái)說(shuō),有這么幾個(gè)接口函數(shù)是必須實(shí)現(xiàn)且導(dǎo)出的:
BOOL USBDeviceAttach(USB_HANDLE hDevice,
                                    LPCUSB_FUNCS lpUsbFuncs, 
                                    LPCUSB_INTERFACE lpInterface,
                                    LPCWSTR szUniqueDriverId, 
                                    LPBOOL fAcceptControl,
                                    LPCUSB_DRIVER_SETTINGS lpDriverSettings,
                                     DWORD dwUnused);
BOOL USBInstallDriver(LPCWSTR szDriverLibFile);
BOOL USBUnInstallDriver();
          建議大家先讀一下sdk的include目錄下的usbdi.h頭文件,這里面定義了很多usb驅(qū)動(dòng)相關(guān)的結(jié)構(gòu)、函數(shù)接口,包括注釋]]>
WinCE5.0入門全過(guò)程http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1824&Page=1wangxinxin2010-11-26 11:10:30以下內(nèi)容僅供參考,由于我也是初學(xué)者,很多概念理解不準(zhǔn),錯(cuò)誤與模糊之處還請(qǐng)大家指出,以利于我們大家共同學(xué)習(xí)與提高!
以下內(nèi)容不接受任何攻擊性評(píng)論,學(xué)習(xí)WinCE是我現(xiàn)階段本科畢業(yè)設(shè)計(jì)的內(nèi)容,所以所有觀點(diǎn)僅從學(xué)術(shù)角度出發(fā),如果有說(shuō)的不當(dāng)之處,希望大家多多指點(diǎn)!
再說(shuō)明一下,如果本帖中有什么其它問(wèn)題,比如言之不當(dāng)之處,希望大家另開(kāi)一帖,在論壇里討論一下,標(biāo)題注明一下jbb0523,我這些天會(huì)常來(lái)論壇看看的,這樣大家就共同提高了!

一、前言

1、首先談?wù)劚救嘶A(chǔ)。我熟悉AVR單片機(jī),使用過(guò)ATmega16單片機(jī)大部分功能,如4X4鍵盤、UART、SPI、I2C、Timer、PWM等等,接觸過(guò)DSP芯片TMS320C54X,懂得VHDL語(yǔ)言,簡(jiǎn)單使用過(guò)LPC2131,并在其上移植過(guò)uC/OS-II,學(xué)習(xí)過(guò)有關(guān)操作系統(tǒng)的基本知識(shí)。
用過(guò)的相關(guān)軟件有:ICCAVR、ADS1.2、CCS、uVision等。

2、學(xué)習(xí)不要著急,如果你沒(méi)有操作系統(tǒng)的基礎(chǔ),可能一時(shí)接受不了操作系統(tǒng)這個(gè)概念,而是拿著自已天天用的PC機(jī)的Windows操作系統(tǒng)的界面鉆牛角尖。不要總感覺(jué)這資料是垃圾,那本書(shū)是騙錢的,之所以你看不懂那是因?yàn)槟氵€沒(méi)達(dá)到看懂的程度!當(dāng)然現(xiàn)在騙錢的書(shū)很多,著書(shū)者很少?gòu)淖x者的角度去寫書(shū)!

3、我所使用的開(kāi)發(fā)環(huán)境:PC XP+GEC2440+WinCE5.0+VS2008+ActiveSync4.5+DNW
GEC2440是廣嵌科技術(shù)的開(kāi)發(fā)板,不喜歡廣嵌,售后技術(shù)支持做的不好,而且技術(shù)論壇也沒(méi)人回帖,不建議使用本實(shí)驗(yàn)板!其實(shí)板子做的還行,只是相關(guān)服務(wù)有待加強(qiáng)!!!

二、入門準(zhǔn)備

1、什么是操作系統(tǒng)?
這個(gè)問(wèn)題是困擾了我很久的問(wèn)題。由于我們大家對(duì)于Windows XP等PC機(jī)操作系統(tǒng)過(guò)于熟悉,而此操作系統(tǒng)又過(guò)于傻瓜式,以致于使我們感覺(jué)不到操作系統(tǒng)的本質(zhì),僅感覺(jué)操作系統(tǒng)就是一個(gè)窗口,反正在我接觸嵌入式操作系統(tǒng)前是這樣認(rèn)為的。那么什么是操作系統(tǒng)呢?從我使用uC/OS-II的體驗(yàn)來(lái)說(shuō),簡(jiǎn)單點(diǎn)兒說(shuō)操作系統(tǒng)就是一個(gè)調(diào)度器,從我現(xiàn)在使用WinCE的體驗(yàn)來(lái)說(shuō),操作系統(tǒng)就是管家婆。總的來(lái)說(shuō)吧,操作系統(tǒng)就是用算法實(shí)現(xiàn)的管理系統(tǒng)所有資源一個(gè)后臺(tái)。可能這樣說(shuō)還是有些抽象,別急,慢慢來(lái)!

2、操作系統(tǒng)安裝在哪兒呢?界面呢?
這個(gè)問(wèn)題絕對(duì)是Windows操作系統(tǒng)使用后遺癥,總感覺(jué)操作要像我們PC機(jī)裝系統(tǒng)一樣進(jìn)行安裝,要有像XP等OS一樣的操作界面。其實(shí)界面僅僅是人機(jī)交互的一種方式而已,不是操作系統(tǒng)必備的元素,而是操作系統(tǒng)的一種趨勢(shì),因?yàn)楝F(xiàn)在對(duì)友好的人機(jī)交互界面要求越來(lái)越高,而且是傻瓜程度過(guò)高越好!
以u(píng)C/OS-II為例,它的核代碼就是幾個(gè)C源文件,使用它時(shí)將其像其它程序一樣加入你所建立的工程即可,當(dāng)然在uC/OS-II與你所寫的普通代碼之間要有一個(gè)橋梁來(lái)進(jìn)行鏈接,這個(gè)橋梁就是我們?cè)谝浦膊僮飨到y(tǒng)時(shí)所要寫的文件,它根本沒(méi)有界面一說(shuō),為什么說(shuō)它是操作系統(tǒng)呢?因?yàn)閡C/OS-II有操作系統(tǒng)的一切特征!操作系統(tǒng)都有什么特征呢?自已網(wǎng)上查一吧!
那么移值uC/OS-II在CPU上有什么好處呢?個(gè)人認(rèn)為,操作系統(tǒng)的核心好處在于多作務(wù)管理與調(diào)度。任務(wù)較少時(shí),也許感覺(jué)不到它的好處,但任務(wù)多了,操作系統(tǒng)的好處就明顯了,比如說(shuō)吧,你的實(shí)驗(yàn)板上有八個(gè)LED,要求你實(shí)現(xiàn)這八個(gè)LED以八種不同頻率進(jìn)行閃爍,你該怎么寫呢?如果有了uC/OS-II操作系統(tǒng),這就太簡(jiǎn)單了,將每個(gè)LED閃爍按uC/OS-II要求形式寫成任務(wù),然后將八個(gè)任務(wù)交由uC/OS-II調(diào)度即可!
說(shuō)了一大堆uC/OS-II的相關(guān)內(nèi)容,下面進(jìn)入正題,談WinCE!

3、相關(guān)術(shù)語(yǔ)
0)PC機(jī)(Personal Computer)就是指你的電腦,OS(Operating System)是指操作系統(tǒng)!
1)BSP(Board Support Package,板級(jí)支持包),介于硬件平臺(tái)和操作系統(tǒng)之間的一層,屬于操作系統(tǒng);不同的操作系統(tǒng)對(duì)應(yīng)于不同定義形式的BSP。
2)Bootloader與BIOS:Bootloader是引導(dǎo)程序,就是對(duì)實(shí)驗(yàn)平臺(tái)進(jìn)行初始化,設(shè)定一些相關(guān)參數(shù)等等。就我現(xiàn)在使用的WinCE5.0來(lái)說(shuō),根據(jù)個(gè)人理解,Bootloader與BIOS是一個(gè)東西,就是在ADS1.2下的一個(gè)工程而已,里面含有start.s及其它的一些相關(guān)代碼。這個(gè)現(xiàn)在我還有些模糊,僅談到此。
3)OEM:Original Equipment Manufacturer原始設(shè)備制造商
4)OAL:OEM Abstraction Layer
5)DLL:Dynamic Link Library,動(dòng)態(tài)鏈接庫(kù) 
6)MFC:Microsoft Foudation Class,微軟基礎(chǔ)類 
7)API:Win32 Application Programming Interface,Win32應(yīng)用程序編程接口
8)SDK:Software Development Kit,使用WinCE時(shí)必須安裝SDK,你不必在網(wǎng)上找SDK的安裝包,對(duì)于每個(gè)具體實(shí)驗(yàn)板都對(duì)于一個(gè)SDK,這個(gè)可以用PB生成。
9)PB、VS、EVC:PB是Platform Builder的簡(jiǎn)稱,VS是Visual Studio的簡(jiǎn)稱,EVC是Embedded Visual C++的簡(jiǎn)稱。
10)Nand flash與Nor flash:與非flash和或非flash,前者價(jià)格便宜,后者較貴。

4、所需開(kāi)發(fā)軟件
1)Platform Builder 5.0:此軟件用來(lái)定制操作系統(tǒng),生成內(nèi)核,生成SDK,編譯驅(qū)動(dòng)程序等。
2)Visual Studio 2008:我用的是此版本,當(dāng)然也許不許這么高版本,網(wǎng)上用的多的是VS2005,還有使用EVC++的。此軟件用來(lái)編寫應(yīng)用程序。
3)ActiveSync 4.5:此軟用來(lái)同步PC機(jī)與實(shí)驗(yàn)板進(jìn)行同步。此軟件可以在微軟中國(guó)官方網(wǎng)站下載。
4)DNW:串口調(diào)試工具,在上電時(shí)用來(lái)顯示BIOS發(fā)往串口的相關(guān)信息,也可以輸入相關(guān)參數(shù)進(jìn)行設(shè)置的。
5)USB同步驅(qū)動(dòng):必備!!!
VS2008的安裝按提示按裝即可,PB5.0的安裝可以參考天嵌科技的手冊(cè)進(jìn)行安裝,講的很好很詳細(xì),至于PB5.0補(bǔ)丁的安裝只需安裝Net2.0與Net3.5的那一個(gè)即可,其實(shí)安裝與否我原由我也不清楚,好好參考天嵌科技術(shù)的手冊(cè)吧。另外要參考天嵌科技術(shù)的手冊(cè)添加BSP,生成相應(yīng)的SDK,然后安裝SDK,這些都安裝好后還有一個(gè)工作就是安裝USB驅(qū)動(dòng),這一關(guān)一定要過(guò),安不上的話就等著安上再說(shuō)!

5、相關(guān)參考書(shū)目:
何宗鍵 編著.Windows CE嵌入式系統(tǒng).北京:北京航空航天大學(xué)出版社
還有就是各個(gè)開(kāi)發(fā)板廠商的使用手冊(cè)都是很好的資料,必備!
主要有天嵌科技TQ2440、朗成電子AT2440EVB、友善之臂mini2440和QQ2440、廣嵌科技GEC2440、飛凌等等,只有飛凌的資料是不公開(kāi)的,其它的都可以在相關(guān)網(wǎng)站下載到。
有關(guān)Visual Studio的書(shū)可以參考一下機(jī)械工業(yè)出版社劉冰等編著的《C++程序設(shè)計(jì)教程——基于Visual Studio 2008》,這本書(shū)我也沒(méi)細(xì)看過(guò),掃了一眼,講的還抽合吧。

三、打開(kāi)WinCE的大門

0、我的學(xué)習(xí)方法
我學(xué)習(xí)的理念是首先把整套開(kāi)發(fā)環(huán)境搭建起來(lái),然后運(yùn)行一個(gè)最簡(jiǎn)單的程序入門再說(shuō),至于更深一層次的內(nèi)容慢慢研究!
1、開(kāi)發(fā)平臺(tái)的建立
個(gè)人認(rèn)為,學(xué)習(xí)單片機(jī)也好,ARM也罷,首先要解決的事情就是將整套開(kāi)發(fā)環(huán)境搭建好,成功跑一個(gè)最簡(jiǎn)單的程序,就算入門了,下面我說(shuō)說(shuō)WinCE開(kāi)發(fā)環(huán)境的建立。

1)安裝VS2008,根據(jù)提示安裝即可,沒(méi)什么注意事項(xiàng),唯一的提示就是要留有足夠的硬盤空間,僅VS就得留2G空間吧,如果安裝MSDN幫助文檔的話,再留3G吧!
安裝好VS后初次打開(kāi)會(huì)讓你選擇默認(rèn)開(kāi)發(fā)環(huán)境,有1、Visual Basic 開(kāi)發(fā)設(shè)置;2、Visual C#開(kāi)發(fā)設(shè)置;3、Visual C++開(kāi)發(fā)設(shè)置;4、Web開(kāi)發(fā)設(shè)置;5、常規(guī)開(kāi)發(fā)設(shè)置。個(gè)人認(rèn)為選哪一個(gè)都無(wú)所謂,差別僅在于新建項(xiàng)目時(shí)項(xiàng)目類型一欄的排列順序有所差別而已。這個(gè)設(shè)置可以按如下更改:工具---》導(dǎo)入和導(dǎo)出設(shè)置(I)…---》重置所有設(shè)置---》否,僅重置設(shè)置,從而覆蓋我的當(dāng)前設(shè)置
2)安裝Microsoft_DotNetFXCHS1.1.exe,這是安裝WinCE的前提,如果你電腦上裝過(guò)VC++等軟件,應(yīng)該就不用安裝了,因?yàn)閂isual Studio系列軟件都需要這個(gè)的。
3)安裝Platform Builder5.0,安裝PB其實(shí)就是所謂的安裝WinCE,這個(gè)參考天嵌的手冊(cè)1.1節(jié)內(nèi)容安裝即可,有一點(diǎn)天嵌手冊(cè)中沒(méi)提到的是:
圖片點(diǎn)擊可在新窗口打開(kāi)查看
 (原文件名:PB安裝.jpg) 
引用圖片

安裝選擇處理器到這一步時(shí)如果ARMV4I是一個(gè)“×”,則應(yīng)單擊向下的小黑三角,選擇第一個(gè)或第二個(gè)選項(xiàng),其它的我也不是很懂,反正第一次入門多安裝了總比不能用好,以后精通了再選擇最優(yōu)方法吧。
4)安裝WinCEPB50-081231-Product-Update-Rollup-Armv4I.msi,這是PB5.0的一個(gè)補(bǔ)丁,網(wǎng)上相關(guān)文章千篇一率,寫了一大堆補(bǔ)丁,個(gè)人認(rèn)為安裝這個(gè)就足夠了,其它的等你用到時(shí)再安吧,我用了這么些天也沒(méi)感覺(jué)到補(bǔ)丁有什么用。
5)安裝ActiveSync4.5,這個(gè)很簡(jiǎn)單!安裝完后打開(kāi)“我的電腦”就會(huì)有一個(gè)“移動(dòng)設(shè)備”圖標(biāo),這個(gè)以后有用!
6)DNW不用安裝,是一個(gè)綠色版的軟件,累似于串口調(diào)試助手,但功能強(qiáng)一些吧!
7)安裝USB同步用驅(qū)動(dòng),用USB線將實(shí)驗(yàn)板與PC機(jī)連接起來(lái)會(huì)提示安裝驅(qū)動(dòng),這個(gè)實(shí)驗(yàn)板廠商應(yīng)該會(huì)提供的,也可以從網(wǎng)上下載!USB驅(qū)動(dòng)安裝不當(dāng)會(huì)導(dǎo)致PC機(jī)藍(lán)屏,所以這一步必須過(guò)關(guān),否則原地待命!
8)添加BSP:打開(kāi)PB5.0,添加BSP包,BSP是由廠商提供的,別告訴我實(shí)驗(yàn)板是你自已做的,一上手就寫B(tài)SP有點(diǎn)不現(xiàn)實(shí)吧。參考天嵌手冊(cè)2.1.1節(jié)內(nèi)容,很輕松搞定!
9)安裝SDK:參考天嵌手冊(cè)2.4節(jié)內(nèi)容很輕松搞定,然后安裝即可!
到現(xiàn)在為止環(huán)境基本搞定,其它相關(guān)細(xì)節(jié)參考開(kāi)嵌手冊(cè)即可!

2、什么叫定制操作系統(tǒng)?為什么要安裝WinCE到PC機(jī)上?
由于受uC/OS-II操作系統(tǒng)的影響,總想著WinCE的源代碼在哪兒?那些API函數(shù)的原型在哪兒頭文件中?須知uC/OS-II的源代碼是開(kāi)源的,而WinCE的代碼則相反!uC/OS-II的呈現(xiàn)在我們面前的是幾個(gè)C語(yǔ)言源文件,WinCE呢?就我現(xiàn)在的理解,將PB5.0裝到PC機(jī)上意味著將WinCE的全部功能放到了PC機(jī)上,然后我們需要做的是通過(guò)PB從WinCE所有功能中挑選出自已需要的功能,這些功能經(jīng)自已通過(guò)PB組合后生成一個(gè)NK.bin和NK.nb0文件,關(guān)于這兩個(gè)的區(qū)別參考天嵌手冊(cè)的第92頁(yè),具體我也不太懂。但我個(gè)人的理解是,生成的NK.nb0就好像是我們?cè)趯W(xué)單片機(jī)時(shí)生成的hex文件,我們將.nb0燒到實(shí)驗(yàn)板上也就是將我們裁剪(即所謂的定制!!!)好的WinCE“安裝”到實(shí)驗(yàn)板上了,這個(gè)過(guò)程可以近似理解為將hex文件通過(guò)ISP或其它方式燒到單片機(jī)里一樣的。
綜上所述,我們安裝PB在PC機(jī)上是將WinCE所有功能“暫時(shí)放到”PC機(jī)上,然后通過(guò)PB“挑出”你所需要的功能后并將其組合(即.nb0文件)“放到”實(shí)驗(yàn)板上即可!
打個(gè)比方說(shuō)吧,WinCE各種功能就好像一塊塊積木(即安裝PB),然后我們用需要的積木搭出我們需要圖形(即我們用PB定制的操作系統(tǒng))。
WinCE代碼是不開(kāi)源的,不要天天去想API函數(shù)在哪兒呢?真想看的話去找找比爾蓋茨看看能不能讓你看看!

3、Bootloader(BIOS)、WinCE核(即nb0文件)及我們用VS編寫的應(yīng)用程序怎么燒到實(shí)驗(yàn)板上?都燒在哪里了呢?
1)Bootloaer與BIOS的區(qū)別我還沒(méi)搞懂,就現(xiàn)在的理解還是將它們合二為一,這個(gè)有待解決。它們可以用sjf2440.exe進(jìn)行燒寫;燒到哪兒了呢?這個(gè)由自已設(shè)定,我也沒(méi)有燒過(guò),只有一個(gè)粗略的理解:S3C2440外擴(kuò)了Nand flash和Nor flash,還有SDRAM,芯片內(nèi)部也有(應(yīng)該有吧?),這里我們不用管內(nèi)部與外部,這個(gè)只要按要求進(jìn)行外擴(kuò)后用尋址到什么地址CPU會(huì)自動(dòng)找相關(guān)存儲(chǔ)空間的。我們可以將所有的flash看成一個(gè)整體,它是用來(lái)固化程序的,把所有RAM看成一個(gè)整體,它是用來(lái)運(yùn)行程序的。我們將flash分成不同的分區(qū),上電時(shí)CPU要從根據(jù)設(shè)定的起始地址的代碼開(kāi)始執(zhí)行,個(gè)人認(rèn)為Bootloader應(yīng)該就燒在這里吧!這里的理解個(gè)人還有待加強(qiáng),僅供參考!
2)WinCE核可以通過(guò)過(guò)USB等方式下載到實(shí)驗(yàn)板上,比如用DNW就可以進(jìn)行下載,之所以下載到哪兒了?下載到flash其中的一個(gè)分區(qū),具體由Bootloader引導(dǎo)程序和你自已設(shè)定的參數(shù)!CPU再聰明還得聽(tīng)人的指揮!
3)VS編的應(yīng)用程序燒在哪兒了?這個(gè)我還沒(méi)弄明白,我是通過(guò)ActiveSync將VS生成的.exe文件發(fā)送到實(shí)驗(yàn)板上或直接復(fù)制到實(shí)驗(yàn)板上的。怎么粘呢?安裝好ActiveSync后PC機(jī)的“我的電腦”會(huì)多一個(gè)移動(dòng)設(shè)備圖標(biāo),如果你的USB同步驅(qū)動(dòng)安裝好的,雙擊“移動(dòng)設(shè)備”其實(shí)就是相當(dāng)于在遠(yuǎn)程控制著實(shí)驗(yàn)板,將VS的應(yīng)用程序復(fù)制過(guò)來(lái)然后在實(shí)驗(yàn)板端相關(guān)目錄下找到應(yīng)用程序運(yùn)行即可!不過(guò)這樣運(yùn)行應(yīng)用程序是在RAM中運(yùn)行,沒(méi)有進(jìn)行固化,至于怎么固化,我再好好研究!
4)這里一直提到flash分區(qū)的問(wèn)題,至于究竟是怎么分區(qū)的目前我也不是很懂,個(gè)人認(rèn)為是通過(guò)bootloader進(jìn)行相關(guān)設(shè)計(jì)的吧,在以前接觸LPC2131時(shí)似乎看到過(guò)相關(guān)內(nèi)容。

四、走進(jìn)WinCE

以下默認(rèn)開(kāi)發(fā)平臺(tái)所有軟件已安裝完畢:

1、燒寫B(tài)ootloader(沒(méi)燒過(guò),只是這樣認(rèn)為要首先燒寫B(tài)IOS)
2、燒寫WinCE核
由于本人拿到實(shí)驗(yàn)板時(shí)以上兩步已做好,即我拿到的實(shí)驗(yàn)板上就有燒好的WinCE5.0操作系統(tǒng),因此以上兩步是我猜測(cè)的!
3、打開(kāi)VS,按照天嵌手冊(cè)4.2節(jié)內(nèi)容進(jìn)行操作,如果成功運(yùn)行,則OK!本步驟成功后則說(shuō)明平臺(tái)搭建成功,但HELLO程序不涉及實(shí)驗(yàn)板上的任何具體硬件,個(gè)人認(rèn)為這只能算是入門了一半,還有一個(gè)坎沒(méi)邁過(guò)去,那就是流驅(qū)動(dòng)的開(kāi)發(fā),因?yàn)殚_(kāi)發(fā)第一個(gè)流驅(qū)動(dòng)的工作量并不比搭建平臺(tái)省事,尤其是全靠自已琢磨,旁邊無(wú)人指導(dǎo)、無(wú)人探討!
4、運(yùn)行成功HELLO程序后你可能會(huì)想,如果想點(diǎn)亮實(shí)驗(yàn)板上的LED燈該怎么用啊?基于VS開(kāi)發(fā)環(huán)境也沒(méi)法控制CPU的IO寄存器啊?這就需要流驅(qū)動(dòng)了!
大部分實(shí)驗(yàn)板的手冊(cè)都有詳細(xì)的HELLO程序過(guò)程,但很少有手冊(cè)詳細(xì)講解流驅(qū)動(dòng)的開(kāi)發(fā)過(guò)程,下面以我的經(jīng)歷詳細(xì)的寫一寫:
流驅(qū)動(dòng)的基本介紹可以看看天嵌手冊(cè)的第五章,腦子里起碼要先有個(gè)基本概念!
1)打開(kāi)以下目錄:E:\WINCE500\PLATFORM\smdk2440\DRIVERS,并在該目錄下新建一個(gè)文件夾,命名為GPIOdriver,并用記事本打開(kāi)該目錄下的dirs文件,按其格式添加\GPIOdriver,dirs沒(méi)有擴(kuò)展名,打開(kāi)看看就懂,沒(méi)什么特別的!
注:其中E盤是我的安裝目錄,smdk2440是GEC2440實(shí)驗(yàn)板提供的BSP,按要求拷貝到了E:\WINCE500\PLATFORM\ 目錄。
2)打開(kāi)剛剛新建的GPIOdriver文件夾,新建txt記事本文件,命名為makefile,打開(kāi)加入以下內(nèi)容:!INCLUDE $(_MAKEENVROOT)\makefile.def,然后將.txt擴(kuò)展名去掉,使其變?yōu)闊o(wú)擴(kuò)展名的文件。
3)仍然在GPIOdriver文件夾內(nèi),仍然新建txt文件,命名為GPIOdriver,加入以下內(nèi)容后將其擴(kuò)展名更改為.def文件:
LIBRARY GPIOdriver
EXPORTS
GIO_Close
GIO_Deinit
GIO_Init
GIO_IOControl
GIO_Open
GIO_PowerDown
GIO_PowerUp
GIO_Read
GIO_Seek
GIO_Write
4)仍然在GPIOdriver文件夾內(nèi),仍然新建txt文件,命名為sources,加入以下內(nèi)容后將其擴(kuò)展名刪除,使其成為無(wú)擴(kuò)展名文件:
RELEASETYPE=PLATFORM
TARGETNAME=GPIODriver
TARGETTYPE=DYNLINK
DLLENTRY=DllEntry
]]>
Windows CE下驅(qū)動(dòng)開(kāi)發(fā)基礎(chǔ)http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1823&Page=1wangxinxin2010-11-26 11:07:19嵌入式開(kāi)發(fā)版以來(lái)第一次發(fā)表文章,加上以前瑣碎的文章共計(jì)30篇。研究的越多就越感覺(jué)自己懂的太少,其實(shí)在驅(qū)動(dòng)開(kāi)發(fā)方面我還是個(gè)菜鳥(niǎo),我是想再次拋磚引玉,讓做驅(qū)動(dòng)有N年經(jīng)驗(yàn)的人奉獻(xiàn)一點(diǎn)出來(lái),讓大家減少一些研究驅(qū)動(dòng)源碼而又缺少注釋所帶來(lái)的痛苦。
  我想即使讀者看過(guò)微軟的關(guān)于驅(qū)動(dòng)開(kāi)發(fā)的培訓(xùn)教材和CE幫助文檔中的驅(qū)動(dòng)部分,頭腦中仍然一片茫然。要想真正了解驅(qū)動(dòng)程序必須結(jié)合一些驅(qū)動(dòng)程序源碼,在此我以串口驅(qū)動(dòng)程序(COM16550)中初始化過(guò)程為線索簡(jiǎn)單講一講驅(qū)動(dòng)開(kāi)發(fā)的基礎(chǔ)知識(shí)。
Windows CE下的串口驅(qū)動(dòng)程序能夠處理所有I/O行為類似串口的設(shè)備,包括基于16450、16550 UART(通用異步收發(fā)芯片)的設(shè)備和一些采用DMA的設(shè)備,常見(jiàn)的有9針串口、紅外I/O口、Modem等。在%_WINCEROOT%\Public\Common\OAK\Drivers\Serial目錄下,COM_MDD2子目錄包含新的串口驅(qū)動(dòng)MDD層函數(shù)代碼。COM16550子目錄包含串口驅(qū)動(dòng)PDD層代碼。SER16550子目錄包含的一系列函數(shù)專用于控制與16550兼容的UART,這樣PDD層的主要工作就是調(diào)用SER16550中的函數(shù)。還有一個(gè)ISR16550子目錄包含的是串口驅(qū)動(dòng)程序?qū)S玫目砂惭bISR(中斷服務(wù)例程),而很多硬件設(shè)備驅(qū)動(dòng)程序采用CE默認(rèn)的可安裝ISR giisr.dll。一般串口設(shè)備相應(yīng)的注冊(cè)表設(shè)置例子及意義如下:
意義
"SysIntr"=dword:13 串口1的中斷ID為十進(jìn)制13
"IoBase"=dword:02F8 串口1的IO空間首地址為十六進(jìn)制2F8
"IoLen"=dword:8 串口1的IO空間長(zhǎng)度為8個(gè)字節(jié)
"DeviceArrayIndex"=dword:0 串口1的索引,是1的由來(lái)
"Order"=dword:0 串口1驅(qū)動(dòng)的加載順序
"DeviceType"=dword:0 串口1的設(shè)備類型
"DevConfig"=hex: 10,00 .... 串口1在與Modem設(shè)備通訊時(shí)的配置,如波特率、奇偶校檢等
"FriendlyName"="COM1:" 串口1在撥號(hào)程序中顯示的名字
"Tsp"="Unimodem.dll" 串口1 被用于與Modem設(shè)備通訊的時(shí)候要加載的TSP(TAPI Service provider)DLL
"Prefix"="COM" 串口1的流接口的前綴
"Dll"="com16550.Dll" 串口1的驅(qū)動(dòng)程序DLL

  SysIntr由CE在文件Nkintr.h中預(yù)定義,用于唯一標(biāo)識(shí)中斷設(shè)備。OEM可以在文件Oalintr.h中定義自己的SysIntr。常見(jiàn)的預(yù)定義SysIntr有SYSINTR_NOP(中斷只由ISR處理,IST不再處理),SYSINTR_RESCHED(重新調(diào)度線程),SYSINTR_DEVICES(由CE預(yù)定義的設(shè)備中斷ID的基值),SYSINTR_PROFILE、SYSINTR_TIMING、SYSINTR_FIRMWARE等都是基于SYSINTR_DEVICES定義的。IoBase是串口1的IO地址空間的首地址,IoLen是IO空間的大小。IO地址空間只存在于x86平臺(tái),如果在其它平臺(tái)硬件寄存器必須映射到物理地址空間,那子鍵的名稱為MemBase和MemLen。在x86平臺(tái)更多硬件的寄存器由于IO空間的局限也映射到物理地址空間。DeviceArrayIndex是設(shè)備的索引,用于區(qū)分同類型的設(shè)備。Prefix是流驅(qū)動(dòng)程序的前綴,當(dāng)應(yīng)用程序調(diào)用CreateFile函數(shù)傳遞COM1:參數(shù)時(shí),文件系統(tǒng)負(fù)責(zé)與串口驅(qū)動(dòng)程序通信,串口驅(qū)動(dòng)程序是在CE啟動(dòng)時(shí)由device.exe加載的。

  下面從MDD層函數(shù)COM_Init開(kāi)始探索串口驅(qū)動(dòng)的初始化過(guò)程。COM_Init是在串口設(shè)備被檢測(cè)后由設(shè)備管理器device.exe調(diào)用的,主要的作用是初始化設(shè)備,它的唯一參數(shù)Identifier是由device.exe傳遞的,其類型是一個(gè)字符串指針,字符串的內(nèi)容是HLM\Drivers\Active\xx,xx是一個(gè)十進(jìn)制數(shù)(device.exe會(huì)跟蹤系統(tǒng)中每個(gè)驅(qū)動(dòng)程序,把加載的驅(qū)動(dòng)程序記錄在Active鍵下)。COM_Init先分配一個(gè)HW_INDEP_INFO結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體是獨(dú)立于串口硬件的頭信息(MDD、PDD、SER16550都包含自己獨(dú)特的結(jié)構(gòu)體,具體的結(jié)構(gòu)體定義請(qǐng)參見(jiàn)串口驅(qū)動(dòng)源碼),分配之后再初始化結(jié)構(gòu)體中每個(gè)成員,初始化結(jié)構(gòu)體后調(diào)用 OpenDeviceKey((LPCTSTR)Identifier)打開(kāi)HLM\Drivers\Active\xx\Key包含的注冊(cè)表路徑,在這里路徑一般為HLM\Drivers\BuiltIn\Serial,即串口的驅(qū)動(dòng)程序信息在注冊(cè)表中所處的位置。COM_Init接著在HLM\Drivers\BuiltIn\Serial下查詢DeviceArrayIndex、Priority256的值,Priority256指定了驅(qū)動(dòng)程序的優(yōu)先級(jí),如果沒(méi)有就用默認(rèn)的優(yōu)先級(jí)。接下來(lái)調(diào)用GetSerialObject(DeviceArrayIndex),這個(gè)函數(shù)由PDD層定義,返回HWOBJ結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體主要包含PDD層和SER16550定義的函數(shù)的指針。也就是說(shuō)MDD通過(guò)調(diào)用這個(gè)函數(shù)才能調(diào)用底層實(shí)現(xiàn)的函數(shù)。接下來(lái)的大多數(shù)工作都是調(diào)用底層函數(shù)實(shí)現(xiàn)初始化。第一個(gè)調(diào)用的底層函數(shù)SerInit主要設(shè)置由用戶設(shè)置的硬件配置,例如線路控制、波特率。它調(diào)用Ser_GetRegistryData函數(shù)得到保存在注冊(cè)表中的硬件信息,Ser_GetRegistryData在內(nèi)部調(diào)用系統(tǒng)提供的DDKReg_GetIsrInfoDDK和DDKReg_GetWindowInfo函數(shù)得到在HLM\Drivers\BuiltIn\Serial下保存的IRQ、SysIntr、IsrDll、IsrHandler、IoBase、IoLen。IRQ是邏輯中斷號(hào),IsrDll表示當(dāng)前驅(qū)動(dòng)程序的可安裝ISR所在的DLL名稱,IsrHandler 表示可安裝ISR的函數(shù)名稱。在這里順便提一下可安裝ISR,讀者在我以前發(fā)表的關(guān)于OAL的文章中可以了解到OEM在OEMInit函數(shù)中關(guān)聯(lián)IRQ和SysIntr,當(dāng)硬件設(shè)備發(fā)生中斷時(shí),ISR會(huì)禁止同級(jí)和低級(jí)中斷,然后根據(jù)IRQ返回關(guān)聯(lián)的SysIntr,內(nèi)核根據(jù)ISR返回的SysIntr喚醒相應(yīng)的IST(SysIntr與IST創(chuàng)建的Event關(guān)聯(lián)),IST處理中斷之后調(diào)用InterruptDone解除中斷禁止。在OEMInit中關(guān)聯(lián)的缺點(diǎn)是一旦編譯了CE內(nèi)核后就無(wú)法添加這種關(guān)聯(lián)了,而一些硬件設(shè)備會(huì)隨時(shí)插拔或者共享中斷,要關(guān)聯(lián)這樣的硬件設(shè)備解決方法就是可安裝ISR,可安裝ISR專用于處理指定的硬件設(shè)備發(fā)出的中斷,所以如果硬件設(shè)備需要可安裝ISR必須在注冊(cè)表中添加IsrDll、IsrHandler。多數(shù)硬件設(shè)備采用CE默認(rèn)的可安裝ISR giisr.dll,格式如下:

 "IsrDll"="giisr.dll"

"IsrHandler"="ISRHandler"

  如果一個(gè)硬件驅(qū)動(dòng)程序需要可安裝ISR而開(kāi)發(fā)者又不想自己寫一個(gè),那么可以利用giisr.dll來(lái)實(shí)現(xiàn)。除了在注冊(cè)表中添加如上所示外,還要在驅(qū)動(dòng)程序中調(diào)用相關(guān)函數(shù)注冊(cè)可安裝ISR。偽代碼如下:

g_IsrHandle = LoadIntChainHandler(IsrDll, IsrHandler, (BYTE)Irq);

GIISR_INFO Info;

PHYSICAL_ADDRESS PortAddress = {PhysAddr, 0};

TransBusAddrToStatic(BusType, dwBusNumber, PortAddress, dwAddrLen, &dwIOSpace, &(PVOID)PhysAddr)

Info.SysIntr = dwSysIntr;

Info.CheckPort = TRUE;

Info.PortIsIO = (dwIOSpace) ? TRUE : FALSE;

Info.UseMaskReg = TRUE;

Info.PortAddr = PhysAddr   0x0C;

Info.PortSize = sizeof(DWORD);

Info.MaskAddr = PhysAddr   0x10;

KernelLibIoControl(g_IsrHandle, IOCTL_GIISR_INFO, &Info, sizeof(Info), NULL, 0, NULL);

  LoadIntChainHandler函數(shù)負(fù)責(zé)注冊(cè)可安裝ISR,參數(shù)1為DLL名稱,參數(shù)2為ISR函數(shù)名稱,參數(shù)3為IRQ。TransBusAddrToStatic函數(shù)在后面講。如果要利用giisr.dll作為可安裝ISR,必須先填充GIISR_INFO結(jié)構(gòu)體,CheckPort=TRUE表示giisr要檢測(cè)指定的寄存器來(lái)確定當(dāng)前發(fā)出中斷的是否是這個(gè)設(shè)備。PortIsIO表示寄存器地址屬于哪個(gè)地址空間,F(xiàn)ALSE表示是內(nèi)定空間,TRUE表示IO空間。UseMaskReg=TRUE表示設(shè)備有一個(gè)掩碼寄存器,專用于指定當(dāng)前設(shè)備是否是中斷源,也就是發(fā)出中斷,而MaskAddr表示掩碼寄存器的地址。如果對(duì)Info.Mask賦值,那么PortAddr表示一個(gè)特殊的寄存器地址,這個(gè)寄存器的值與Mask的值&運(yùn)算的結(jié)果如果為真,則證明當(dāng)前設(shè)備是中斷源,否則返回SYSINTR_CHAIN(表示當(dāng)前ISR沒(méi)有處理中斷,內(nèi)核將調(diào)用ISR鏈中下一個(gè)ISR),如果UseMaskReg=TRUE,那么MaskReg寄存器的值與PortAddr指定的寄存器的值&運(yùn)算的結(jié)果如果為真,則證明當(dāng)前設(shè)備是中斷源。
  函數(shù)SerInit接著調(diào)用函數(shù)Ser_InternalMapRegisterAddresses轉(zhuǎn)換IO地址并且映射地址,Ser_InternalMapRegisterAddresses在內(nèi)部調(diào)用系統(tǒng)提供的HalTranslateBusAddress(Isa, 0, ioPhysicalBase, &inIoSpace, &ioPhysicalBase)函數(shù)將與總線相關(guān)的地址轉(zhuǎn)換為系統(tǒng)地址,參數(shù)1為總線類型,參數(shù)2為總線號(hào),參數(shù)3為要轉(zhuǎn)換的地址(PHYSICAL_ADDRESS類型,實(shí)際是LARGE_INTEGER型),參數(shù)4指定寄存器地址屬于IO地址空間還是物理地址空間,參數(shù)5返回轉(zhuǎn)換后的物理地址。觀察HalTranslateBusAddress的源碼得知如果是在x86平臺(tái),這個(gè)函數(shù)除了把參數(shù)3賦給了參數(shù)5其余什么都沒(méi)有做,而非x86平臺(tái)將inIoSpace的值置為0,表示一定是物理地址。在調(diào)用HalTranslateBusAddress前要確定從注冊(cè)表中得到的寄存器地址到底是屬于哪個(gè)地址空間的

]]>
詳解WinCE下USB Host驅(qū)動(dòng)開(kāi)發(fā)http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1822&Page=1wangxinxin2010-11-26 11:00:37詳解WinCE下USB Host驅(qū)動(dòng)開(kāi)發(fā)(2)
當(dāng)用戶需要卸載USB Host設(shè)備驅(qū)動(dòng)時(shí),將會(huì)調(diào)用USBUnInstallDriver函數(shù)BOOL USBUnInstallDriver()
它與USBInstallDriver類似,不過(guò)是調(diào)用如下兩個(gè)函數(shù)UnRegisterClientSettings BOOL UnRegisterClientSettings(LPCWSTR szUniqueDriverId, LPCWSTR szReserved, LPCUSB_DRIVER_SETTINGS lpDriverSettings)
BOOL UnRegisterClientDriverID(LPCWSTR szUniqueDriverId)
其中szUniqueDriverId是注冊(cè)時(shí),使用的ID,szReserved保留,故設(shè)置為NULL,lpDriverSettings則是驅(qū)動(dòng)程序設(shè)置信息。例程如下:BOOL USBUnInstallDriver(){RETAILMSG(1,(TEXT("USBUninstallDriver\r\n")))BOOL fRet = FALSEUSB_DRIVER_SETTINGS DriverSettingsDriverSettings.dwCount = sizeof(DriverSettings)DriverSettings.dwVendorId = 0x10C4DriverSettings.dwProductId = 0x0003DriverSettings.dwReleaseNumber = USB_NO_INFODriverSettings.dwDeviceClass = USB_NO_INFODriverSettings.dwDeviceSubClass = USB_NO_INFODriverSettings.dwDeviceProtocol = USB_NO_INFODriverSettings.dwInterfaceClass = 0DriverSettings.dwInterfaceSubClass = 0DriverSettings.dwInterfaceProtocol = 0fRet = UnRegisterClientSettings(L"USBTest", NULL, DriverSettings)if(fRet) {fRet = UnRegisterClientDriverID(L"USBTest")if(!fRet)RETAILMSG(1,(TEXT("UnRegisterClientDriverID error\r\n")))} elseRETAILMSG(1,(TEXT("UnRegisterClientSettings error\r\n")))return fRet} 其中DriverSettings必須與USBInstallDriver的DriverSettings一致。
回到原來(lái)的流程,WinCE注冊(cè)表中已經(jīng)包含了驅(qū)動(dòng)信息,WinCE系統(tǒng)自動(dòng)查找注冊(cè)表,在找到設(shè)備對(duì)應(yīng)鍵值的DLL后,將會(huì)調(diào)用該DLL的USBDeviceAttach函數(shù)。BOOL USBDeviceAttach(USB_HANDLE hDevice,LPCUSB_FUNCS lpUsbFuncs,LPCUSB_INTERFACE lpInterface,LPCWSTR szUniqueDriverId,LPBOOL fAcceptControl,DWORD dwUnused)
hDevice 設(shè)備句柄,操作USB設(shè)備時(shí),需要使用該句柄 lpUsbFuncs 指向一個(gè)包含各種USB操作的函數(shù)指針 lpInterface USB接口信息,這里需要注意的是,如果在DriverSettings里dwInterfaceClass、dwInterfaceSubClass、dwInterfaceProtocol設(shè)置為USB_NO_INFO,則該指針為NULL
szUniqueDriverId 注冊(cè)設(shè)備ID fAcceptControl 該值被賦值為TRUE,表示該驅(qū)動(dòng)能操作該設(shè)備。如果不能操作該設(shè)備,則“未能識(shí)別的USB設(shè)備”對(duì)話框會(huì)再次出現(xiàn),要求用戶輸入驅(qū)動(dòng)程序名稱 dwUnused 未使用
在該函數(shù)內(nèi),主要是做一些檢查,判斷是否能驅(qū)動(dòng)設(shè)備,還有就是注冊(cè)USB事件通知回調(diào)函數(shù),以及激活流驅(qū)動(dòng)。對(duì)于檢查部分,這里不再詳細(xì)說(shuō)明。 首先,介紹一下激活流驅(qū)動(dòng)。 流驅(qū)動(dòng)為應(yīng)用程序提供了一個(gè)訪問(wèn)設(shè)備的接口,利用該接口可以像訪問(wèn)文件一樣訪問(wèn)設(shè)備。USB設(shè)備同樣可以使用該接口來(lái)為應(yīng)用程序提供支持。在注冊(cè)表的
HKEY_LOCAL_MACHINE\Drivers\BuiltIn鍵下,保存了各種WinCE內(nèi)建流驅(qū)動(dòng)程序的入口。這些驅(qū)動(dòng)通過(guò)device.exe在系統(tǒng)啟動(dòng)時(shí)被激活。像USB這樣的設(shè)備,只有插入時(shí),才存在流
驅(qū)動(dòng)接口,所以我們需要手動(dòng)激活流驅(qū)動(dòng)。激活流驅(qū)動(dòng)的函數(shù)是: HANDLE ActivateDevice(LPCWSTR lpszDevKey, DWORD dwClientInfo)lpszDevKey 字符串指明了流驅(qū)動(dòng)所在注冊(cè)表的鍵。獲悉流驅(qū)動(dòng)的人都知道,流驅(qū)動(dòng)在注冊(cè)表中必須包含兩個(gè)鍵Prefix和Dll。 流驅(qū)動(dòng)中所有接口函數(shù)都有類似XXX_的前綴,而這個(gè)Prefix則指明XXX對(duì)應(yīng)的字符串,如Prefix為COM,則流驅(qū)動(dòng)包含如COM_Open、COM_Close、COM_Write、COM_Read這樣接口函數(shù)。Dll則說(shuō)明了這些函數(shù)所在的動(dòng)態(tài)鏈接庫(kù)。在我的例子中存在如下的注冊(cè)表鍵:[HKEY_LOCAL_MACHINE\Drivers\USB\ClientDrivers\USBTest] "Prefix"="TST" "Dll"="MyUSBTest.dll" 通過(guò)dwClientInfo,可以把參數(shù)間接傳給驅(qū)動(dòng)的XXX_init。我們可以把hDevice、lpUsbFuncs、lpInterface這樣信息放置在一個(gè)結(jié)構(gòu)體中,通過(guò)該函數(shù)傳遞給流驅(qū)動(dòng)使用。
USB通知回調(diào)函數(shù),可以用來(lái)判斷各種USB事件的發(fā)生,如USB拔出。當(dāng)發(fā)生事件后,系統(tǒng)會(huì)根據(jù)注冊(cè)的回調(diào)函數(shù)做相應(yīng)的處理,在USB設(shè)備拔出后,所要做的事情,就是卸載流驅(qū)動(dòng),并釋放占用的各種資源。 注冊(cè)回調(diào)函數(shù)是一個(gè)包含在lpUsbFuncs中的函數(shù)指針:LPUN_REGISTER_NOTIFICATION_ROUTINE lpUnRegisterNotificationRoutine該函數(shù)的聲明如下:typedef BOOL (* LPREGISTER_NOTIFICATION_ROUTINE)( USB_HANDLE hDevice, LPDEVICE_NOTIFY_ROUTINE lpNotifyRoutine, LPVOID lpvNotifyParameter)hDevice 設(shè)備句柄lpNotifyRoutine 回調(diào)函數(shù)lpvNotifyParameter 傳遞給回調(diào)函數(shù)的參數(shù)
在回調(diào)函數(shù)中卸載流驅(qū)動(dòng)使用BOOL DeactivateDevice(HANDLE hDevice)其中,hDevice 傳入ActivateDevice時(shí)返回的句柄。
下面是具體的示例:
typedef struct {DWORD dwSizeUSB_HANDLE hDevice,LPCUSB_FUNCS lpUsbFuncs,LPCUSB_INTERFACE lpInterface,HANDLE hStreamDevice} TESTUSBINFO, PTESTUSBINFO
//回調(diào)函數(shù)extern "C" BOOL USBDeviceNotifications(LPVOID lpvNotifyParameter,DWORD dwCode,LPDWORD *dwInfo1,LPDWORD *dwInfo2,LPDWORD *dwInfo3,LPDWORD *dwInfo4){if (dwCode == USB_CLOSE_DEVICE) {PTESTUSBINFO pDrv = (PDRVCONTEXT) lpvNotifyParameterDeactivateDevice(pDrv-hStreamDevice) //卸載流驅(qū)動(dòng)LocalFree(pDrv) //釋放資源}RETAILMSG(1,(TEXT("Free Driver Resources!\r\n")))return TRUE}
BOOL USBDeviceAttach(USB_HANDLE hDevice,LPCUSB_FUNCS lpUsbFuncs,LPCUSB_INTERFACE lpInterface,LPCWSTR szUniqueDriverId,LPBOOL fAcceptControl,DWORD dwUnused){RETAILMSG(1,(TEXT("USBDeviceAttach\r\n")))*fAcceptControl = FALSE
//顯示USB設(shè)備的一些信息if(lpInterface != NULL) {RETAILMSG(1,(TEXT("usbserialhost: DeviceAttach, IF %u, #EP:%u, Class:%u, Sub:%u, Prot:%u\r\n"),lpInterface-Descriptor.bInterfaceNumber,lpInterface-Descriptor.bNumEndpoints,lpInterface-Descriptor.bInterfaceClass,lpInterface-Descriptor.bInterfaceSubClass,lpInterface-Descriptor.bInterfaceProtocol))RETAILMSG(1,(TEXT("Endpoint 1:%u\r\n"), lpInterface-lpEndpoints.Descriptor.bmAttributes))RETAILMSG(1,(TEXT("Endpoint 2:%u\r\n"), lpInterface-lpEndpoints.Descriptor.bmAttributes))RETAILMSG(1,(TEXT("Endpoint 3:%u\r\n"), lpInterface-lpEndpoints.Descriptor.bmAttributes))}
LPCUSB_DEVICE lpUsbDev = (lpUsbFuncs-lpGetDeviceInfo)(hDevice)if(!lpUsbDev){RETAILMSG(1,(TEXT("Unable to get USB device!\r\n")))return FALSE}
//保存必要的信息供驅(qū)動(dòng)程序其他部分使用PTESTUSBINFO pDrv = (PTESTUSBINFO)LocalAlloc (LPTR, sizeof (PTESTUSBINFO))pDrv-dwSize = sizeof (DRVCONTEXT)pDrv-hDevice = hDevicepDrv-lpUsbFuncs = lpUsbFuncspDrv-lpInterface = lpInterface
//激活流驅(qū)動(dòng)pDrv-hStreamDevice = ActivateDevice (L"Drivers\\USB\\ClientDrivers\\USBTest", (DWORD)pDrv)if (pDrv-hStreamDevice) {//注冊(cè)回調(diào)函數(shù)(*lpUsbFuncs-lpRegisterNotificationRoutine)(hDevice,USBDeviceNotifications,pDrv)} else {RETAILMSG(1, (TEXT("Can't activate stream device! rc=%d\r\n"), GetLastError()))LocalFree(pDrv)return FALSE}//驅(qū)動(dòng)可以操作該設(shè)備*fAcceptControl = TRUEreturn TRUE}
至此,USB Host端設(shè)備驅(qū)動(dòng)程序所必須實(shí)現(xiàn)的功能都已經(jīng)實(shí)現(xiàn)。并且和流驅(qū)動(dòng)相連接。應(yīng)用程序已經(jīng)可以使用流驅(qū)動(dòng)的接口來(lái)操作USB設(shè)備了。
]]>
WinCE中觸摸屏驅(qū)動(dòng)開(kāi)發(fā)詳解http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1821&Page=1wangxinxin2010-11-26 10:59:311.觸摸屏驅(qū)動(dòng)程序的模型

1.1 分層觸摸屏驅(qū)動(dòng)層序結(jié)構(gòu)

本觸摸屏驅(qū)動(dòng)采用分層驅(qū)動(dòng)程序結(jié)構(gòu),其驅(qū)動(dòng)模型如下圖所示,這種結(jié)構(gòu)將驅(qū)動(dòng)程序代碼區(qū)分為上層模型設(shè)備驅(qū)動(dòng)層(MDD),下層是依賴平臺(tái)的驅(qū)動(dòng)層(PDD)。其中MDD層通常無(wú)需修改就可以直接使用,改部分提供面向GWES的DDI的接口,而MDD通過(guò)指定的DDSI函數(shù)接口調(diào)用PDD,這就是我們通常驅(qū)動(dòng)要實(shí)現(xiàn)的部分。PDD部分和MDD部分除了DDSI函數(shù)集接口外,還要實(shí)現(xiàn)一些指定的變量的定義或變量初始化動(dòng)作(比如,gIntrTouch和gIntrTouchChanged在PDD層定義,但主要在MDD層使用。),也就是說(shuō)MDD層和PDD層之間并不一定是以嚴(yán)格的分層模型來(lái)實(shí)現(xiàn)的,有時(shí)候也要通過(guò)共享變量的方式來(lái)完成交互。

1.2 DDI函數(shù)集(MDD層)

TouchPanelPowerHandler(BOOL boff)

Touch Screen的電源管理函數(shù),boff:TRUE表示關(guān)閉電源,F(xiàn)ALSE表示打開(kāi)電源,其只是調(diào)用DdsiTouchPanelPowerHandler()函數(shù),該函數(shù)在進(jìn)入或退出poweroff狀態(tài)時(shí)產(chǎn)生。

TouchPanelCalibrationAPoint()

該函數(shù)用于校準(zhǔn)輸入的觸摸屏坐標(biāo),把觸摸屏坐標(biāo)轉(zhuǎn)換為顯示坐標(biāo),利用了公式Sx=A1*Tx+B1*Ty+C和Sy=A2*Tx+B2*Ty+C2。

TouchPanelReadCalibrationPoint()

在執(zhí)行觸摸屏校準(zhǔn)程序時(shí),用這個(gè)函數(shù)獲得在當(dāng)前校準(zhǔn)點(diǎn)的十字形上點(diǎn)擊的觸摸屏坐標(biāo)。

TouchPanelReadCalibrationAbord()

該函數(shù)在校準(zhǔn)取消時(shí)被調(diào)用(在觸摸屏校準(zhǔn)程序運(yùn)行過(guò)程中取消校準(zhǔn)),僅僅設(shè)置狀態(tài)位和事件后返回。

TouchPanelDisable()

禁用觸摸屏(touch panel)設(shè)備,該函數(shù)關(guān)閉ISR,停止中斷和注銷事件及其他同步手段,此函數(shù)調(diào)用了DdsiTouchPanelDisable()函數(shù)。

TouchPanelEnable(PFN_TOUCH_PANEL_CALLBACK    pfnCallback)

PfnCallback是指向處理touch panel事件的回調(diào)函數(shù),該函數(shù)的執(zhí)行動(dòng)作:

⑴創(chuàng)建事件hTouchPanelEvent和hCalibrationSampleAvailable,其中當(dāng)觸筆按下或抬起,或者定時(shí)器中斷時(shí)會(huì)觸發(fā)hTouchPanelEvent事件,而在校準(zhǔn)狀態(tài)下當(dāng)有校準(zhǔn)數(shù)據(jù)輸入時(shí)會(huì)觸發(fā)hCalibrationSampleAvailable事件。

⑵初始化臨界區(qū),初始化所需的觸摸屏中斷gIntrTouch和gIntrTouchChanged,并且把它們關(guān)聯(lián)到事件hTouchPanelEvent中。

⑶創(chuàng)建IST TouchPanelpISR,并設(shè)定其優(yōu)先級(jí)。

TouchPanelSetCalibration()

該函數(shù)通過(guò)運(yùn)行觸摸屏校準(zhǔn)程序時(shí)的校準(zhǔn)動(dòng)作獲得顯示坐標(biāo)(Sx,Sy)和觸筆在十字形上按下的觸摸坐標(biāo)(Tx,Ty)用于計(jì)算校準(zhǔn)參數(shù)A1,B1,C1和A2,B2,C2。

TouchPanelGetDeviceCaps()

用于查詢觸摸屏設(shè)備支持的具體功能,通過(guò)DDSI函數(shù)查詢相應(yīng)的信息,當(dāng)查詢屏幕坐標(biāo)信息時(shí)保存屏幕信息,供后面程序計(jì)算校準(zhǔn)參數(shù)所用。

TouchPanelSetMode()

用于設(shè)置觸摸屏的工作模式(采用低采樣率還是高采樣率),當(dāng)設(shè)置IST優(yōu)先級(jí)時(shí)直接通過(guò)內(nèi)核API來(lái)完成,而直接將其他設(shè)置交給DdsiTouchPanelSetMode()函數(shù)來(lái)處理。

1.3WinCE  DDSI函數(shù)集(PDD層)

DdsiTouchPanelGetDeviceCaps(INT iIndex, LPVOID lpOutput)

查詢touch panel設(shè)備的相關(guān)信息。

IIndex:查詢的索引值,其取值如下:

TPDC_SAMPLE_RATE_ID:查詢采樣率信息。

TPDC_CALIBRATION_POINT_COUNT_ID:查詢用于校驗(yàn)的點(diǎn)的個(gè)數(shù)。

TPDC_CALIBRATION_POINT_ID:查詢需要校驗(yàn)的點(diǎn)的坐標(biāo)。

LpOutput:根據(jù)iIndex值分別指向相關(guān)的信息。

DdsiTouchPanelSetMode()

設(shè)置Touch Panel工作模式。

iIndex:模式索引

TPSM_SAMPLERATE_HIGH_ID:高采樣率

TPSM_SAMPLERATE_LOW_ID:低采樣率

lpInput:指向包含相關(guān)信息的內(nèi)存

DdsiTouchPanelEnable()

該函數(shù)所執(zhí)行的動(dòng)作:

⑴為需要用到的I/O,ADC,PWM和INT寄存器分配內(nèi)存空間。

⑵配置觸摸屏控制器、中斷控制器和PWM的寄存器。

⑶申請(qǐng)觸摸屏中斷gIntrTouch和定時(shí)器中斷gIntrTouchChanged,并且對(duì)它們進(jìn)行初始化,為物理中斷號(hào)分配相應(yīng)的系統(tǒng)邏輯中斷號(hào)。。

DdsiTouchPanelDisable()

屏蔽觸摸屏中斷和釋放為I/O,ADC,PWM和INT寄存器分配的WinCE內(nèi)存空間。

DdsiTouchPanelAttach()

只是簡(jiǎn)單地返回1。

DdsiTouchPanelDetach()

只是簡(jiǎn)單地返回0。

DdsiTouchPanelGetPoint (TOUCH_PANEL_SAMPLE_FLAGS * pTipStateFlags,

                       INT * pUncalX,

                       INT * pUncalY )

獲得Touch Panel上被按下的點(diǎn)的狀態(tài)和坐標(biāo)。

◆pTipState:當(dāng)前觸摸點(diǎn)的狀態(tài),比如無(wú)效點(diǎn),有效點(diǎn),被按下的點(diǎn)等。

◆pUnCalX:觸摸點(diǎn)的X坐標(biāo)

◆pUnCalY:觸摸點(diǎn)的Y坐標(biāo)

◆DdsiTouchPanelPowerHandler()

設(shè)置touch panel的電源狀態(tài),boff:TRUE表示關(guān)閉電源,F(xiàn)ALSE表示打開(kāi)電源,

2.觸摸屏驅(qū)動(dòng)程序的實(shí)現(xiàn)

Windows CE5.0觸摸屏驅(qū)動(dòng)程序采用中斷方式對(duì)觸摸筆的按下?tīng)顟B(tài)進(jìn)行檢測(cè),如果檢測(cè)到觸摸筆按下將產(chǎn)生中斷并觸發(fā)一個(gè)事件通知一個(gè)工作線程開(kāi)始采集數(shù)據(jù)。同時(shí),驅(qū)動(dòng)將打開(kāi)一個(gè)硬件定時(shí)器,只要檢測(cè)到觸摸筆仍然在按下?tīng)顟B(tài)將定時(shí)觸發(fā)同一個(gè)事件通知工作線程采集數(shù)據(jù),直到觸摸筆抬起后關(guān)閉該定時(shí)器,并重新檢測(cè)按下?tīng)顟B(tài)。驅(qū)動(dòng)中采用了觸摸屏中斷以及定時(shí)器中斷2個(gè)中斷源,不僅可以監(jiān)控觸摸筆按下和抬起狀態(tài),而且可以檢測(cè)觸摸筆按下時(shí)的拖動(dòng)軌跡。觸摸屏驅(qū)動(dòng)流程下圖所示

3.四線電阻式觸摸屏的工作原理

四線電阻式觸摸屏的結(jié)構(gòu)如圖1,在玻璃或丙烯酸基板上覆蓋有兩層透平,均勻?qū)щ姷腎TO層,分別做為X電極和Y電極,它們之間由均勻排列的透明格 點(diǎn)分開(kāi)絕緣。其中下層的ITO與玻璃基板附著,上層的ITO附著在PET薄膜上。X電極和Y電極的正負(fù)端由“導(dǎo)電條”(圖中黑色條形部分)分別從兩端引 出,且X電極和Y電極導(dǎo)電條的位置相互垂直。引出端X-,X+,Y-,Y+一共四條線,這就是四線電阻式觸摸屏名稱的由來(lái)。當(dāng)有物體接觸觸摸屏表面并施以 一定的壓力時(shí),上層的ITO導(dǎo)電層發(fā)生形變與下層ITO發(fā)生接觸,該結(jié)構(gòu)可以等效為相應(yīng)的電路,

計(jì)算觸點(diǎn)的X,Y坐標(biāo)分為如下兩步:

1. 計(jì)算Y坐標(biāo),在Y+電極施加驅(qū)動(dòng)電壓Vdrive, Y-電極接地,X+做為引出端測(cè)量得到接觸點(diǎn)的電壓,由于ITO層均勻?qū)щ姡|點(diǎn)電壓與Vdrive電壓之比等于觸點(diǎn)Y坐標(biāo)與屏高度之比。

2. 計(jì)算X坐標(biāo),在X+電極施加驅(qū)動(dòng)電壓Vdrive, X-電極接地,Y+做為引出端測(cè)量得到接觸點(diǎn)的電壓,由于ITO層均勻?qū)щ姡|點(diǎn)電壓與Vdrive電壓之比等于觸點(diǎn)X坐標(biāo)與屏寬度之比。

測(cè)得的電壓由ADC轉(zhuǎn)化為觸摸點(diǎn)的原始坐標(biāo)(數(shù)值范圍由所選用的A/D轉(zhuǎn)換器位數(shù)決定)后,還要根據(jù)具體使用的液晶屏實(shí)際像素進(jìn)行轉(zhuǎn)換,轉(zhuǎn)換后通過(guò)校準(zhǔn)直接轉(zhuǎn)化為屏幕上的坐標(biāo),供GWES使用。

4.觸摸屏的接口部分

◆X+:連接觸摸屏控制器的TSXP,。

◆X-:連接觸摸屏控制器的TSXM。

◆Y+:連接觸摸屏控制器的TSYP。

◆Y-:連接觸摸屏控制器的TSYM。

在觸摸屏接口使用時(shí),TSXM或TSYM應(yīng)該接觸摸屏接口的。

5.配置控制器硬件

5.1 ADCCON-----ADC控制寄存器

ECFLG:ADCCON[15],AD轉(zhuǎn)換結(jié)束標(biāo)志,只讀,0表示AD轉(zhuǎn)換在過(guò)程中;1表示AD轉(zhuǎn)換結(jié)束。

PRSCEN:ADCCON[14],AD轉(zhuǎn)換器預(yù)分頻器使能,在此使能,故為1。

PRSCVL:ADCCON[13:6],AD轉(zhuǎn)換器預(yù)分頻器值,在此為49。

SEL_MUX:ADCCON[5:3],模擬信號(hào)輸入通道選擇,在此選擇XP,故為7。

STDBM:ADCCON[2],備用操作模式選擇,在此選擇普通操作模式,故為0。

READ_START:ADCCON[1],通過(guò)讀取來(lái)啟動(dòng)A/D轉(zhuǎn)換,在此選擇通過(guò)讀取操作無(wú)效來(lái)啟動(dòng)A/D轉(zhuǎn)換,故為0。

ENABLE_START,ADCCON[0],通過(guò)使能該位來(lái)啟動(dòng)A/D轉(zhuǎn)換,在此選擇無(wú)操作。此位在A/D轉(zhuǎn)換開(kāi)始后被使能。

5.2 ADCTSC-----ADC觸摸屏控制寄存器

UD_SEN:ADCTSC[8],在此選擇檢測(cè)到觸筆按下就產(chǎn)生中斷信號(hào),故為0。

YM_SEN:ADCTSC[7],YM開(kāi)關(guān)使能,在此選擇YM輸出驅(qū)動(dòng)有效(GND),故為1。

YP_SEN:ADCTSC[6],YP開(kāi)關(guān)使能,在此選擇YP輸出驅(qū)動(dòng)無(wú)效(AIN5),故為1。

XM_SEN:ADCTSC[5],XM開(kāi)關(guān)使能,在此選擇XM輸出驅(qū)動(dòng)無(wú)效(Hi-Z),故為0。

XP_SEN:ADCTSC[4],XP開(kāi)關(guān)使能,在此選擇XP輸出驅(qū)動(dòng)無(wú)效(AIN7),故為1。

PULL_UP:ADCTSC[3],上拉開(kāi)關(guān)使能,在此選擇XP上拉有效,故為0。

AUTO_PST:ADCTSC[2],初始化時(shí),在此選擇自動(dòng)連續(xù)測(cè)量X坐標(biāo)和Y坐標(biāo),故為0,但如果開(kāi)始轉(zhuǎn)換時(shí),應(yīng)該置1。

XY_PST:ADCTSC[1:0],手動(dòng)測(cè)量X坐標(biāo)和Y坐標(biāo),在此選擇等待中斷模式,故為3。

注:當(dāng)?shù)却|摸屏中斷時(shí),XP_SEN位(XP輸出無(wú)效)應(yīng)該置為1,且PULL_UP(XP上拉使能)位應(yīng)該置為0。

5.3 ADCDLY-----ADC開(kāi)始延時(shí)寄存器

DELAY:ADCDLY[154:0],因?yàn)檫x擇等待中斷模式,此值表示,當(dāng)觸筆按下出現(xiàn)在睡眠模式時(shí),產(chǎn)生一個(gè)用于推出睡眠模式的信號(hào),有幾個(gè)毫秒的時(shí)間間隔。在此此值為40000?????????(40s,太長(zhǎng)了吧?)

SUBINTMSK-----WinCE中子中斷屏蔽寄存器

該寄存器有11位,每位和一位中斷源相關(guān)。觸摸屏中斷請(qǐng)求有效,故第十位應(yīng)設(shè)為0。

v_pINTregs->INTSUBMSK &= ~(1<<IRQ_SUB_TC);

5.4 TCFG1-----5路多路器及DMA模式選擇寄存器

MUX3:TCFG1[15:12],為PWM計(jì)時(shí)器3選擇多路輸入,并初始化其值,每個(gè)定時(shí)器都有一個(gè)時(shí)鐘分頻器,其可以生成5鐘不同的分頻信號(hào)(1/2,1/4,1/8,1/16和TCLK),在此選擇1/16分頻。

v_pPWMregs->TCFG1 &= ~(0xf << 12); /* Timer3's Divider Value   */

v_pPWMregs->TCFG1 |= (3   << 12);     /* 1/16   

TCNTB3-----PWM定時(shí)器3計(jì)數(shù)緩存寄存器,選擇定時(shí)器3為時(shí)鐘,比如定義10ms中斷一次,提供觸摸屏采樣時(shí)間基準(zhǔn),即10ms觸摸屏采樣一次。在此為17×1000/100=170,在此PCLK=400MHz/6,可以得出timer3的時(shí)鐘頻率=PCLK/(244+1).16,可以算數(shù)觸摸屏就是10ms產(chǎn)生一次定時(shí)中斷,進(jìn)行一次采樣

]]>
OMAP3530 WINCE GPIO驅(qū)動(dòng)開(kāi)發(fā)過(guò)程http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1820&Page=1wangxinxin2010-11-26 10:58:35    言歸正傳,OMAP3530的GPIO(General-purpose Interface)按照分組的原則,共有6組,每組的控制類寄存器是32bit的,代表了32個(gè)GPIO,所以總共有192個(gè)GPIO,這些是屬于MPU控制的,超過(guò)192編號(hào)的GPIO是屬于IVA2.2(DSP)控制的。結(jié)構(gòu)框圖如下:
    WINCE GPIO驅(qū)動(dòng)開(kāi)發(fā)過(guò)程" height=274 alt="OMAP3530 WINCE GPIO驅(qū)動(dòng)開(kāi)發(fā)過(guò)程" src="http://static12.photo.sina.com.cn/middle/68e59675x8ab48e529b6b&690" width=653 real_src="http://static12.photo.sina.com.cn/middle/68e59675x8ab48e529b6b&690">
OMAP3530的GPIO具有以下功能:
1)數(shù)據(jù)輸入(捕獲)/輸出(驅(qū)動(dòng))
2) 帶有防抖功能的鍵盤接口
3)外部事件檢測(cè)(電平中斷、邊沿中斷)
4) 在空閑模式下通過(guò)外部事件的睡眠喚醒功能
相關(guān)的配置需要仔細(xì)參照技術(shù)手冊(cè)
    接下來(lái)是WINCE下的GPIO驅(qū)動(dòng),跳過(guò)流驅(qū)動(dòng)的標(biāo)準(zhǔn)框架以及MDD層框架和PDD層的與硬件相關(guān)的寄存器設(shè)置。這些和三星ARM的GPIO驅(qū)動(dòng)大同小異。
    著重介紹可能遇到的問(wèn)題,忽略的地方:
我在編寫完OMAP3530的GPIO驅(qū)動(dòng)后,發(fā)現(xiàn)有的GPIO能夠控制輸入輸出,有的則不能。經(jīng)過(guò)同學(xué)提醒,重新看了技術(shù)手冊(cè),原來(lái)在技術(shù)手冊(cè)的第7章System Control Module(SCM)中明確介紹了core modul(內(nèi)核模塊)和wake-up module(喚醒模塊)。
    SCM主要負(fù)責(zé)以下功能
1)I/O端口功能復(fù)用、多工選擇
2) Pad塊配置(端口上拉/下拉)
3) 設(shè)備狀態(tài)
4) MPU和DSP(IVA2.2)的外圍擴(kuò)展設(shè)備特性
5) 靜態(tài)設(shè)備配置
6)調(diào)試和觀測(cè)功能IO復(fù)用
7) 存儲(chǔ)pad塊的配置
pad塊配置寄存器如下:
WINCE GPIO驅(qū)動(dòng)開(kāi)發(fā)過(guò)程" height=273 alt="OMAP3530 WINCE GPIO驅(qū)動(dòng)開(kāi)發(fā)過(guò)程" src="http://static2.photo.sina.com.cn/middle/68e59675x8ab4e91d0761&690" width=690 real_src="http://static2.photo.sina.com.cn/middle/68e59675x8ab4e91d0761&690">

其中pad塊的配置中有一項(xiàng)就是端口的MODE(3bits),由于一個(gè)GPIO可能有多個(gè)功能,他們是互斥的,只能選擇一個(gè),就涉及到端口功能的選擇,總共有MODE0到MODE7八個(gè)模式,默認(rèn)是MODE0,MODE7是安全模式。比如GPIO143總共有實(shí)實(shí)在在的5個(gè)模式:mcbsp3_fsx/uart2_rx/gpio143/hsusb3_till_data7/safemode。所以在配置GPIO的時(shí)候需要選擇成GPIO模式,不然操作GPIO就沒(méi)有效果,這是問(wèn)題1.
   另外,上面的配置只能解決端口的輸出控制,當(dāng)端口配置成輸入時(shí),就不一定能讀取端口電平。問(wèn)題出在哪里呢,繼續(xù)仔細(xì)參照技術(shù)手冊(cè)的SCM模塊。pad塊中還有兩項(xiàng)是GPIO的上拉/下拉選項(xiàng)、輸入使能選項(xiàng)。針對(duì)當(dāng)GPIO端口配置為輸入時(shí)不能讀取正確的引腳電平的問(wèn)題,主要原因是由于GPIO端口的輸入使能被關(guān)閉了。
   輸入使能(INPUTENABLE)(1bits)的描述如下:
1)INPUTENABLE = 0,關(guān)閉引腳輸入,引腳只能夠作為輸出。
2) INPUTENABLE = 1,使能引腳輸入,引腳具有雙向端口功能,即輸入/輸出。
所以我們應(yīng)該使能SCM中,pad塊的這項(xiàng)功能。
   具體到相關(guān)的WINCE文件有
GPIO驅(qū)動(dòng):
   1) $\WINCE600\PLATFORM\TI_EVM_3530\SRC\DRIVERS\GPIO\gpio.cpp
   2)$\WINCE600\PLATFORM\COMMON\SRC\SOC\OMAP35XX_TPS659XX_TI_V1\omap35xx\GPIO\omap35xx_gpio.cpp
啟動(dòng)時(shí)安裝配置成GPIO的文件:
   1)$\WINCE600\PLATFORM\TI_EVM_3530\SRC\BOOT\XLDR\platform.c
比如:
   VOID GpioSetup()函數(shù)下的GPIO模式和端口方向定制:
 OUTREG16(&pConfig->CONTROL_PADCONF_SDRC_D0, (INPUT_ENABLE | PULL_INACTIVE | MUX_MODE_0));  
    OUTREG16(&pConfig->CONTROL_PADCONF_SDRC_D1, (INPUT_ENABLE | PULL_INACTIVE | MUX_MODE_0));  
    OUTREG16(&pConfig->CONTROL_PADCONF_SDRC_D2, (INPUT_ENABLE | PULL_INACTIVE | MUX_MODE_0));  
    OUTREG16(&pConfig->CONTROL_PADCONF_SDRC_D3, (INPUT_ENABLE | PULL_INACTIVE | MUX_MODE_0));  
    OUTREG16(&pConfig->CONTROL_PADCONF_SDRC_D4, (INPUT_ENABLE | PULL_INACTIVE | MUX_MODE_0));  
    OUTREG16(&pConfig->CONTROL_PADCONF_SDRC_D5, (INPUT_ENABLE | PULL_INACTIVE | MUX_MODE_0));  
    OUTREG16(&pConfig->CONTROL_PADCONF_SDRC_D6, (INPUT_ENABLE | PULL_INACTIVE | MUX_MODE_0));  
    OUTREG16(&pConfig->CONTROL_PADCONF_SDRC_D7, (INPUT_ENABLE | PULL_INACTIVE | MUX_MODE_0));  
    OUTREG16(&pConfig->CONTROL_PADCONF_SDRC_D8, (INPUT_ENABLE | PULL_INACTIVE | MUX_MODE_0));  
 
   綜上所述:SCM模塊決定了端口的功能,而GPIO模塊控制了端口的GPIO功能;GPIO只是端口功能的一個(gè)子集。
]]>
WINCE下的USB驅(qū)動(dòng)開(kāi)發(fā)http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1819&Page=1wangxinxin2010-11-26 10:53:36首先USB加載式流接口驅(qū)動(dòng)要點(diǎn)分析

為了支持不同類型的外圍設(shè)備,WinCE平臺(tái)提供了具有定制接口的流接口驅(qū)動(dòng)程序模型。因?yàn)榇蟛糠諹SB外圍設(shè)備由于功能性更適合流接口驅(qū)動(dòng)的結(jié)構(gòu),所以一般都采用加載式流接口驅(qū)動(dòng)程序模型來(lái)開(kāi)發(fā)USB設(shè)備驅(qū)動(dòng)程序。

(1)USB系統(tǒng)結(jié)構(gòu)分析
WinCE下USB系統(tǒng)軟件由兩層組成:較高USB設(shè)備驅(qū)動(dòng)程序?qū)雍洼^低的USB函數(shù)層。較低的USB函數(shù)層本身又由兩部分組成:較高的通用串行總線驅(qū)動(dòng)程序(USBD)模塊和較低的主控制器驅(qū)動(dòng)程序(HCD)模塊。通過(guò)HCD模塊功能和USBD模塊實(shí)現(xiàn)高層的USBD接口函數(shù),USB設(shè)備驅(qū)動(dòng)程序就能與外圍設(shè)備進(jìn)行通訊。

在數(shù)據(jù)傳輸?shù)倪^(guò)程中,操作流程通常按下列的次序進(jìn)行:①USB設(shè)備驅(qū)動(dòng)程序進(jìn)行數(shù)據(jù)傳輸?shù)某跏蓟赐ㄟ^(guò)USBD接口函數(shù)給USBD模塊發(fā)送數(shù)據(jù)傳輸?shù)恼?qǐng)求。②USBD模塊將該請(qǐng)求分成一些單獨(dú)的事務(wù)。③HCD模塊排出事務(wù)次序。④主控制器硬件執(zhí)行事務(wù)。這里需要提醒的是,所有的事務(wù)都是從主機(jī)發(fā)出的,外圍設(shè)備完全是被動(dòng)接受型的。

(2)USB設(shè)備驅(qū)動(dòng)程序入口點(diǎn)函數(shù)
從結(jié)構(gòu)分析我們可知,所有的USB設(shè)備驅(qū)動(dòng)程序必須在它們的DLL庫(kù)設(shè)置一定的入口點(diǎn)與USBD模塊進(jìn)行適當(dāng)?shù)慕换ァTO(shè)置入口點(diǎn)函數(shù)有兩個(gè)作用:一是使得 USBD 模塊能與外部設(shè)備交互;二是使得驅(qū)動(dòng)程序能創(chuàng)建和管理任何可能需要的注冊(cè)鍵。

下面簡(jiǎn)要介紹相關(guān)函數(shù)的作用:USBDeviceAttach是當(dāng) USB 設(shè)備連接到主計(jì)算機(jī)時(shí)運(yùn)行,USBD模塊會(huì)調(diào)用這個(gè)函數(shù)初始化USB設(shè)備,取得USB設(shè)備信息和配置USB設(shè)備,并且申請(qǐng)必需的資源。 USBInstallDrive是在第一次加載USB設(shè)備驅(qū)動(dòng)程序時(shí)首先被調(diào)用,它使得驅(qū)動(dòng)程序能創(chuàng)建需要的注冊(cè)鍵,用于將一個(gè)驅(qū)動(dòng)程序所需的注冊(cè)表信息寫入到HKEY_LOCAL_MACHINE\Drivers\USB\ClientDrivers目錄下,例如設(shè)備名稱等。需要注意的是,USB設(shè)備驅(qū)動(dòng)程序不使用標(biāo)準(zhǔn)的注冊(cè)表函數(shù),而是使用RegisterClientDriverID()、RegisterClientSettings()函數(shù)來(lái)注冊(cè)相應(yīng)的設(shè)備信息。

USBUninstallDriver是在用戶刪除USB設(shè)備驅(qū)動(dòng)程序時(shí)調(diào)用,負(fù)責(zé)刪除注冊(cè)鍵并釋放其它相關(guān)資源。它通過(guò)調(diào)用 UnRegisterClientSettings()和UnRegisterClientDriverID()函數(shù)來(lái)刪除由驅(qū)動(dòng)程序的 USBInstallDriver()函數(shù)創(chuàng)建的所有注冊(cè)鍵。因此,我們?cè)隍?qū)動(dòng)程序中就需要嚴(yán)格按照這三個(gè)函數(shù)的原型來(lái)實(shí)現(xiàn),否則就不能為設(shè)備管理器所識(shí)別。

3.USB設(shè)備流接口驅(qū)動(dòng)的實(shí)現(xiàn)步驟

從WinCE USB設(shè)備驅(qū)動(dòng)模型及結(jié)構(gòu)分析中,我們可以清晰的看到主機(jī)和外設(shè)之間的實(shí)現(xiàn)方式。在主機(jī)端,通過(guò)USBD模塊和HCD模塊使用默認(rèn)的PIPE訪問(wèn)一個(gè)通用的邏輯設(shè)備,實(shí)際上就是說(shuō)USBD和HCD是一組訪問(wèn)所有USB設(shè)備的邏輯接口,它們負(fù)責(zé)管理所有USB設(shè)備的連接、加載、移除、數(shù)據(jù)傳輸和通用配置。其中HCD是主機(jī)控制驅(qū)動(dòng),是為USBD提供底層的功能訪問(wèn)服務(wù),USBD是USB總線驅(qū)動(dòng),位于HCD的上層,利用HCD的服務(wù)提供較高層次的功能。因此,實(shí)現(xiàn)USB加載流驅(qū)動(dòng)程序大致需要完成以下步驟:

(1)選擇代表設(shè)備的文件名前綴。前綴非常重要,設(shè)備管理器在注冊(cè)表中通過(guò)前綴來(lái)識(shí)別設(shè)備。同時(shí),在流接口命名時(shí)也將這個(gè)前綴作為入口點(diǎn)函數(shù)的前綴,如果設(shè)備前綴為XXX,那么流接口對(duì)應(yīng)為XXX_Close,XXX_Init等。

(2)設(shè)置驅(qū)動(dòng)的各個(gè)入口點(diǎn)函數(shù)。所謂入口點(diǎn)是指提供給設(shè)備管理器的標(biāo)準(zhǔn)文件I/O接口。在生成一個(gè)DLL后,就用設(shè)備文件名前綴替換名字中的XXX。因此,每個(gè)加載式流接口驅(qū)動(dòng)程序必須實(shí)現(xiàn)XXX_Init()、XXX_IOControl()以及XXX_PowerUp()等一組標(biāo)準(zhǔn)的函數(shù),用來(lái)完成標(biāo)準(zhǔn)的文件I/O函數(shù)和電源管理等。

(3)建立.DEF文件。當(dāng)設(shè)備管理器初始化USB設(shè)備編譯出來(lái)的流接口函數(shù)后,還必須建立一個(gè).def文件。DEF文件定義了DLL要導(dǎo)出的接口集,而且加載式流驅(qū)動(dòng)大多是以DLL形式存在的,所以應(yīng)將DLL和DEF的文件名統(tǒng)一起來(lái)。DEF文件告訴鏈接程序需要輸出什么樣的函數(shù),最后將驅(qū)動(dòng)程序編譯到內(nèi)核中去,這樣這個(gè)USB設(shè)備流接口驅(qū)動(dòng)程序就可以被應(yīng)用程序調(diào)用。

(4)在注冊(cè)表中為驅(qū)動(dòng)程序建立表項(xiàng)。在注冊(cè)表中建立驅(qū)動(dòng)程序入口點(diǎn),這樣設(shè)備管理器才能識(shí)別和管理這個(gè)驅(qū)動(dòng)。此外,注冊(cè)表中還能存儲(chǔ)額外的信息,這些信息可以在驅(qū)動(dòng)運(yùn)行之后被使用到。

在這次USB驅(qū)動(dòng)開(kāi)發(fā)過(guò)程中,錯(cuò)走許多冤枉路使我叫苦連天。我感受最深的是由于WinCE提供了通用串行總線驅(qū)動(dòng)程序(USBD)模塊、USBD接口函數(shù)全集、樣本主機(jī)控制器驅(qū)動(dòng)程序(HCD)模塊。所以,我們只需要根據(jù)USB設(shè)備硬件特性,利用USBD提供的不同函數(shù),實(shí)現(xiàn)流接口函數(shù)與外圍設(shè)備的交互。在沒(méi)有特別的情況下,我最大的收獲經(jīng)驗(yàn)是把這些公用的源程序照搬過(guò)來(lái),能極大的縮短開(kāi)發(fā)周期,從而能更快速地進(jìn)行嵌入式開(kāi)發(fā)。

隨著USB設(shè)備的普及,擺在開(kāi)發(fā)人員面前的驅(qū)動(dòng)開(kāi)發(fā)任務(wù)也是越來(lái)越繁重了,特別是對(duì)于一些嵌入式開(kāi)發(fā)廠商來(lái)講,由于設(shè)備所采用的操作系統(tǒng)不同,相應(yīng)的硬件接口也是不一樣的,開(kāi)發(fā)相關(guān)的USB 驅(qū)動(dòng)程序更是難上加難。Windows CE.NET 是微軟推出的功能強(qiáng)大的嵌入式操作系統(tǒng),國(guó)內(nèi)采用此操作系統(tǒng)的廠商已經(jīng)很多了,本文就以windows ce.net為例,簡(jiǎn)單介紹一下如何開(kāi)發(fā)windows ce.net下的USB驅(qū)動(dòng)程序。

首先要熟悉一些USB的基本概念,當(dāng)然最好把USB 1.1的協(xié)議看一遍,(當(dāng)然現(xiàn)在2。0的協(xié)議都已經(jīng)有了)http://www.usb.org
上可以下載,我記得好像有個(gè)中文版的,翻譯的還可以,http://www.driverdevolep.com
上有的,具體位置記不太清楚了,中文版的協(xié)議可以快速翻一邊,了解一些基本的概念,但是設(shè)計(jì)到一些關(guān)鍵性的東西最好還是看英文版的心里比較清楚些。

這里我就不介紹USB的基本協(xié)議了,假設(shè)用戶已經(jīng)熟悉了USB設(shè)備的一些基本的概念,并且對(duì)Winows CE.NET的開(kāi)發(fā)有一定的了解。

下面簡(jiǎn)略介紹一下Windows CE.NET中USB設(shè)備驅(qū)動(dòng)開(kāi)發(fā)的一些基礎(chǔ)知識(shí)。

Windows CE.NET 的USB系統(tǒng)軟件分為兩層: USB Client設(shè)備驅(qū)動(dòng)程序和底層的Windows CE實(shí)現(xiàn)的函數(shù)層。USB設(shè)備驅(qū)動(dòng)程序主要負(fù)責(zé)利用系統(tǒng)提供的底層接口配置設(shè)備,和設(shè)備進(jìn)行通訊。底層的函數(shù)提本身又由兩部分組成,通用串行總線驅(qū)動(dòng)程序(USBD)模塊和較低的主控制器驅(qū)動(dòng)程序(HCD)模塊。HCD負(fù)責(zé)最最底層的處理,USBD模塊實(shí)現(xiàn)較高的USBD函數(shù)接口。USB設(shè)備驅(qū)動(dòng)主要利用 USBD接口函數(shù)和他們的外圍設(shè)備打交道。

USB設(shè)備驅(qū)動(dòng)程序主要和USBD打交道,所以我們必須詳細(xì)的了解USBD提供的函數(shù)。

主要的傳輸函數(shù)有:
AbourtTransfer   IssueControlTransfer
CloseTransfer    IssueInterrupTransfer
GetIsochResult   IssueIsochTransfer
GetTransferStatus  IstransferComplete
IssueBulkTransfer  IssueVendorTransfer

主要的用于打開(kāi)和關(guān)閉USBD和USB設(shè)備之間的通信通道的函數(shù)有:
AbortPipeTransfers  ClosePipe
IsDefaultPipeHalted  IsPipeHalted
OpenPipe       ResetDefaultPipe
ResetPipe

相應(yīng)的打包函數(shù)接口有:
GetFrameLength   GetFrameNumber   ReleaseFrameLengthControl
SetFrameLength   TakeFrameLengthControl

取得設(shè)置設(shè)備配置函數(shù):
ClearFeature   SetDescriptor
GetDescriptor  SetFeature
GetInterface   SetInterface
GetStatus    SyncFrame

與USB進(jìn)行交互的實(shí)現(xiàn)方法相關(guān)的多任務(wù)函數(shù):
FindInterface         RegisterClientDeviceId
GetDeviceInfo         RegisterClientSettings
GetUSBDVersion         RegisterNotificationRoutine
LoadGenericInterfaceDriver   TranslateStringDescr
OpenClientRegisterKey     UnRegisterNotificationRoutine
常見(jiàn)的Windows CE.NET下USB的設(shè)備驅(qū)動(dòng)程序的編寫有以下幾種方法:

● 流式接口函數(shù)
這種驅(qū)動(dòng)程序主要呈現(xiàn)流式函數(shù)接口,主要輸出XXX_Init,XXX_Deinit,XXX_Open,XXX_Close,XXX_Open,XXX_Close,XXX_Read,XXX_Write,
XXX_Seek, XXX_IOControl,XXX_PowerUp,XXX_PowerDown等流式接口,注意上述的幾個(gè)接口一定都要輸出,另外XXX必須為三個(gè)字符,否則會(huì)出錯(cuò)。但是此類的驅(qū)動(dòng)程序不是通過(guò)設(shè)備管理接口來(lái)加載的,所以必須手工的調(diào)用RegisterDevice()和 DeregisterDevice()函數(shù)來(lái)加載和卸載驅(qū)動(dòng)程序。用戶可以將此類的設(shè)備作為標(biāo)準(zhǔn)的文件來(lái)操作,只要調(diào)用相應(yīng)的文件操作就可以和驅(qū)動(dòng)程序打交道。

● 使用現(xiàn)有的Window CE.NET的應(yīng)用程序接口
此類設(shè)備主要是利用Windows CE.NET中已經(jīng)有了現(xiàn)成的函數(shù)接口,例如USB Mass Storage Disk,它主要利用現(xiàn)有的Windows CE.Net中已經(jīng)有的可安裝文件系統(tǒng)接口,呈現(xiàn)給系統(tǒng)可用的文件系統(tǒng),對(duì)于用戶來(lái)講,它是透明的,用戶僅僅感覺(jué)在操作一個(gè)文件夾。

● 創(chuàng)建指定到特定的USBD的用戶指定的API
這種方法在USBD呈現(xiàn)設(shè)備時(shí)不需要任何限制,主要是特制的提供API給用戶,一般不太常見(jiàn)。


USB設(shè)備驅(qū)動(dòng)程序必須輸出的函數(shù)有:
● USBDeviecAttach
當(dāng)USB設(shè)備連接到計(jì)算機(jī)上時(shí),USBD模塊就會(huì)調(diào)用此函數(shù),這個(gè)函數(shù)主要用于初始化USB設(shè)備,取得USB設(shè)備信息,配置USB設(shè)備,并且申請(qǐng)必需的資源。
● USBInstallDriver
主要用于創(chuàng)建一個(gè)驅(qū)動(dòng)程序加載所需的注冊(cè)表信息,例如讀寫超時(shí),設(shè)備名稱等。
● USBUninstallDriver
主要用于釋放驅(qū)動(dòng)程序所占用的資源,以及刪除USBInstallDriver函數(shù)創(chuàng)建的注冊(cè)表等。
上述的三個(gè)函數(shù)接口是所有的USB驅(qū)動(dòng)程序必須提供的,缺一不可。
另外比較重要的是USB設(shè)備驅(qū)動(dòng)程序的注冊(cè)表配置,一般的USB設(shè)備驅(qū)動(dòng)程序的注冊(cè)表配置在HKEY_LOCAL_MACHINE\Drivers\USB \LoadClients下,每個(gè)驅(qū)動(dòng)程序的子鍵都有Group1_ID\Group2_ID\Group3_ID\DriverName格式,如果注冊(cè)表信息與USB設(shè)備信息符合,USBD就會(huì)加載此驅(qū)動(dòng)程序。否則設(shè)備的子鍵應(yīng)該由供應(yīng)商,設(shè)備類和協(xié)議信息通過(guò)下劃線組成。
具體的配置舉個(gè)例子:
例如你有個(gè)PDA設(shè)備,它具有一個(gè)USB接口,它的供應(yīng)廠商ID假設(shè)為0x0888,設(shè)備ID為0x0999,沒(méi)有使用特殊的協(xié)議,那么它的加載注冊(cè)表應(yīng)該寫為:
[HKEY_LOCAL_MACHINE\Drivers\USB\LoadClients\2184_2457\Default\Default\PDA] "DLL"="pdausb.dll"
需要注意的是注冊(cè)表構(gòu)成都是十進(jìn)制數(shù)值來(lái)標(biāo)識(shí)的,注意一下十進(jìn)制和十六進(jìn)制的轉(zhuǎn)換。
再舉個(gè)USB鼠標(biāo)的例子,USB鼠標(biāo)是標(biāo)準(zhǔn)的HID設(shè)備,它的協(xié)議為:InterfaceClassCode為3(HID類), InterfaceSubclassCode為1(引導(dǎo)接口類),InterfaceProtocolCode為2(鼠標(biāo)協(xié)議類),所以它的注冊(cè)如下:
[HKEY_LOCAL_MACHINE\Drivers\USB\LoadClients\Default\Default\3_1_2\USBMouse] "DLL"="usbmouse.dll"

到此為止,我們可以看出,其實(shí)驅(qū)動(dòng)開(kāi)發(fā)無(wú)非做兩件事情,一件是和硬件打交道,另外一件是和操作系統(tǒng)打交道。舉個(gè)簡(jiǎn)單的例子,例如:我們需要開(kāi)發(fā)一個(gè)USB鼠標(biāo)驅(qū)動(dòng)程序,我們就需要了解USB鼠標(biāo)硬件上是怎么發(fā)送數(shù)據(jù)的?操作系統(tǒng)怎么才能得到鼠標(biāo)的控制事件?其實(shí)USB鼠標(biāo)是有一個(gè)中斷PIPE的,用于傳送鼠標(biāo)產(chǎn)生的數(shù)據(jù),Windwos CE.NET中有個(gè)接口函數(shù)叫做mouse_event(),專門用于產(chǎn)生鼠標(biāo)事件,但是它是不關(guān)心具體什么硬件的,甚至我們自己在應(yīng)用程序中調(diào)用這個(gè)函數(shù)都可以實(shí)現(xiàn)模擬鼠標(biāo),對(duì)應(yīng)的有個(gè)keybd_event(),用于產(chǎn)生鍵盤事件,知道了這個(gè)就好辦多了,只要將相應(yīng)的數(shù)據(jù)轉(zhuǎn)換一下,調(diào)用一下 mouse_event()即可

例如我們有個(gè)USB Mouse設(shè)備,設(shè)備信息描述如下:
Device Descriptor:
bcdUSB: 0x0100
bDeviceClass: 0x00
bDeviceSubClass: 0x00
bDeviceProtocol: 0x00
bMaxPacketSize0: 0x08 (8)
idVendor: 0x05E3 (Genesys Logic Inc.)
idProduct: 0x0001
bcdDevice: 0x0101
iManufacturer: 0x00
iProduct: 0x01
iSerialNumber: 0x00
bNumConfigurations: 0x01

ConnectionStatus: DeviceConnected
Current Config Value: 0x01
Device Bus Speed: Low
Device Address: 0x02
Open Pipes: 1

Endpoint Descriptor:
bEndpointAddress: 0x81
Transfer Type: Interrupt
wMaxPacketSize: 0x0003 (3)
bInterval: 0x0A

可以看出上述設(shè)備有一個(gè)中斷PIPE,包的最大值為3。可能有人問(wèn)上述的值怎么得到的,win2k 的DDK中有個(gè)usbview的例程,編譯一下,將你的USB設(shè)備插到PC機(jī)的USB口中,運(yùn)行usbview.exe即可看得相應(yīng)的設(shè)備信息。

有了這些基本信息,就可以編寫USB設(shè)備了,首先聲明一下,下面的代碼取自微軟的USB鼠標(biāo)樣本程序,版權(quán)歸微軟所有,此處僅僅借用來(lái)描述一下USB鼠標(biāo)驅(qū)動(dòng)的開(kāi)發(fā)過(guò)程,讀者如需要引用此代碼,需要得到微軟的同意。

首先,必須輸出USBD要求調(diào)用的三個(gè)函數(shù),首先到設(shè)備插入到USB端口時(shí),USBD會(huì)調(diào)用USBDeviceAttach()函數(shù),相應(yīng)的代碼如下:
extern "C" BOOL
USBDeviceAttach(
USB_HANDLE hDevice, // USB設(shè)備句柄
LPCUSB_FUNCS lpUsbFuncs, // USBDI的函數(shù)集合
LPCUSB_INTERFACE lpInterface, // 設(shè)備接口描述信息
LPCWSTR szUniqueDriverId, // 設(shè)備ID描述字符串。
LPBOOL fAcceptControl, // 返回TRUE,標(biāo)識(shí)我們可以控制此設(shè)備, 反之表示不能控制
DWORD dwUnused)
{
*fAcceptControl = FALSE;
// 我們的鼠標(biāo)設(shè)備有特定的描述信息,要檢測(cè)是否是我們的設(shè)備。
if (lpInterface == NULL)
return FALSE;
// 打印相關(guān)的USB設(shè)備接口描述信息。
DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: DeviceAttach, IF %u, #EP:%u, Class:%u, Sub:%u,Prot:%u\r\n"), lpInterface->Descriptor.bInterfaceNumber,lpInterface->Descriptor.bNumEndpoints, lpInterface->Descriptor.bInterfaceClass,lpInterface->Descriptor.bInterfaceSubClass,lpInterface->Descriptor.bInterfaceProtocol));
// 初試數(shù)據(jù)USB鼠標(biāo)類,產(chǎn)生一個(gè)接受USB鼠標(biāo)數(shù)據(jù)的線程
CMouse * pMouse = new CMouse(hDevice, lpUsbFuncs, lpInterface);
if (pMouse == NULL)
return FALSE;

if (!pMouse->Initialize())
{
delete pMouse;
return FALSE;
}

// 注冊(cè)一個(gè)監(jiān)控USB設(shè)備事件的回調(diào)函數(shù),用于監(jiān)控USB設(shè)備是否已經(jīng)拔掉。
(*lpUsbFuncs->lpRegisterNotificationRoutine)(hDevice,
USBDeviceNotifications, pMouse);

*fAcceptControl = TRUE;
return TRUE;
}

第二個(gè)函數(shù)是 USBInstallDriver()函數(shù),
一些基本定義如下:
const WCHAR gcszRegisterClientDriverId[] = L"RegisterClientDriverID";
const WCHAR gcszRegisterClientSettings[] = L"RegisterClientSettings";
const WCHAR gcszUnRegisterClientDriverId[] = L"UnRegisterClientDriverID";
const WCHAR gcszUnRegisterClientSettings[] = L"UnRegisterClientSettings";
const WCHAR gcszMouseDriverId[] = L"Generic_Sample_Mouse_Driver";

函數(shù)接口如下:
extern "C" BOOL
USBInstallDriver(
LPCWSTR szDriverLibFile) // @parm [IN] - Contains client driver DLL name
{
BOOL fRet = FALSE;
HINSTANCE hInst = LoadLibrary(L"USBD.DLL");

// 注冊(cè)USB設(shè)備信息
if(hInst)
{
LPREGISTER_CLIENT_DRIVER_ID pRegisterId = (LPREGISTER_CLIENT_DRIVER_ID)
GetProcAddress(hInst, gcszRegisterClientDriverId);

LPREGISTER_CLIENT_SETTINGS pRegisterSettings =
(LPREGISTER_CLIENT_SETTINGS) GetProcAddress(hInst,
gcszRegisterClientSettings);

if(pRegisterId && pRegisterSettings)
{
USB_DRIVER_SETTINGS DriverSettings;

DriverSettings.dwCount = sizeof(DriverSettings);

// 設(shè)置我們的特定的信息。
DriverSettings.dwVendorId = USB_NO_INFO;
DriverSettings.dwProductId = USB_NO_INFO;
DriverSettings.dwReleaseNumber = USB_NO_INFO;

DriverSettings.dwDeviceClass = USB_NO_INFO;
DriverSettings.dwDeviceSubClass = USB_NO_INFO;
DriverSettings.dwDeviceProtocol = USB_NO_INFO;

DriverSettings.dwInterfaceClass = 0x03; // HID
DriverSettings.dwInterfaceSubClass = 0x01; // boot device
DriverSettings.dwInterfaceProtocol = 0x02; // mouse

fRet = (*pRegisterId)(gcszMouseDriverId);

if(fRet)
{

]]>
WINCE6.0+S3C2443系統(tǒng)速度測(cè)試http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1818&Page=1wangxinxin2010-11-26 10:52:10根據(jù)客戶的需要,我們公司的GPS產(chǎn)品決定采用WINCE6.0操作系統(tǒng),采用基于長(zhǎng)高的WINCE6.0+S3C2443的BSP包來(lái)開(kāi)發(fā),就系統(tǒng)速度這個(gè)問(wèn)題做了以下測(cè)試:

測(cè)試硬件和軟件
硬件:
同一塊板子,LCD是800*480分辨率的
軟件:
同是TCPMP0.81版本的視頻播放軟件

測(cè)試:
1. 在板子上運(yùn)行長(zhǎng)高的WINCE5.0系統(tǒng),使用TCPMP0.81版本進(jìn)行benchmark測(cè)試(用GDI格式),得到的Average Speed =100.48%
2. 在板子上運(yùn)行長(zhǎng)高的WINCE6.0系統(tǒng),使用TCPMP0.81版本進(jìn)行benchmark測(cè)試(用GDI格式),得到的Average Speed =72.18%

問(wèn)題:
為什么在同一塊板子上運(yùn)行同一個(gè)視頻播放軟件,測(cè)試出來(lái)的Average Speed的值會(huì)差這么多,而且反而是WINCE5.0的NK的播放速度更快(100.48%>72.18%)

我在測(cè)試過(guò)程中發(fā)現(xiàn)以下問(wèn)題:
在5.0的系統(tǒng)開(kāi)機(jī)后第一次運(yùn)行TCPMP時(shí),這個(gè)視頻播放軟件很快就加載起來(lái)了(運(yùn)行起來(lái)),而在6.0的系統(tǒng)開(kāi)機(jī)后第一次運(yùn)行TCPMP時(shí),要等大概30s中才能加載起來(lái),而且有如下的串口輸出信息:
Exception 'Undefined Instruction' (1): Thread-Id=084e0002(pth=83c29270), Proc-Id=084d0002(pprc=83c0f024) 'PLAYER.EXE', VM-active=084d0002(pprc=83c0f024) 'PLAYER.EXE'
PC=4170b6c8(common.dll+0x0004b6c8) RA=416f9f40(common.dll+0x00039f40) SP=0003fba8, BVA=00000000
OALIoCtlHalGetDeviceInfo():SPI_GETPLATFORMNAME
OALIoCtlHalGetDeviceInfo():SPI_GETOEMINFO
+GetGameXInfo 
Stride=1600, Width=800, Height=480, FrmaeBuffer=d2e20000 
-GetGameXInfo 
Exception 'Data Abort' (4): Thread-Id=084e0002(pth=83c29270), Proc-Id=084d0002(pprc=83c0f024) 'PLAYER.EXE', VM-active=084d0002(pprc=83c0f024) 'PLAYER.EXE'
PC=416ffb44(common.dll+0x0003fb44) RA=416ffb3c(common.dll+0x0003fb3c) SP=0003fb10, BVA=d2e20000
In else------------>>>

根據(jù)我的分析,至于為什么會(huì)出現(xiàn)WINCE5.0的NK的播放速度對(duì)6.0下的快這個(gè)問(wèn)題,我想問(wèn)題在以下部分:
1. TCPMP0.81不能很好的兼容WINCE6.0,這需要TCPMP針對(duì)WINCE6.0做一些修改和移植。
2. 可能WINCE6.0的BSP包的顯示驅(qū)動(dòng)沒(méi)有完善好

 
]]>
如何為WinCE的定制鍵盤寫驅(qū)動(dòng)http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1817&Page=1wangxinxin2010-11-26 10:49:40常看到有人問(wèn)怎么給定制鍵盤制作驅(qū)動(dòng)程序,在這里談?wù)勎业慕?jīng)驗(yàn)。完整的鍵盤驅(qū)動(dòng)怎么寫不是這篇文章的目的,這些MSDN上有很詳細(xì)的介紹。這里談的是,舉個(gè)例子,標(biāo)準(zhǔn)的美國(guó)英語(yǔ)鍵盤的數(shù)字鍵SHIFT+2輸出符號(hào)@,你想改成歐元符號(hào)該怎么做?或者你想做一個(gè)法語(yǔ)鍵盤,又該怎么做?又或者你想基于同樣的鍵盤硬件設(shè)計(jì),軟件上同時(shí)支持英語(yǔ)、法語(yǔ)、俄語(yǔ)layout,又該怎么弄?

在WinCE上,從鍵盤驅(qū)動(dòng)的角度看,鍵盤驅(qū)動(dòng)對(duì)按鍵動(dòng)作的響應(yīng)過(guò)程大約可描述為:

按鍵產(chǎn)生中斷
鍵盤驅(qū)動(dòng)讀取按鍵的scan code
鍵盤驅(qū)動(dòng)把scan code映射成virtual key和unicode字符
鍵盤驅(qū)動(dòng)把按鍵消息發(fā)送到圖形窗口子系統(tǒng)(GWES)。
鍵的scan code由keyboard matrix決定,跟鍵盤的硬件設(shè)計(jì)有關(guān)。因此從軟件角度看,鍵盤的scan code是不能改的。但是由于按鍵最終輸出的是可打印字符或者virtual key,這里面就有個(gè)映射關(guān)系,這個(gè)映射關(guān)系可以在鍵盤驅(qū)動(dòng)理指定,甚至可以動(dòng)態(tài)切換。WinCE的標(biāo)準(zhǔn)鍵盤驅(qū)動(dòng)框架定義了兩張映射表:即Scan code到virtual key的映射表(Device layout),和virtual key到unicode的映射表(input language)。通過(guò)修改這兩張映射表的定義,我們就可以控制鍵盤上的每一個(gè)按鍵或者按鍵組合的輸出。

 D:\WINCE500\PUBLIC\COMMON\OAK\DRIVERS\KEYBD目錄下有一些針對(duì)標(biāo)準(zhǔn)鍵盤的源代碼:DEVICELAYOUTS子目錄下是Scan code到virtual key映射表,INPUTLANGS子目錄下是virtual key到unicode映射表。具體做時(shí)主要是改這兩張表,加上其他一些輔助代碼編譯成DLL。除此之外,WinCE還提供一個(gè)工具 (D:\WINCE500\PUBLIC\COMMON\OAK\BIN\I386\kbdgen.exe),可以從Windows XP系統(tǒng)鍵盤驅(qū)動(dòng)中提取映射表。比如下面命令生成法語(yǔ)鍵盤映射表的源代碼:

kbdgen.exe kbdfr.dll -o kbd_040c -i 0000040C

結(jié)果輸出三個(gè)文件:

kbd_040c.reg:注冊(cè)表文件
kbd_040cDL.cpp:scan code -> virtual key映射表
kbd_040cIL.cpp:virtual key -> wide character映射表

鍵盤驅(qū)動(dòng)名在注冊(cè)表里[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Keyboard Layouts]可以查到,比如法語(yǔ)的locale是040C,在0000040c子鍵下可以找到驅(qū)動(dòng)為kbdfr.dll。

scan code到virtual key(即device layout)在ScanCodeToVKeyTable數(shù)組里定義,一般不用改:

#define ScanCodeTableFirst  0x00
#define ScanCodeTableLast   0x8f
static UINT8 ScanCodeToVKeyTable[] =
{
    0,      // Scan Code 0x0
    VK_F9,  // Scan Code 0x1
    0,      // Scan Code 0x2
    VK_F5,  // Scan Code 0x3
    VK_F3,  // Scan Code 0x4
    VK_F1,  // Scan Code 0x5
    VK_F2,  // Scan Code 0x6
    VK_F12, // Scan Code 0x7
    0,      // Scan Code 0x8
    VK_F10, // Scan Code 0x9
    VK_F8,  // Scan Code 0xA
    VK_F6,  // Scan Code 0xB

};
 有時(shí)候你可能想知道鍵盤上每個(gè)鍵對(duì)應(yīng)的scan code,你可以在鍵盤驅(qū)動(dòng)KeybdPdd_GetEventEx2函數(shù)中用RETAILMSG把scan code打印出來(lái)。

定制的重點(diǎn)是修改virtual key到unicode映射表,即 aVkToWch1~aVkToWch5等幾個(gè)數(shù)組,歐洲語(yǔ)言鍵盤還要改aDeadKey數(shù)組,這幾個(gè)數(shù)組控制各種組合按鍵輸出,比如用戶按下A, Shift+A, Ctrl+Shift+A, Dead key+A,分別輸出什么東西 。

舉例來(lái)說(shuō),標(biāo)準(zhǔn)美語(yǔ)鍵盤SHIFT+2輸出@,你想改成歐元符號(hào)€。先查出€的unicode值為20AC(利用MS Office的symbol對(duì)話框),然后修改aVkToWch2數(shù)組:

static VK_TO_WCHARS2 aVkToWch2[] = {
  {'2'          ,0      ,'2'      ,0x20ac      },

};
 如果你同時(shí)還想讓CTRL+ALT+2輸出§(unicode 00A7),那么要改aVkToWch5而不是aVkToWch2:

static VK_TO_WCHARS5 aVkToWch5[] = {
  {'2'          ,0 ,'2'      ,0x20ac      ,WCH_NONE ,0x0000   ,0xb9    },

};

映射表的修改過(guò)程大致如此。有了DLL還要在注冊(cè)表中做些配置。在platform.reg中添加:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Layouts\0000040C]
    "Layout File"="kbd_040c.dll"
    "Layout Text"="French"
    "PS2_AT"="kbd_040c.dll"

如果你同時(shí)支持英語(yǔ)和法語(yǔ)鍵盤,可以把法語(yǔ)設(shè)為第二鍵盤:
[HKEY_CURRENT_USER\Keyboard Layout\Preload\2]
    @="0000040C"

甚至還可以設(shè)置熱鍵在運(yùn)行時(shí)切換鍵盤:
;Enabling ALT+SHIFT keyboard layout toggle short cut key
;  "Hotkey"="1" => ALT+SHIFT
;  "Hotkey"="2" => CTRL+SHIFT
;  "Hotkey"="3" => None
; The toggle key is disabled even if the key is not defined.
[HKEY_CURRENT_USER\keyboard layout\toggle]
    "Hotkey"="1"

]]>
WinCE和Win2000/XP設(shè)備驅(qū)動(dòng)開(kāi)發(fā)的區(qū)別http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1816&Page=1wangxinxin2010-11-26 10:44:42引 言

Windows CE是一個(gè)32位、多任務(wù)、多線程的嵌入式操作系統(tǒng),是微軟專門為信息設(shè)備、移動(dòng)應(yīng)用、消費(fèi)類電子產(chǎn)品、嵌入式應(yīng)用等非PC領(lǐng)域設(shè)計(jì)的操作系統(tǒng)產(chǎn)品,在外觀和使用的感覺(jué)上十分接近桌面Windows系統(tǒng)。它使用平面內(nèi)存模式尋址,可以同時(shí)運(yùn)行多個(gè)程序并支持一個(gè)程序中的多個(gè)線程,并且非常精煉,只有很小的內(nèi)存要求。與基于PC的操作系統(tǒng)不同,Windows CE不需要標(biāo)準(zhǔn)硬件,反而支持各種各樣的CPU(如X86、PowerPC、ARM、MIPS等),通過(guò)OEM適配層(OEM adaptation layer)可以把Windows CE適配到任何硬件平臺(tái)。Windows CE是微軟Windows操作系統(tǒng)家族的一個(gè)成員,支持用于Windows 2000/XP和Windows 98等桌面Windows操作系統(tǒng)的Win32 API的一個(gè)子集。由于它不是桌面Windows操作系統(tǒng)的一部分或縮減版本,使得開(kāi)發(fā)Windows CE的驅(qū)動(dòng)程序與開(kāi)發(fā)桌面Windows的驅(qū)動(dòng)程序有所不同。本文將著重討論這些區(qū)別,以使廣大熟悉桌面Windows驅(qū)動(dòng)程序開(kāi)發(fā)的程序員能快速掌握嵌入式操作系統(tǒng)WindowsCE驅(qū)動(dòng)程序的開(kāi)發(fā)方法。

1 驅(qū)動(dòng)結(jié)構(gòu)模型比較

在桌面Windows系統(tǒng),以支持Windows2000/XP的WDM驅(qū)動(dòng)模型為例。WDM體系結(jié)構(gòu)實(shí)行分層處理,即設(shè)備驅(qū)動(dòng)被分成了若干層——最高層驅(qū)動(dòng)程序、中間層驅(qū)動(dòng)程序、最低層驅(qū)動(dòng)程序,如圖1所示。

圖片點(diǎn)擊可在新窗口打開(kāi)查看 圖片點(diǎn)擊可在新窗口打開(kāi)查看

在Windows CE驅(qū)動(dòng)中,按驅(qū)動(dòng)的結(jié)構(gòu)可以分為兩種類型——分層式設(shè)備驅(qū)動(dòng)程序和整體式驅(qū)動(dòng)程序,如圖2所示。分層式設(shè)備驅(qū)動(dòng)程序由上層和下層兩部分代碼組成。上層的程序叫做模型設(shè)備驅(qū)動(dòng)程序(MDD),下層的程序則叫做平臺(tái)相關(guān)的驅(qū)動(dòng)程序(PDD)。整體式驅(qū)動(dòng)程序的源代碼由中斷服務(wù)線程代碼和針對(duì)平臺(tái)的代碼組成。

同桌面Windows設(shè)備驅(qū)動(dòng)結(jié)構(gòu)模型相比,Windows CE設(shè)備驅(qū)動(dòng)相對(duì)簡(jiǎn)單一些。正如圖1和圖2所示,兩種操作系統(tǒng)的設(shè)備驅(qū)動(dòng)雖然存在許多相似的地方,都采用了模塊、分層的設(shè)計(jì)方法,但是還存在許多不同的地方。在Windows CE操作系統(tǒng)中,分層的驅(qū)動(dòng)程序并不適用于所用的驅(qū)動(dòng),尤其是將驅(qū)動(dòng)程序分為兩層將會(huì)導(dǎo)致在驅(qū)動(dòng)程序操作時(shí)附加的功能調(diào)用,這無(wú)疑會(huì)降低驅(qū)動(dòng)程序的效率。對(duì)于時(shí)間或性能關(guān)鍵的實(shí)時(shí)操作,整體式驅(qū)動(dòng)程序?qū)?huì)更適合。

圖片點(diǎn)擊可在新窗口打開(kāi)查看

在桌面Windows系統(tǒng)中,驅(qū)動(dòng)各層通信之間使用一種稱為I/O請(qǐng)求包(IRP)的數(shù)據(jù)結(jié)構(gòu)進(jìn)行通信。影響到設(shè)備的每個(gè)操作都使用I/O請(qǐng)求包,采用層次結(jié)構(gòu)可以使I/O請(qǐng)求過(guò)程更加明了。I/O管理器發(fā)送IRP來(lái)請(qǐng)求驅(qū)動(dòng)程序的處理,通常IRP由分層的驅(qū)動(dòng)程序棧來(lái)處理,高層的驅(qū)動(dòng)程序把請(qǐng)求劃分成更簡(jiǎn)單的請(qǐng)求并傳遞給下層驅(qū)動(dòng)程序。IRP首先被送到設(shè)備堆棧的最上層驅(qū)動(dòng)程序,然后逐漸過(guò)濾到下層的驅(qū)動(dòng)程序。每一層驅(qū)動(dòng)程序都可以決定如何處理IRP。而Windows CE驅(qū)動(dòng)各層之間的通信沒(méi)有采用IRP通信機(jī)制,而是通過(guò)接口函數(shù)調(diào)用實(shí)現(xiàn)的。設(shè)備驅(qū)動(dòng)程序接口(Device Driver Interface,DDI)是在MDD層中實(shí)現(xiàn)的函數(shù)集,系統(tǒng)中的GWES模塊通過(guò)這個(gè)接口調(diào)用設(shè)備驅(qū)動(dòng)程序;設(shè)備驅(qū)動(dòng)程序服務(wù)器接口(Device Driver Service Provider Interface,DDSI)是在PDD層中實(shí)現(xiàn)的函數(shù)集并由MDD調(diào)用。

2 設(shè)備驅(qū)動(dòng)組成部分比較

簡(jiǎn)單地說(shuō),驅(qū)動(dòng)程序是一些例程的集合,它們被動(dòng)地存在,等待主機(jī)系統(tǒng)軟件來(lái)調(diào)用或激活它們。在Win-dows系統(tǒng)中驅(qū)動(dòng),具體的驅(qū)動(dòng)程序有所不同,其包含的例程也不同,但其主要例程是相同的。圖3描述一個(gè)Windows驅(qū)動(dòng)的基本流程。

圖片點(diǎn)擊可在新窗口打開(kāi)查看

以下從幾個(gè)方面闡述WindowsCE和桌面Windows設(shè)備驅(qū)動(dòng)組成的不同。

2.1 驅(qū)動(dòng)程序的入口點(diǎn)

在桌面Windows和Windows CE兩個(gè)系統(tǒng)中的驅(qū)動(dòng)程序都含有初始化模塊,該模塊主要功能是完成驅(qū)動(dòng)程序的初始化及卸載。在桌面Windows系統(tǒng)的初始化模塊中,包括每一個(gè)設(shè)備驅(qū)動(dòng)程序都有的一個(gè)初始化入口點(diǎn)——DriverEntry例程,每次設(shè)備驅(qū)動(dòng)程序啟動(dòng)時(shí)該例程被系統(tǒng)自動(dòng)調(diào)用。其最重要的功能是設(shè)置驅(qū)動(dòng)程序?qū)?yīng)于I/O請(qǐng)求的主功能代碼(MajorFunction)的回調(diào)例程。DriverEntry例程如下:

圖片點(diǎn)擊可在新窗口打開(kāi)查看

其中,AddDevice例程是在系統(tǒng)添加一個(gè)設(shè)備時(shí)被PnP管理器調(diào)用的,其主要工作是創(chuàng)建并初始化設(shè)備對(duì)象;DriverUnload例程在系統(tǒng)卸載硬件時(shí)使用,由I/O管理器調(diào)用,釋放所有資源。初始化模塊中還包括Create和Close兩個(gè)例程,這是Win32程序獲得和釋放設(shè)備句柄的唯一途徑。

與桌面Windows設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)相比,WindowsCE設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)的主要難點(diǎn)是,對(duì)于不同類型設(shè)備的驅(qū)動(dòng)程序架構(gòu)是不一樣的。以流接口驅(qū)動(dòng)程序?yàn)槔琖indows CE設(shè)備驅(qū)動(dòng)程序是用戶模式動(dòng)態(tài)鏈接庫(kù)(DLL),其入口點(diǎn)在不同的情況有一些細(xì)微的差別,主要入口點(diǎn)包括XXX_Init、XXX_Deinit、XXX_Open、XXX_Close、XXX_IOControl、XXX_Read、XXX_Seek、XXX_PowerUp和XXX_PowerDown,在實(shí)際開(kāi)發(fā)中接口名稱中的XXX三個(gè)字母由設(shè)備驅(qū)動(dòng)的設(shè)備文件名前綴代替。

2.2 與應(yīng)用程序的通信

設(shè)備驅(qū)動(dòng)程序構(gòu)造成功之后,將它與設(shè)備一同安裝進(jìn)系統(tǒng),以便用戶可以對(duì)設(shè)備進(jìn)行適當(dāng)?shù)目刂萍霸L問(wèn)。在桌面Windows和Windows CE兩個(gè)系統(tǒng)中使用Win32 API實(shí)現(xiàn)硬件的訪問(wèn)。首先調(diào)用CreateFile創(chuàng)建一個(gè)設(shè)備的連接,獲得該設(shè)備的句柄(Handle),然后根據(jù)需要調(diào)用ReadFile、WriteFile、DeviceIoControI等函數(shù)對(duì)設(shè)備進(jìn)行讀寫或者其他I/O控制操作,最后調(diào)用CloseHandle關(guān)閉設(shè)備。

在桌面Windows系統(tǒng)中,當(dāng)用戶需要訪問(wèn)某設(shè)備時(shí),必須首先取出指定設(shè)備全局唯一標(biāo)識(shí)符(GUID)的設(shè)備信息集,枚舉設(shè)備實(shí)例的接口數(shù)據(jù),從中獲得設(shè)備的符號(hào)鏈接名,然后調(diào)用CreatFile創(chuàng)建設(shè)備,并獲得設(shè)備句柄,而在驅(qū)動(dòng)程序內(nèi)部通過(guò)處理IRP響應(yīng)來(lái)自Win32應(yīng)用程序?qū)RP_MJ_CREATE、IRP_MJ_READ、IRP_MJ_WRITE和IRP_MJ_OCTL等請(qǐng)求。IRP由IRP首部結(jié)構(gòu)和一系列的棧單元組成,每個(gè)棧單元是一個(gè)IO_STACK_LOCA-TION結(jié)構(gòu)。驅(qū)動(dòng)程序僅需知道當(dāng)前I/O棧單元和IRP首部結(jié)構(gòu)中的信息就可以對(duì)IRP進(jìn)行處理。驅(qū)動(dòng)程序處理完IRP后,使用IoCompleteRequest函數(shù)通知I/O管理器,可以通過(guò)其參數(shù)設(shè)定狀態(tài)碼和返回的字節(jié)數(shù)。在Windows CE系統(tǒng)中,應(yīng)用程序需要了解中斷處理線程中數(shù)據(jù)的輸入輸出完成情況,以便及時(shí)地處理。這就需要建立應(yīng)用程序和設(shè)備驅(qū)動(dòng)程序的同步通信。

2.3 設(shè)備名

在Windows設(shè)備驅(qū)動(dòng)中,為了提供Win32程序可用的名字,必須為每個(gè)設(shè)備創(chuàng)建符號(hào)鏈接。在桌面Windows和Windows CE兩個(gè)系統(tǒng)中,都可以采用一個(gè)明確的符號(hào)鏈接名。一個(gè)具體設(shè)備名稱是由設(shè)備名前綴和設(shè)備名索引組成的,即3個(gè)大寫字母、1位數(shù)字和冒號(hào)組成。另外在桌面Windows系統(tǒng)中,還可以采用設(shè)備接口為設(shè)備創(chuàng)建符號(hào)鏈接。每個(gè)設(shè)備接口由一個(gè)128位全局唯一標(biāo)識(shí)符(GUID)標(biāo)志。把設(shè)備注冊(cè)為一個(gè)特定的設(shè)備接口就創(chuàng)建了一個(gè)符號(hào)鏈接。用戶態(tài)設(shè)備可以取得擁有此GUID的設(shè)備。

2. 4 驅(qū)動(dòng)程序的運(yùn)行模式

在Windows系統(tǒng)中支持兩種基本模式的驅(qū)動(dòng)程序類型,即用戶模式(user mode)和內(nèi)核模式(kernel mode),不同的模式允許不同層次的內(nèi)存存取和系統(tǒng)資源的分配。內(nèi)核模式驅(qū)動(dòng)程序則由運(yùn)行于內(nèi)核模式的系統(tǒng)級(jí)代碼組成,它們沒(méi)有系統(tǒng)資源存取的限制,可以執(zhí)行任何有效的CPU指令,被用來(lái)直接控制硬件。用戶模式驅(qū)動(dòng)程序是按用戶模式運(yùn)行的系統(tǒng)級(jí)代碼,它們不能使用直接的硬件I/O指令來(lái)訪問(wèn)硬件。

桌面Windows系統(tǒng)一般要求設(shè)備驅(qū)動(dòng)運(yùn)行在內(nèi)核模式下。內(nèi)核模式提供設(shè)備資源的直接訪問(wèn),沒(méi)有固定的用戶模式的輔助操作。

Windows CE系統(tǒng)一般要求設(shè)備驅(qū)動(dòng)運(yùn)行在用戶模式下。這種運(yùn)行在用戶模式下的設(shè)備驅(qū)動(dòng)程序有許多優(yōu)點(diǎn),最明顯的優(yōu)點(diǎn)是當(dāng)設(shè)備驅(qū)動(dòng)開(kāi)發(fā)有錯(cuò)誤動(dòng)作時(shí),內(nèi)核被有效地保護(hù)起來(lái)了,因此內(nèi)核被驅(qū)動(dòng)程序破壞,或者可能導(dǎo)致不能重新啟動(dòng)內(nèi)核的潛在目標(biāo)存儲(chǔ)錯(cuò)誤,以及其他意想不到的災(zāi)難等發(fā)生的可能性就明顯地減少。

2.5 驅(qū)動(dòng)程序的安裝

桌面Windows的驅(qū)動(dòng)安裝通過(guò)INF文件。INF文件是一個(gè)文本文件,含有安裝一個(gè)WDM驅(qū)動(dòng)設(shè)備程序需要的所有必需的信息,包括要復(fù)制的文件列表、要?jiǎng)?chuàng)建的注冊(cè)表項(xiàng)等。驅(qū)動(dòng)根據(jù)INF文件中的指令安裝,驅(qū)動(dòng)程序可執(zhí)行文件被復(fù)制到正確的位置,通常是Windows Sys-tem32\Drivers目錄,然后創(chuàng)建各種注冊(cè)表項(xiàng)。WindowsCE和桌面Windows之間的最大區(qū)別是,Windows CE不支持.sys和.inf文件。Windows CE設(shè)備驅(qū)動(dòng)編譯成動(dòng)態(tài)庫(kù),將驅(qū)動(dòng)的動(dòng)態(tài)庫(kù)文件直接拷入Windows\目錄,然后創(chuàng)建各種注冊(cè)表項(xiàng)即可。這就減少了Windows CE加載程序的復(fù)雜性和大小。

3 開(kāi)發(fā)環(huán)境比較

在桌面Windows系統(tǒng)中,驅(qū)動(dòng)程序的開(kāi)發(fā)采用兩種方式。一類是Microsoft公司提供的Windows DDK(De-vice Driver Kit),由于DDK基于匯編語(yǔ)言的編程方式和內(nèi)核模式的調(diào)用,對(duì)沒(méi)有深厚的OS原理和編程水平的人員來(lái)說(shuō),任務(wù)相當(dāng)艱巨。另一類是NuMega公司提供的DriverStudio,它是一個(gè)大的開(kāi)發(fā)工具包,包含VtoolsD、SoftICE和DriverWorks等開(kāi)發(fā)工具。利用DriverStudio開(kāi)發(fā)WDM驅(qū)動(dòng)程序,可以大大減輕開(kāi)發(fā)人員的工作量、縮短開(kāi)發(fā)周期,以及降低開(kāi)發(fā)驅(qū)動(dòng)程序的難度。

Windows CE開(kāi)發(fā)平臺(tái)的開(kāi)發(fā)者、獨(dú)立硬件供應(yīng)商(IHVS)和應(yīng)用程序開(kāi)發(fā)者都會(huì)從事基于Windows CE平臺(tái)的設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)。對(duì)于不同的開(kāi)發(fā)者,微軟為Windows CE提供了2種開(kāi)發(fā)工具:Platform Builder和Embedded Visual Tools。Platform Builder是一個(gè)定制基于Windows CE操作系統(tǒng)的嵌入式平臺(tái)的集成開(kāi)發(fā)環(huán)境(IDE),為創(chuàng)建Windows CE嵌入式系統(tǒng)提供了全部相關(guān)工具,范圍從用來(lái)開(kāi)發(fā)基于Windows CE的應(yīng)用程序和設(shè)備驅(qū)動(dòng)程序,到用來(lái)創(chuàng)建操作系統(tǒng)各種自定義版本。而Embedded Visual Tools主要用于上層應(yīng)用程序、驅(qū)動(dòng)的開(kāi)發(fā),功能類似于桌面Windows平臺(tái)上的開(kāi)發(fā)工具VC、VB等。這個(gè)工具的核心是Embedded Visual C++,它具有和Visual C++6.0基本相同的特性,包括對(duì)MFC、ATL以及COM/DCOM的支持、應(yīng)用程序向?qū)А⒕幾g調(diào)試等多種功能。

結(jié) 語(yǔ)

理解Windows CE與桌面Windows設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)的區(qū)別,有助于廣大熟悉桌面Windows設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)的程序員快速掌握嵌入式操作系統(tǒng)Windows CE的設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)。近幾年來(lái),信息家電、掌上電腦、電視機(jī)頂盒等基于Windows CE操作系統(tǒng)的設(shè)備已變得越來(lái)越普及,而Windows CE上的設(shè)備驅(qū)動(dòng)程序還比較少,因此Windows CE設(shè)備驅(qū)動(dòng)程序具有不少潛力和市場(chǎng)。希望本文對(duì)打算開(kāi)發(fā)Windows CE設(shè)備驅(qū)動(dòng)程序的人們有所幫助。

]]>
詳解WinCE下USB Host驅(qū)動(dòng)開(kāi)發(fā)(2)http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1815&Page=1wangxinxin2010-11-26 10:38:05BOOL USBUnInstallDriver();
    它與USBInstallDriver類似,不過(guò)是調(diào)用如下兩個(gè)函數(shù)
UnRegisterClientSettings
    BOOL UnRegisterClientSettings(LPCWSTR szUniqueDriverId, LPCWSTR szReserved, LPCUSB_DRIVER_SETTINGS lpDriverSettings);
    BOOL UnRegisterClientDriverID(LPCWSTR szUniqueDriverId);
    其中szUniqueDriverId是注冊(cè)時(shí),使用的ID,szReserved保留,故設(shè)置為NULL,lpDriverSettings則是驅(qū)動(dòng)程序設(shè)置信息。

例程如下:
BOOL USBUnInstallDriver()
{
 RETAILMSG(1,(TEXT("USBUninstallDriver\r\n")));
 BOOL fRet = FALSE;
 USB_DRIVER_SETTINGS DriverSettings;
 DriverSettings.dwCount = sizeof(DriverSettings);
 DriverSettings.dwVendorId = 0x10C4;
 DriverSettings.dwProductId = 0x0003;
 DriverSettings.dwReleaseNumber = USB_NO_INFO;
 
 DriverSettings.dwDeviceClass = USB_NO_INFO;
 DriverSettings.dwDeviceSubClass = USB_NO_INFO;
 DriverSettings.dwDeviceProtocol = USB_NO_INFO;
 
 DriverSettings.dwInterfaceClass = 0;
 DriverSettings.dwInterfaceSubClass = 0;
 DriverSettings.dwInterfaceProtocol = 0;
 
 fRet = UnRegisterClientSettings(L"USBTest", NULL, &DriverSettings);
 if(fRet) {
  fRet = UnRegisterClientDriverID(L"USBTest");
  if(!fRet)
   RETAILMSG(1,(TEXT("UnRegisterClientDriverID error\r\n")));
 } else
  RETAILMSG(1,(TEXT("UnRegisterClientSettings error\r\n")));
 return fRet;
}
    其中DriverSettings必須與USBInstallDriver的DriverSettings一致。
    回到原來(lái)的流程,WinCE注冊(cè)表中已經(jīng)包含了驅(qū)動(dòng)信息,WinCE系統(tǒng)自動(dòng)查找注冊(cè)表,在找到設(shè)備對(duì)應(yīng)鍵值的DLL后,將會(huì)調(diào)用該DLL的USBDeviceAttach函數(shù)。
BOOL USBDeviceAttach(
 USB_HANDLE hDevice,
 LPCUSB_FUNCS lpUsbFuncs,
 LPCUSB_INTERFACE lpInterface,
 LPCWSTR szUniqueDriverId,
 LPBOOL fAcceptControl,
 DWORD dwUnused)
    hDevice 設(shè)備句柄,操作USB設(shè)備時(shí),需要使用該句柄
    lpUsbFuncs 指向一個(gè)包含各種USB操作的函數(shù)指針
    lpInterface USB接口信息,這里需要注意的是,如果在DriverSettings里dwInterfaceClass、dwInterfaceSubClass、dwInterfaceProtocol設(shè)置為USB_NO_INFO,則該指針為NULL 
    szUniqueDriverId 注冊(cè)設(shè)備ID
    fAcceptControl 該值被賦值為TRUE,表示該驅(qū)動(dòng)能操作該設(shè)備。如果不能操作該設(shè)備,則“未能識(shí)別的USB設(shè)備”對(duì)話框會(huì)再次出現(xiàn),要求用戶輸入驅(qū)動(dòng)程序名稱
    dwUnused 未使用

    在該函數(shù)內(nèi),主要是做一些檢查,判斷是否能驅(qū)動(dòng)設(shè)備,還有就是注冊(cè)USB事件通知回調(diào)函數(shù),以及激活流驅(qū)動(dòng)。對(duì)于檢查部分,這里不再詳細(xì)說(shuō)明。

    首先,介紹一下激活流驅(qū)動(dòng)。
    流驅(qū)動(dòng)為應(yīng)用程序提供了一個(gè)訪問(wèn)設(shè)備的接口,利用該接口可以像訪問(wèn)文件一樣訪問(wèn)設(shè)備。USB設(shè)備同樣可以使用該接口來(lái)為應(yīng)用程序提供支持。在注冊(cè)表的
HKEY_LOCAL_MACHINE\Drivers\BuiltIn鍵下,保存了各種WinCE內(nèi)建流驅(qū)動(dòng)程序的入口。這些驅(qū)動(dòng)通過(guò)device.exe在系統(tǒng)啟動(dòng)時(shí)被激活。像USB這樣的設(shè)備,只有插入時(shí),才存在流
驅(qū)動(dòng)接口,所以我們需要手動(dòng)激活流驅(qū)動(dòng)。激活流驅(qū)動(dòng)的函數(shù)是:

    HANDLE ActivateDevice(LPCWSTR lpszDevKey, DWORD dwClientInfo);
lpszDevKey 字符串指明了流驅(qū)動(dòng)所在注冊(cè)表的鍵。獲悉流驅(qū)動(dòng)的人都知道,流驅(qū)動(dòng)在注冊(cè)表中必須包含兩個(gè)鍵Prefix和Dll。

    流驅(qū)動(dòng)中所有接口函數(shù)都有類似XXX_的前綴,而這個(gè)Prefix則指明XXX對(duì)應(yīng)的字符串,如Prefix為COM,則流驅(qū)動(dòng)包含如COM_Open、COM_Close、COM_Write、COM_Read這樣接口函數(shù)。Dll則說(shuō)明了這些函數(shù)所在的動(dòng)態(tài)鏈接庫(kù)。

在我的例子中存在如下的注冊(cè)表鍵:
[HKEY_LOCAL_MACHINE\Drivers\USB\ClientDrivers\USBTest]
   "Prefix"="TST"
   "Dll"="MyUSBTest.dll"
    通過(guò)dwClientInfo,可以把參數(shù)間接傳給驅(qū)動(dòng)的XXX_init。我們可以把hDevice、lpUsbFuncs、lpInterface這樣信息放置在一個(gè)結(jié)構(gòu)體中,通過(guò)該函數(shù)傳遞給流驅(qū)動(dòng)使用。
USB通知回調(diào)函數(shù),可以用來(lái)判斷各種USB事件的發(fā)生,如USB拔出。當(dāng)發(fā)生事件后,系統(tǒng)會(huì)根據(jù)注冊(cè)的回調(diào)函數(shù)做相應(yīng)的處理,在USB設(shè)備拔出后,所要做的事情,就是卸載流驅(qū)動(dòng),并釋放占用的各種資源。

    注冊(cè)回調(diào)函數(shù)是一個(gè)包含在lpUsbFuncs中的函數(shù)指針:
LPUN_REGISTER_NOTIFICATION_ROUTINE lpUnRegisterNotificationRoutine

該函數(shù)的聲明如下:
typedef BOOL (* LPREGISTER_NOTIFICATION_ROUTINE)(
  USB_HANDLE hDevice,
  LPDEVICE_NOTIFY_ROUTINE lpNotifyRoutine,
  LPVOID lpvNotifyParameter
);
hDevice 設(shè)備句柄
lpNotifyRoutine 回調(diào)函數(shù)
lpvNotifyParameter 傳遞給回調(diào)函數(shù)的參數(shù)
在回調(diào)函數(shù)中卸載流驅(qū)動(dòng)使用
BOOL DeactivateDevice(HANDLE hDevice);
其中,hDevice 傳入ActivateDevice時(shí)返回的句柄。
下面是具體的示例:
typedef struct {
 DWORD dwSize;
 USB_HANDLE hDevice,
 LPCUSB_FUNCS lpUsbFuncs,
 LPCUSB_INTERFACE lpInterface,
 HANDLE hStreamDevice;
} TESTUSBINFO, PTESTUSBINFO;
//回調(diào)函數(shù)
extern "C" BOOL USBDeviceNotifications(
 LPVOID lpvNotifyParameter,
 DWORD dwCode,
 LPDWORD *dwInfo1,
 LPDWORD *dwInfo2,
 LPDWORD *dwInfo3,
 LPDWORD *dwInfo4)
{
 if (dwCode == USB_CLOSE_DEVICE) {
  PTESTUSBINFO pDrv = (PDRVCONTEXT) lpvNotifyParameter;
  DeactivateDevice(pDrv->hStreamDevice); //卸載流驅(qū)動(dòng)
  LocalFree(pDrv); //釋放資源
 }
 RETAILMSG(1,(TEXT("Free Driver Resources!\r\n")));
 return TRUE;
}
BOOL USBDeviceAttach(
 USB_HANDLE hDevice,
 LPCUSB_FUNCS lpUsbFuncs,
 LPCUSB_INTERFACE lpInterface,
 LPCWSTR szUniqueDriverId,
 LPBOOL fAcceptControl,
 DWORD dwUnused)
{
 RETAILMSG(1,(TEXT("USBDeviceAttach\r\n")));
 *fAcceptControl = FALSE;
 //顯示USB設(shè)備的一些信息
 if(lpInterface != NULL) {
  RETAILMSG(1,(TEXT("usbserialhost: DeviceAttach, IF %u, #EP:%u, Class:%u, Sub:%u, Prot:%u\r\n"),
   lpInterface->Descriptor.bInterfaceNumber,
   lpInterface->Descriptor.bNumEndpoints,
   lpInterface->Descriptor.bInterfaceClass,
   lpInterface->Descriptor.bInterfaceSubClass,
   lpInterface->Descriptor.bInterfaceProtocol));
  RETAILMSG(1,(TEXT("Endpoint 1:%u\r\n"),
   lpInterface->lpEndpoints[0].Descriptor.bmAttributes));
  RETAILMSG(1,(TEXT("Endpoint 2:%u\r\n"),
   lpInterface->lpEndpoints[1].Descriptor.bmAttributes));
  RETAILMSG(1,(TEXT("Endpoint 3:%u\r\n"),
   lpInterface->lpEndpoints[2].Descriptor.bmAttributes));
 }
 LPCUSB_DEVICE lpUsbDev = (lpUsbFuncs->lpGetDeviceInfo)(hDevice);
 if(!lpUsbDev)
 {
  RETAILMSG(1,(TEXT("Unable to get USB device!\r\n")));
  return FALSE;
 }
 //保存必要的信息供驅(qū)動(dòng)程序其他部分使用
 PTESTUSBINFO pDrv = (PTESTUSBINFO)LocalAlloc (LPTR, sizeof (PTESTUSBINFO));
 pDrv->dwSize = sizeof (DRVCONTEXT);
 pDrv->hDevice = hDevice;
 pDrv->lpUsbFuncs = lpUsbFuncs;
 pDrv->lpInterface = lpInterface;
 //激活流驅(qū)動(dòng)
 pDrv->hStreamDevice = ActivateDevice (L"Drivers\\USB\\ClientDrivers\\USBTest", (DWORD)pDrv);
 if (pDrv->hStreamDevice) {
  //注冊(cè)回調(diào)函數(shù)
  (*lpUsbFuncs->lpRegisterNotificationRoutine)(
   hDevice,
   USBDeviceNotifications,
   pDrv);
 } else {
  RETAILMSG(1, (TEXT("Can't activate stream device! rc=%d\r\n"), GetLastError()));
  LocalFree(pDrv);
  return FALSE;
 }
 //驅(qū)動(dòng)可以操作該設(shè)備
 *fAcceptControl = TRUE;
 return TRUE;
}

    至此,USB Host端設(shè)備驅(qū)動(dòng)程序所必須實(shí)現(xiàn)的功能都已經(jīng)實(shí)現(xiàn)。并且和流驅(qū)動(dòng)相連接。應(yīng)用程序已經(jīng)可以使用流驅(qū)動(dòng)的接口來(lái)操作USB設(shè)備了。
]]>
基于WinCE6.0的LPC3250串口驅(qū)動(dòng)程序開(kāi)發(fā)http://www.rfoamep.cn/bbs/dispbbs.asp?BoardID=36&ID=1814&Page=1wangxinxin2010-11-26 10:34:15串口的Active注冊(cè)表鍵為依據(jù)查出物理中斷號(hào),并保存在 DDKISRINFO結(jié)構(gòu)體的dwlrq成員中。KernelloCon-trol函數(shù)將物理中斷號(hào)轉(zhuǎn)換為邏輯中斷號(hào),符合條件就將邏輯中斷號(hào)回寫到注冊(cè)表中。相關(guān)代碼如下:

圖片點(diǎn)擊可在新窗口打開(kāi)查看

  接著調(diào)用父類CPdd16550的Init函數(shù),創(chuàng)建中斷服務(wù)線程(IST)事件,并通過(guò)InterruptInitialize函數(shù)將事件與邏輯中斷號(hào)關(guān)聯(lián)起來(lái),最后調(diào)用CreateHardwareAccess和MapHardware函數(shù)將串口基地址及相關(guān)寄存器片內(nèi)地址映射到內(nèi)核進(jìn)程的虛擬地址。

  在MapHardware中,用GetWindowInfo根據(jù)串口的Active注冊(cè)表鍵獲得串口的全部I/O端口和內(nèi)存地址信息,然后用 MmMapIoSpace函數(shù)將串口物理地址和相關(guān)控制寄存器地址轉(zhuǎn)換成內(nèi)核進(jìn)程的虛擬地址,以便后面對(duì)寄存器進(jìn)行操作,部分代碼如下:

圖片點(diǎn)擊可在新窗口打開(kāi)查看

  CreateHardwareAccess函數(shù)根據(jù)MapHardware得到的m_pBaseAddress,構(gòu)造一個(gè)CRegLPC32xx類實(shí)例,然后調(diào)用CRegLPC32xx類的Init函數(shù)確保串口控制器硬件進(jìn)入穩(wěn)定的工作狀態(tài)。

  根據(jù)LPC3250的數(shù)據(jù)手冊(cè),設(shè)置標(biāo)準(zhǔn)UART的波特率需要設(shè)置小數(shù)波特率預(yù)分頻器和UART波特率發(fā)生器。當(dāng)不用小數(shù)波特率預(yù)分頻器(即X=Y=1) 時(shí),將標(biāo)準(zhǔn)UART的{Baudrate,DLM:DLL}的值定義一個(gè)數(shù)組BaudPairs[]。GetDivisorOfRate根據(jù)這個(gè)數(shù)組得到分頻系數(shù),然后調(diào)用父類的成員函數(shù)SetBaudRate便可設(shè)置波特率。高速UART的波特率類似,只是波特率計(jì)算公式和分頻系數(shù)與標(biāo)準(zhǔn)UART不同。

  用GetWaterMark得到接收器FIFO的觸發(fā)深度,分別為16、32、48和60位,然后在CPdd16550的InitReceive中設(shè)置FIFO控制寄存器,默認(rèn)的FIFO觸發(fā)深度是32位。

  Clpc32xxPdd16550UART是個(gè)抽象類,實(shí)現(xiàn)通用功能,具體的要分別由繼承的標(biāo)準(zhǔn)串口Clpc32xxPdd16550Stan- dardUART類和高速串口Clpc32xxPdd16550HighUART類實(shí)現(xiàn)。在各自初始化時(shí),主要是配置各種寄存器,實(shí)現(xiàn)具體硬件差異化,包括:配置UART時(shí)鐘控制寄存器、時(shí)鐘模式寄存器和時(shí)鐘選擇寄存器,分別使能UART時(shí)鐘、設(shè)置自動(dòng)時(shí)鐘模式、選擇相應(yīng)的時(shí)鐘源作為分頻器的輸入時(shí)鐘;禁止UART3 Modem和UART6 IrDA功能;禁止UART的回送功能。

  特別要強(qiáng)調(diào)的是關(guān)于中斷的處理,串口驅(qū)動(dòng)中斷可以用動(dòng)態(tài)映射,也可以用靜態(tài)映射。在OEMInter-ruptHandler、 Clpc32xxPdd16550UART::Init、CPdd16550::Init、CPdd16550::ThreadRun等處加入調(diào)試打印信息,可以較快地找到問(wèn)題所在,確定硬件中斷是否映射為系統(tǒng)中斷、系統(tǒng)中斷與中斷事件是否綁定、中斷產(chǎn)生時(shí)是否進(jìn)入相應(yīng)的處理程序。中斷處理好了,串口驅(qū)動(dòng)就基本完成了。

  上述工作結(jié)束后,就要添加串口的注冊(cè)表。以串口3為例,主要是設(shè)置動(dòng)態(tài)鏈接庫(kù)DLL、設(shè)備基地址、中斷號(hào)、前綴名、被加載的順序等。根據(jù)注冊(cè)表的 DeviceArrayIn-dex、CreateSerialObject就可以構(gòu)造標(biāo)準(zhǔn)串口或高速串口類實(shí)例了, DeleteSerialObject在退出驅(qū)動(dòng)時(shí)刪除實(shí)例。具體代碼如下:

圖片點(diǎn)擊可在新窗口打開(kāi)查看

圖片點(diǎn)擊可在新窗口打開(kāi)查看

圖片點(diǎn)擊可在新窗口打開(kāi)查看

  在廣州致遠(yuǎn)電子有限公司的SmartARM3250開(kāi)發(fā)板上,通過(guò)WinCE的串口應(yīng)用程序與上位PC機(jī)進(jìn)行發(fā)送接收實(shí)驗(yàn),本驅(qū)動(dòng)已經(jīng)實(shí)現(xiàn)標(biāo)準(zhǔn)串口最高460 800 b/s、高速串口最高921 600 b/s的穩(wěn)定傳輸。

  結(jié) 語(yǔ)

  本文介紹了WinCE6.0下的串口驅(qū)動(dòng)模型,結(jié)合LPC3250的硬件情況,詳細(xì)說(shuō)明了串口驅(qū)動(dòng)開(kāi)發(fā)過(guò)程,包括配置串口相關(guān)的寄存器和處理中斷中重要函數(shù)的實(shí)現(xiàn),以及注冊(cè)表和Source文件編寫等。本驅(qū)動(dòng)程序在廣州致遠(yuǎn)電子有限公司的SmartARM3250開(kāi)發(fā)板上實(shí)驗(yàn)成功。在串口驅(qū)動(dòng)開(kāi)發(fā)中所用的思路,對(duì)其他類似的驅(qū)動(dòng)設(shè)計(jì)有較高的參考價(jià)值。

 
]]>
主站蜘蛛池模板: 国产精品毛片在线大全 | 日韩精品一区二三区中文 | 蜜桃视频一区二区在线观看 | 一区二区三区在线免费看 | 亚洲一级成人 | 精品久久久久久国产免费了 | 欧美日韩中文国产 | 午夜性爽爽爽 | 午夜爽爽爽 | 99热这里只有免费国产精品 | 在线观看毛片视频 | 最新国产三级在线观看不卡 | 国产男女猛烈无遮挡免费视频 | 虎白女粉嫩尤物福利视频 | 毛片视频播放 | 国产在线播放精品视频 | 337p日本欧洲亚洲大胆精品 | 一级黄色片在线看 | 一道精品一区二区三区 | 成人久久18免费网 | 国产精品美女久久久久av福利 | 亚洲精品成人一区 | 久久精品国产一区二区 | 久久99久久99精品免观看女同 | 99精品影视 | 女人被做到高潮免费视频 | 亚洲欧美成人影院 | 日本高清色倩视频在线观看 | 国产美女亚洲精品久久久综合 | 欧美性群另类交 | 久久久久99人妻一区二区三区 | 久久久久久福利 | 久久国内免费视频 | 老司机免费在线观看视频 | 欧美激情欧美狂野欧美精品免费 | 国产精品国产三级区别第一集 | 黄色小网站在线观看 | 久久精品免费观看久久 | 小蜜被两老头吸奶头在线观看 | 久久婷婷国产综合精品 | 日产一区二区三区四区 |