|
1、 WINCE 下的SD卡驅動架構
Wince 下SD卡驅動協議棧組成 : HOST硬體底層部分 (主控制端驅動) SDHC_XXX.DLL BUS 中間邏輯命令層 (匯流排驅動) SDBUS.DLL CLIENT上層(用戶端驅動) SDMEMORY.DLL
主控制端驅動 主控制端驅動控制包含主控制器硬體,遵循主控制端驅動介面,它被用於匯流排驅動通訊和設定作業參數。主控制器驅動介面提供一個硬體提取層,在匯流排和主控制端執行之間。即:SDHC_XXX.DLL是最底層,因為這層是硬體關聯層,因此取名XXX便是為了對應的具體的硬體BSP包(如本項目的硬體平台是ZYLONITE,其硬體供應商給的BSP包名即為ZYLONITE,在實際項目中我們便將SDHC_XXX.DLL取代為SDHC_ZYLONITE.DLL),它負責具體的發命令,大多數情況下都需要修改。
匯流排驅動 匯流排驅動作為提取和管理層處於主控制驅動和用戶端驅動之間。它包括在SDbus.dll檔案。為用戶端驅動提供了標準的API,允許運行在任何的基於windows ce裝置。匯流排驅動將是獨立於應用程式和主控制端驅動,在不同的處理器之間移植,並不需要改動。SDBus.dll是中介層,負責整合命令和管理。
用戶端驅動 用戶端驅動和SD用戶端驅動通訊介面允許用戶端驅動去和SD裝置通訊。用戶端驅動介面是有計劃地抽象SD匯流排物理裝置的執行,提供了用戶端驅動最大的彈性。用戶端驅動介面允許用戶端驅動去衡量一個單一的,同步的訪問儲存卡驅動使用一個線程,非同步通訊裝置驅動。SDMemory.dll是最高層,類似於應用程式層。
2.立足微軟SD卡協議棧開發Zylonite 的BSP包的SD卡驅動
當我們開發SD卡驅動時,並詳細分析比較了Microsoft的SD驅動架構和Intel所提供的BSP內的參考SD卡驅動以後,可以得出如下結論:
針對主控制端驅動(SDHC_XXX.DLL):因為這一層是直接操作硬體的一層,所以大多數情況下都需要修改。修改的內容基本為收發命令部分以及資料轉送和硬體初始化部分.
針對匯流排驅動(SDBUS.DLL):因為這一層處於主控制驅動和用戶端驅動之間,用於他們之間的通訊,SD卡匯流排請求都放在它裡面,微軟提供了非常完備的範例代碼,所以我們一般都不需要改動,直接調用它的介面就可以了。
針對用戶端驅動( SDMEMORY.DLL):因為SDMemory就是所謂的Client層,類似於應用程式層,它還可用來識別卡的,不同種類的卡,比如sd memory card等,鑒於我們只需開發SD卡部分的驅動,所以也不需要怎麼修改了(如果我要開發SD介面的SDIO裝置,那麼就得在這層做比較大的改動了)。
Intel所提供的BSP內的參考SD卡驅動自己實現了主控制端驅動(SDHC_ZYLONITE.DLL),而調用並保留了匯流排驅動(SDBUS.DLL)和用戶端驅動( SDMEMORY.DLL)。因此結合具體的硬體設計(SD卡的CONNECTOR等),我們的主要任務便是利用BSP內的SD卡主控制端驅動代碼,開發(配置並改進)我們實際項目內的SD卡驅動。
Zylonite BSP內的SD卡主控制端驅動概述
SD卡的驅動程式是以流的形式提供的,而該SD卡主控制端驅動以sdhc_zylonite.dll 的形式提供,入口在: /WINCE500/PLATFORM/Zylonite/public/csp/monahans/sdhc
有如下兩個檔案:
sdcontrol.c:內含一個非常重要的線程---SDControllerISTHandler, 主要負責卡與控制器的互動,處理控制器接收的訊息等,具體的控制和處理函數均在此檔案中。
main.c: SDH(主控制端驅動)的匯出流介面在該檔案中實現,並包含有主控制端驅動的(sdhc_zylonite.dll)的進入點。
SD卡硬體初始化及其主控制端驅動的註冊表資訊設定路徑為: /WINCE500/PLATFORM/Zylonite/Platform/ZYLONITE/SRC/DRIVERS/SDHC
主要檔案為:
impl.c: 主要是在載入SD卡主控制端驅動時初始化硬體。內含一個非
常重要的線程---- SDCardDetectIstThread,專門處理SD卡的插拔操作。但是具體的插拔操作也是在Sdcontrol.c檔案實現的。
SD卡的外部引腳及功能配置
在實際項目(一款以WINCE為作業系統核心的GSM/PHS雙模智能手機)中,SD卡的外部引腳與Monahans_L的GPIO串連圖及連接導向器的電路圖如下所示:
先要配置SD卡的外部引腳及功能。而SD卡的引腳配置在其下的 /source 檔案夾的xllp_mmc_board.c檔案XllpMMCConfigure函數內修改。(特別注意:GPIO34要配成檢測SD卡插入的中斷源。)
分析修改並改進主控制端驅動重要線程及硬體初始化部分代碼
SD卡主控制端驅動載入及架構解析
需要聲明的是SD卡驅動載入順序是:
載入SDBus.dll→載入sdhc_zylonite.dll→載入sdmemory.dll
我們在這裡只詳細討論第2步(sdhc_zylonite.dll的載入),此時SDBus.dll已經載入成功。WINCE系統初始化後,會載入DEVICE.EXE, 對應代碼devload.C中的WINMAIN函數會被調用起來,從而啟動InitDevice函數,此函數會搜尋(/WINCE500/PLATFORM/Zylonite/Platform/ZYLONITE/SRC/DRIVERS/SDHC下的sdhc_zylonite.reg)註冊表根鍵,準備參數調用WIN32 API介面-----Activedevice,接著利用Dllmaincrtstartup函數找到sdhc_zylonite.dll的入口,執行該檔案的入口函數DllMain()然後繼續返回到DEVICE.EXE(devload.C),調用launchdevice()函數,再調用sdhc_zylonite.dll的入口main.c檔案內的SDH_Init(),自此將開始將開始SD卡主控制端驅動的初始化過程: 1. 調用SDH_Init() 2. 調用 SDHCDAllocateContext() 來分配一段主控制器的上下文 a)Context 是匯流排驅動和主控制端驅動共用的 3. 主控制端驅動使用SDHCDSetXxx宏來填充這個上下文結構 a)這個步驟是把主控制器向匯流排驅動描述一下 b)包括函數指標,支援的電流,最大時鐘,槽數目,SDIO的支援等等。 4. 調用 SDHCDRegisterHostController() 來把自己向匯流排驅動註冊一下 5. 當匯流排驅動準備處理SD事件時,它會調用主控制端驅動的init 函數(pContext->pInitHandler)
接著便是sdbus.dll驅動部分的代碼和SD卡主控制端驅動部分的互動設定:比如設定電源、時鐘和匯流排寬度等。一般都是sdbus.dll發起請求,再去調用主控制端驅動部分的API,這裡最後詳細分析插槽狀態互動確認,因為這是成功載入sdhc_zylonite.dll的關鍵。當有SD卡在插槽,sdbus.dll的slotstatuschange()調用並建立一個重要線程SDcardDetectIstThread(),當探測到有卡,即返回給sdbus.dll, 匯流排驅動即可調用HandleAddDevice()函數,自此初始化結束,sdhc_zylonite.dll載入成功。
對主控制端驅動重要線程SDcardDetectIstThread()代碼的改進
在前面的敘述中,可以看出線程SDcardDetectIstThread()在sdhc_zylonite.dll最後的載入起決定性作用。然而我們發現在INTEL所給的BSP中,在檢測卡的過程裡,其採用了輪詢的方式----即每隔一定的時間,CPU都會去讀一次GPIO34的電平,以確定SD卡是否被插入或拔出,以此來判定是否去載入或卸載SD卡的用戶端和主控制端驅動。很顯然,這種方式的弊端是佔用了過多的CPU資源,效率很低,嚴重影響了整個系統的即時性。因此,最能解決這個問題的辦法無外乎是使用中斷檢測的方式。中斷綁定靜態配置:
1.在Bsp_cfg.h檔案內定義一個系統中斷號SYSINTR_SDMMC_DETECT
#define SYSINTR_SDMMC_DETECT (SYSINTR_FIRMWARE+N) N為當前已定義的最大值(以保證此中斷未使用過)。
2.在Xllp_gpio_plat.h檔案中找出GPIO34的定義:#define XLLP_GPIO_MMC_CD_0 34
3.在intr.c檔案裡將系統中斷號和IRQ關聯:
OALIntrStaticTranslate(SYSINTR_SDMMC_DETECT, IRQ_GPIO_SHARE(XLLP_GPIO_MMC_CD_0));
4.在主控制端驅動的硬體初始化代碼Impl.c中的InitializeHardware()加入 EnablesdcardInterrupt()函數。
5.在Impl.c中完善EnablesdcardInterrupt(),加入GPIO上升沿或下降沿的檢測和SET EVENT。
6.在Impl.c檔案中定義hCardInsertInterruptEvent並在SetupCardDetectIST()內建立hCardInsertInterruptEvent
7.Impl.c檔案中初始化dwSysintrCD= SYSINTR_SDMMC_DETECT,並綁定相應的EVENT:InterruptInitialize (dwSysintrCD,hCardInsertInterruptEvent,NULL,0)
8. 改進線程SDcardDetectIstThread()的While部分代碼,加入WaitForSingleObject( hCardInsertInterruptEvent, dwTimeout );只有當hCardInsertInterruptEvent被置上,才會往下走,否則一直在此處等待。
9.同上原理改寫CardremoveInterrupt用於動態卸載SD卡主控制端驅動。 |