楊再明,崔恒武,曹洪龍
(1.92001 部隊,青島266000;2.蘇州大學(xué)電子信息學(xué)院,蘇州215006)
在現(xiàn)代航空航天和航海領(lǐng)域,通常需要同時監(jiān)測多個信號并根據(jù)各個信號的狀態(tài)和時序進(jìn)行工作狀態(tài)監(jiān)測,從而為整體系統(tǒng)正常運轉(zhuǎn)提供保障。例如,采用便攜式多路開關(guān)量信號檢測儀同時對多路電磁繼電器通斷信號進(jìn)行檢測,很好的解決了多路開關(guān)量信號的并行實時檢測和計時問題[1]。在這類儀器設(shè)計中主要采用上位機+下位機的系統(tǒng)模式,其中上位機通常采用Windows 系統(tǒng)的計算機,下位機為定制的信號采集板卡,考慮通信速率和實時性要求上位機和下位機采用PCI 協(xié)議通信的方式被廣泛應(yīng)用。該系統(tǒng)的軟件開發(fā)主要分為上位機Windows 應(yīng)用程序開發(fā)、下位機嵌入式軟件開發(fā)和Windows 驅(qū)動開發(fā)三部分。對于Win?dows XP 或Windows 7 系統(tǒng),微軟公司(Microsoft)提供Windows 驅(qū)動程序開發(fā)包WDK(Windows Driver Kit)簡化了Windows 驅(qū)動程序開發(fā)過程,可用于開發(fā)支持即插即用功能的WDM(Windows Driver Mode)驅(qū)動程序,實現(xiàn)上位機Windows 應(yīng)用程序基于PCI 協(xié)議通過驅(qū)動訪問下位機的功能[2-4]。
為滿足信號采集、處理等功能的實時性要求,數(shù)字信號處理器(DSP,Digital Signal Processor)被廣泛應(yīng)用在實時數(shù)字信號處理領(lǐng)域,TI TMS320C54x DSP 憑借其低功耗、高性價比的優(yōu)點在信號采集PCI 設(shè)備領(lǐng)域廣泛應(yīng)用。圖1 是基于TMS320C54x DSP 的信號采集PCI 設(shè)備系統(tǒng)架構(gòu)框圖,主要由上位機和下位機兩部分組成,上位機和下位機PCI 協(xié)議進(jìn)行通信,實現(xiàn)信號采集、實時分析、處理、存儲和顯示等功能。其中下位機為信號采集卡,其核心處理器可以選用TMS320C54x DSP,主要完成信號采集、實時分析處理。由于TMS320C54x DSP 本身不支持PCI 協(xié)議,需要協(xié)議轉(zhuǎn)換芯片PCI2040 實現(xiàn)DSP 的HPI 接口與上位機(計算機)的PCI 接口之間相互轉(zhuǎn)換。信號采集卡采用PCI金手指方式插入上位機主板上的PCI 插槽實現(xiàn)上位機和下位機的互聯(lián)互通。
如圖1 所示,上位機運行Windows 系統(tǒng),具有可擴展性,支持新的硬件。為確保Windows 系統(tǒng)的健壯性和可靠性,Windows 系統(tǒng)從總體上分為內(nèi)核模式和用戶模式。Windows 系統(tǒng)內(nèi)核工作在內(nèi)核模式,可以訪問底層硬件(訪問物理映射內(nèi)存、設(shè)備端口等),因此要增加新硬件則必須增加Windows 內(nèi)核內(nèi)容,模塊化的驅(qū)動程序相當(dāng)于Windows 內(nèi)核的“積木”件,通過安裝驅(qū)動程序可以實現(xiàn)Windows 內(nèi)核對新硬件(例如圖1的信號采集卡)的操作訪問。用戶應(yīng)用程序(本例中為信號采集應(yīng)用程序)工作在用戶模式,無法直接訪問底層硬件(本例為PCI 型的信號采集卡),需要安裝驅(qū)動后通過驅(qū)動實現(xiàn)訪問。
圖1 基于DSP的信號采集PCI設(shè)備系統(tǒng)架構(gòu)框圖
由圖1 可見信號采集卡驅(qū)動程序在整個系統(tǒng)中起到聯(lián)通作用,實現(xiàn)了運行在Windows 系統(tǒng)下的應(yīng)用程序與信號采集卡(PCI 插卡)之間的通信,其具體的工作方案如圖2 所示。在系統(tǒng)上電后驅(qū)動受限對其進(jìn)行枚舉識別,上位機用戶應(yīng)用程序啟動后通過驅(qū)動可以查詢有效的信號采集卡并獲得訪問句柄。由于TI TMS320C54x DSP 內(nèi)部沒有可固化用戶DSP 程序的存儲器,從節(jié)約成本和低功耗方面考慮選用HPI 自舉模式由上位機在啟用信號采集卡時灌DSP 程序,因此圖2 驅(qū)動工作方案中主要分為初始化信號采集卡和數(shù)據(jù)采集2 部分。
當(dāng)上位機用戶應(yīng)用程序要采集數(shù)據(jù)時,必須先通過驅(qū)動灌DSP 程序到信號采集卡。驅(qū)動在接收到灌DSP 程序的信息后,首先通過控制DSP 復(fù)位管腳電平觸發(fā)DSP 硬件復(fù)位中斷,通過查詢DSP 復(fù)位管腳電平來確認(rèn)信號采集卡是否成功進(jìn)入HPI 自舉模式;確認(rèn)DSP 進(jìn)入HPI 自舉模式后,驅(qū)動通知上位機用戶程序可以灌DSP 程序,并在接收到DSP 程序自舉列表后按地址加載到DSP 的程序空間和數(shù)據(jù)空間;信號采集卡HPI 自舉成功后將運行加載的DSP 程序采用中斷方式通知驅(qū)動,驅(qū)動處理中斷事務(wù)通過讀取信號采集卡工作狀態(tài)確認(rèn)其初始化是否成功,記錄且同時通知上位機用戶應(yīng)用程序。
用戶應(yīng)用程序接收到驅(qū)動通知確認(rèn)信號采集卡正常工作后,可以發(fā)送采集命令通過驅(qū)動通知信號采集卡開啟采集功能。為提高信號采集、處理和顯示、存儲的實時性,用戶應(yīng)用程序?qū)⒂檬录‥vent)監(jiān)聽線程,通過WaitForSingleObject 函數(shù)或WaitForMultipleOb?jects 函數(shù)監(jiān)聽與驅(qū)動共享的Event 狀態(tài)實現(xiàn)實時處理;PCI 驅(qū)動程序在接收到采集命令后,通過中斷服務(wù)函數(shù)(ISR)實時響應(yīng)信號采集卡向驅(qū)動發(fā)送的中斷,利用內(nèi)核函數(shù)KeInitializeDpc 啟用延遲過程調(diào)用例程(DPC)搬移數(shù)據(jù)提高ISR 響應(yīng)的實時性;信號采集卡連續(xù)采集信號,且每完成一幀信號采集、分析、處理將發(fā)送中斷通知驅(qū)動搬移數(shù)據(jù)。當(dāng)驅(qū)動接收到停止采集命令后,通知信號采集卡停止數(shù)據(jù)采集進(jìn)入低功耗狀態(tài)。
圖2 PCI驅(qū)動程序工作方案
PCI 設(shè)備一般選用WDM(Windows Driver Mode)驅(qū)動程序類型支持即插即用,其入口函數(shù)為DriverEntry函數(shù)。Windows 內(nèi)核中的I/O 管理器調(diào)用DriverEntry函數(shù)并通過形參pDO 傳入驅(qū)動對象,形參RegistryPath為驅(qū)動在注冊表中的鍵值[5],具體示例代碼如下。代碼中用Extern"C"修飾DriverEntry 函數(shù)是為了指示編譯器該函數(shù)按C 語言的方式進(jìn)行編譯。
●AddDevice 回調(diào)函數(shù),本例設(shè)置Pci2040AddDe?vice 為回調(diào)函數(shù),主要負(fù)責(zé)創(chuàng)建設(shè)備對象、初始化設(shè)備擴展數(shù)據(jù)結(jié)構(gòu)、創(chuàng)建符號鏈接和初始化DPC 處理函數(shù),等等。
●DriverUnload 回調(diào)函數(shù),本例設(shè)置Pci2040Un?load 為回調(diào)函數(shù),即注冊卸載例程,但在WDM 中卸載處理工作一般放在PNP 相關(guān)的回調(diào)函數(shù)中處理。
●IRP(I/O Request Packet)派遣函數(shù),Windows 系統(tǒng)中I/O 管理器是用戶模式和內(nèi)核模式之間通信的橋梁,即工作在用戶模式的應(yīng)用程序發(fā)出I/O 請求時,由I/O 管理器捕獲并轉(zhuǎn)化為IRP 請求發(fā)送給驅(qū)動,驅(qū)動即調(diào)用對應(yīng)的派遣函數(shù)進(jìn)行處理。表1 中列出了一些主要IRP 派遣函數(shù)。
表1 WDM 驅(qū)動主要的IRP 回調(diào)函數(shù)
開發(fā)基于WDM 的PCI 驅(qū)動程序主要是在WDM框架上實現(xiàn)IRP 派遣函數(shù),實現(xiàn)應(yīng)用程序、驅(qū)動和采集卡之間的相互通信。其中,應(yīng)用程序可以通過Creat?File、ReadFile、WriteFile、DeviceIoCtrol 等函數(shù)與驅(qū)動程序進(jìn)行交互,其對應(yīng)的IRP 類型見表1。實現(xiàn)PCI 設(shè)備驅(qū)動程序的難點是驅(qū)動程序與采集卡之間的交互,重點是資源訪問操作和中斷處理,這需要在了解板卡硬件原理圖的基礎(chǔ)上實現(xiàn)。
以圖1 為例,驅(qū)動對設(shè)備的訪問相當(dāng)于借助PCI2040 芯片轉(zhuǎn)換進(jìn)行HPI 訪問,訪問HPI 映射的物理存儲空間需要調(diào)用內(nèi)核函數(shù)READE_REGIS?TER_ULONG 和WRITE_REGISTER_ULONG 該系列函數(shù),主要通過控制C54x DSP 的管腳狀態(tài)實現(xiàn)表2 所示4 種模式的HPI 寄存器訪問操作,進(jìn)而封裝成對HPI映射的物理存儲空間的4 種訪問方法[6]。
●DspMemReadNoInc 驅(qū)動函數(shù),功能是讀取指定C54x DSP 的RAM 地址的1 個16 位數(shù)據(jù),具體操作方法是采用表2 中模式2 先向HPIA 寄存器寫入地址,然后采用表2 中的模式3 讀取HPID 的數(shù)據(jù)。
●DspMemWriteNoInc 驅(qū)動函數(shù),功能是向C54x DSP 的RAM 地址寫入1 個數(shù)據(jù),具體操作方法是采用表2 中模式2 先向HPIA 寄存器寫入地址,然后采用表2 中的模式3 向HPID 寫入數(shù)據(jù)。
●DspMemReadInc 驅(qū)動函數(shù),功能是讀取指定C54x DSP 的RAM 地址的連續(xù)N(N≥1)個16 位數(shù)據(jù),具體操作方法是采用表2 中模式1 先向HPIA 寄存器寫入地址,然后采用表2 中的模式1 連續(xù)執(zhí)行N 次HPID 讀操作,可以讀取從HPIA 中的地址開始的連續(xù)N 個16 位數(shù)據(jù)。
●DspMemWriteInc 驅(qū)動函數(shù),功能是向C54x DSP的RAM 地址連續(xù)寫入N(N≥1)個16 位數(shù)據(jù),具體操作方法是采用表2 中模式1 先向HPIA 寄存器寫入初始地址(目標(biāo)地址-1),然后采用表2 中的模式1 連續(xù)執(zhí)行N 次HPID 寫操作,實現(xiàn)以目標(biāo)地址為起始地址連續(xù)寫入N 個16 位數(shù)據(jù)。
表2 C54x DSP HPI 訪問方式
此外,可以通過調(diào)用內(nèi)核函數(shù)WRITE_REGIS?TER_ULONG 該系列函數(shù)運用表2 中的工作模式0 向HPIC 寄存器寫入數(shù)據(jù),實現(xiàn)驅(qū)動觸發(fā)DSP 的主機中斷、配置HPI 通信方式等功能。
采集卡亦可以發(fā)送中斷信號,WDM 驅(qū)動程序采用如下步驟處理中斷事件:
(1)在IRP_MJ_PNP 的派遣函數(shù)Pci2040Pnp 中處理次級的IRP_MN_START_DEVICE 類型時,調(diào)用內(nèi)核函數(shù)IoConnectInterrupt 將中斷注冊到系統(tǒng),并指定中斷服務(wù)函數(shù)(例如OnInterrupt)。
(2)自定義中斷服務(wù)函數(shù)(例如OnInterrupt)實時處理中斷,主要方法是讀取中斷標(biāo)志,清除中斷標(biāo)志位,根據(jù)讀取到的中斷標(biāo)志進(jìn)行相應(yīng)的處理。
(3)由于中斷服務(wù)程序運行在高的設(shè)備中斷請求級(DIRQL),執(zhí)行時間不易過長,因此通常代碼量盡量少,必要情況將不重要的代碼放置DPC 函數(shù)中執(zhí)行。DPC 函數(shù)運行在在相對較低的DISPATCH_LEVEL 級別,調(diào)用方法是在中斷服務(wù)函數(shù)中利用內(nèi)核函數(shù)IoRe?questDpc 調(diào)用在AddDevice 回調(diào)函數(shù)中初始化的DPC函數(shù)處理。
微軟提供Windows 驅(qū)動開發(fā)套件(WDK,Windows Driver Kit),包括了WDM 驅(qū)動開發(fā)工具、例程和幫助文檔,可用于用戶開發(fā)Windows 驅(qū)動程序,其官方提供的最新版本為7.1,安裝后可以編譯鏈接C 源程序生成驅(qū)動。利用WDK 生成驅(qū)動程序的步驟如下:
(1)編寫MAKEFILE 文件(無擴展名),內(nèi)容固定不變,詳細(xì)內(nèi)容見WDK 例程。
(2)編寫Sources 文件(無擴展名),定義驅(qū)動名稱、類型和源程序文件,例如:
注意:MAKEFILE、Sources 和源程序文件在同一文件夾下。
(1)在開始菜單的“所有程序”中選擇WDK 下的“Build Environments”,選擇操作系統(tǒng)版本(例如Win?dows XP)下X86 Checked Build Environment 快捷方式進(jìn)入命令行形式的工具窗口。
(2)利用CD 命令進(jìn)入Sources 等文件所在目錄(英文路徑),然后執(zhí)行build 命令,若無誤將生成驅(qū)動程序pci2040Examples.sys。
采用VC++開發(fā)測試程序如圖3 所示,基于DSP的信號采集PCI 設(shè)備實現(xiàn)了對多路開關(guān)量信號的采集和狀態(tài)變化判斷。設(shè)計的驅(qū)動使Windows 系統(tǒng)可以識別該設(shè)備,并為測試程序提供了對該設(shè)備的讀、寫和中斷響應(yīng)等接口。設(shè)計圖3 所示測試程序時,主要采用以下方法:
圖3 基于DSP的信號采集PCI設(shè)備測試程序界面
●利用Windows API 函數(shù)SetupDiGetClassDevs 對該PCI 設(shè)備進(jìn)行枚舉。
●利用Windows API 函數(shù)DeviceIoControl 發(fā)起IRP 與驅(qū)動交互。
●利用Windows API 函數(shù)ReadFile 和WriteHan?dle 函數(shù)與驅(qū)動交互。
●開啟獨立線程采用Windows API 函數(shù)WaitForS?ingleObject 或WaitForMultipleObjects 接收驅(qū)動發(fā)送的事件中斷,提高上位機的響應(yīng)實時性。
本文給出了基于WDM 的Windows 驅(qū)動程序設(shè)計方法,以基于DSP 的信號采集PCI 設(shè)備為例主要介紹了WDM 驅(qū)動程序設(shè)計框架、PCI 驅(qū)動程序設(shè)計過程和基于WDK 的驅(qū)動程序生成方法,并給出了進(jìn)行開關(guān)量信號采集的PCI 設(shè)備測試程序?qū)嵗?,為開發(fā)基于WDM的PCI 驅(qū)動程序提供了參考。