潘俊虹,彭 濤,蔡闖華1,
(1.武夷學(xué)院數(shù)學(xué)與計(jì)算機(jī)學(xué)院,福建 武夷山 354300;2.蘇州大學(xué)計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院,江蘇 蘇州 215006;3.認(rèn)知計(jì)算與智能信息處理福建省高校重點(diǎn)實(shí)驗(yàn)室,福建 武夷山 354300)
MQX(Message Queue eXecutive,消息隊(duì)列執(zhí)行)是由恩智浦公司推出的一款免費(fèi)、開(kāi)源且提供持續(xù)技術(shù)支持的嵌入式實(shí)時(shí)操作系統(tǒng)(Embedded Real Time Operation System,RTOS)[1].MQX以其豐富的外設(shè)驅(qū)動(dòng)、精簡(jiǎn)的內(nèi)核、清晰的架構(gòu)和較強(qiáng)的實(shí)時(shí)性等優(yōu)點(diǎn),在工業(yè)自動(dòng)化、智能家居等領(lǐng)域廣泛應(yīng)用.MQX版本在不斷更新,目前的最新版本是于2015年7月推出的MQX 4.2.0.鑒于MQX在嵌入式開(kāi)發(fā)領(lǐng)域廣闊的市場(chǎng)前景[2-4],分析研究MQX底層設(shè)備驅(qū)動(dòng)設(shè)計(jì)的原理和方法對(duì)促進(jìn)其發(fā)展具有一定的意義.
在嵌入式軟件系統(tǒng)中,底層設(shè)備驅(qū)動(dòng)直接面向底層硬件,實(shí)現(xiàn)對(duì)底層硬件的訪問(wèn)控制,是操作系統(tǒng)的重要組成部分[5].MQX采用統(tǒng)一的模型來(lái)管理設(shè)備驅(qū)動(dòng),用戶在應(yīng)用程序中可以通過(guò)一組標(biāo)準(zhǔn)的接口函數(shù)對(duì)設(shè)備進(jìn)行訪問(wèn).MQX根據(jù)管理設(shè)備方式的不同,將設(shè)備驅(qū)動(dòng)分為內(nèi)核安裝管理的輸入輸出(Input/Output,I/O)子系統(tǒng)層設(shè)備驅(qū)動(dòng)和非內(nèi)核安裝管理的驅(qū)動(dòng)2大類.對(duì)于非內(nèi)核安裝類驅(qū)動(dòng),用戶直接調(diào)用MQX提供的應(yīng)用程序編程接口(Application Programming Interface,API)函數(shù)或者靜態(tài)庫(kù)即可[6].筆者主要針對(duì)內(nèi)核安裝的I/O子系統(tǒng)層設(shè)備驅(qū)動(dòng)管理和設(shè)計(jì)方法進(jìn)行闡述,通過(guò)分析MQX底層設(shè)備驅(qū)動(dòng)管理和設(shè)計(jì)模式,給出了底層驅(qū)動(dòng)開(kāi)發(fā)的基本方法,并在此基礎(chǔ)上對(duì)底層驅(qū)動(dòng)設(shè)計(jì)方式進(jìn)行改進(jìn).
圖1 MQX I/O設(shè)備驅(qū)動(dòng)層次結(jié)構(gòu)Fig.1 Hierarchical Structure of MQX I/O Device Drivers
MQX標(biāo)準(zhǔn)I/O設(shè)備驅(qū)動(dòng)可分為格式化ANSI(American National Standards Institute,美國(guó)國(guó)家標(biāo)準(zhǔn)協(xié)會(huì))I/O層、MQX I/O子系統(tǒng)層和底層設(shè)備驅(qū)動(dòng)層[7],具體結(jié)構(gòu)如圖1所示.
格式化ANSI I/O層由應(yīng)用程序調(diào)用,是MQX為應(yīng)用程序提供的一組格式化ANSI文件接口.在源文件“MQXincludeio.h”中可以看出,MQX通過(guò)宏定義映射到I/O子系統(tǒng)層對(duì)應(yīng)的接口函數(shù)上(表1).
表1 MQX設(shè)備驅(qū)動(dòng)函數(shù)映射關(guān)系Table 1 Mapping Relationship Between MQX Device Driver Functions
MQX I/O子系統(tǒng)層遵循可移植操作系統(tǒng)接口(Portable Operating System Interface of UNIX,POSIX)標(biāo)準(zhǔn)[8],由格式化ANSI I/O層調(diào)用,是格式化ANSI I/O層與底層設(shè)備驅(qū)動(dòng)的紐帶,它提供了專門(mén)的API函數(shù)將標(biāo)準(zhǔn)I/O函數(shù)與設(shè)備的私有信息及底層設(shè)備驅(qū)動(dòng)進(jìn)行關(guān)聯(lián).這些API函數(shù)中,最關(guān)鍵的是驅(qū)動(dòng)注冊(cè)安裝函數(shù)io_dev_install.該函數(shù)主要功能是將包含有I/O設(shè)備的標(biāo)識(shí)符、驅(qū)動(dòng)函數(shù)名及其數(shù)據(jù)結(jié)構(gòu)的結(jié)構(gòu)體安裝到操作系統(tǒng)的設(shè)備管理隊(duì)列中.實(shí)際打開(kāi)設(shè)備時(shí),I/O子系統(tǒng)以設(shè)備標(biāo)識(shí)符作為索引檢索設(shè)備管理隊(duì)列,建立設(shè)備文件到設(shè)備結(jié)點(diǎn)的關(guān)聯(lián),并返回文件指針,通過(guò)文件指針句柄調(diào)用關(guān)聯(lián)的設(shè)備驅(qū)動(dòng)函數(shù)來(lái)執(zhí)行操作.通過(guò)這種方式,底層設(shè)備在MQX中被抽象成文件,借助文件名間接調(diào)動(dòng)底層設(shè)備驅(qū)動(dòng),以實(shí)現(xiàn)打開(kāi)設(shè)備和打開(kāi)文件的方式統(tǒng)一.
底層設(shè)備驅(qū)動(dòng)層是根據(jù)各種具體設(shè)備開(kāi)發(fā)的驅(qū)動(dòng)程序.MQX為不同型號(hào)的嵌入式MCU提供了大量的板級(jí)支持包(Board Support Package,BSP)級(jí)底層驅(qū)動(dòng)程序,用戶也可以根據(jù)需要改寫(xiě)或自己編寫(xiě)設(shè)備驅(qū)動(dòng)程序.當(dāng)用戶在應(yīng)用工程中需要訪問(wèn)這些底層設(shè)備時(shí),只需將所需的底層驅(qū)動(dòng)程序添加到用戶工程,并將驅(qū)動(dòng)程序注冊(cè)到I/O子系統(tǒng)設(shè)備管理隊(duì)列中,就可以在用戶任務(wù)中直接調(diào)用fopen,fclose,fread和fwrite等標(biāo)準(zhǔn)函數(shù)對(duì)底層設(shè)備進(jìn)行訪問(wèn)和控制.
圖2 I/O驅(qū)動(dòng)管理隊(duì)列設(shè)備結(jié)點(diǎn)結(jié)構(gòu)Fig.2 Node Structure of I/O Driver Management Queue Device
MQX通過(guò)鏈隊(duì)列的形式來(lái)實(shí)現(xiàn)I/O設(shè)備驅(qū)動(dòng)的組織和管理.MQX系統(tǒng)在內(nèi)核初始化時(shí)創(chuàng)建設(shè)備驅(qū)動(dòng)鏈隊(duì)列的頭結(jié)點(diǎn),如圖2所示,隊(duì)列中每一個(gè)結(jié)點(diǎn)都是IO_DEVICE_STRUCT結(jié)構(gòu)體類型,包括設(shè)備標(biāo)識(shí)符、驅(qū)動(dòng)接口指針和驅(qū)動(dòng)設(shè)備信息指針等.用戶在使用驅(qū)動(dòng)前需將驅(qū)動(dòng)注冊(cè)到I/O子系統(tǒng)層的設(shè)備管理隊(duì)列中,注冊(cè)安裝過(guò)程實(shí)際上就是將各設(shè)備的驅(qū)動(dòng)結(jié)點(diǎn)插入到驅(qū)動(dòng)管理隊(duì)列當(dāng)中,并通過(guò)指針連接成完整的驅(qū)動(dòng)鏈表隊(duì)列.設(shè)備驅(qū)動(dòng)必須注冊(cè)到I/O設(shè)備驅(qū)動(dòng)管理隊(duì)列才能為標(biāo)準(zhǔn)I/O層的格式化標(biāo)準(zhǔn)函數(shù)提供服務(wù).設(shè)備驅(qū)動(dòng)結(jié)點(diǎn)由_io_dev_install函數(shù)安裝設(shè)備驅(qū)動(dòng)時(shí)動(dòng)態(tài)創(chuàng)建,并由I/O子系統(tǒng)維護(hù).新添加的設(shè)備驅(qū)動(dòng)被插入到鏈隊(duì)列的尾部.由于每個(gè)I/O設(shè)備傳入安裝函數(shù)的初始化信息參數(shù)不同,在調(diào)用安裝函數(shù)之前每個(gè)I/O設(shè)備都要定義自己的安裝函數(shù)_io_dev_install.在打開(kāi)設(shè)備時(shí),先由fopen函數(shù)創(chuàng)建一個(gè)設(shè)備文件描述符,并由該描述符的DEV_PTR指針(文件句柄)建立與設(shè)備驅(qū)動(dòng)結(jié)點(diǎn)的關(guān)聯(lián),通過(guò)該句柄在設(shè)備隊(duì)列中快速定位設(shè)備結(jié)點(diǎn),然后調(diào)用標(biāo)準(zhǔn)I/O函數(shù)如同訪問(wèn)文件一樣對(duì)設(shè)備進(jìn)行訪問(wèn).
MQX底層設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)開(kāi)發(fā)相對(duì)獨(dú)立于上層I/O子系統(tǒng)層[9].只要明確上層函數(shù)傳遞來(lái)的參數(shù)格式,在底層驅(qū)動(dòng)中將其分解出來(lái)供底層設(shè)備驅(qū)動(dòng)程序使用,其他設(shè)計(jì)原則和方法與無(wú)操作系統(tǒng)下的驅(qū)動(dòng)開(kāi)發(fā)一致.因此,設(shè)備驅(qū)動(dòng)設(shè)計(jì)的關(guān)鍵就是函數(shù)參數(shù)的組織、傳遞和分解.
(1)底層設(shè)備驅(qū)動(dòng)參數(shù)的組織封裝.MQX操作系統(tǒng)底層設(shè)備驅(qū)動(dòng)函數(shù)的參數(shù)傳遞過(guò)程,一般是先將參數(shù)信息封裝在數(shù)據(jù)結(jié)構(gòu)體中,再將數(shù)據(jù)結(jié)構(gòu)體指針傳遞給底層設(shè)備驅(qū)動(dòng)程序.底層設(shè)備驅(qū)動(dòng)程序通過(guò)結(jié)構(gòu)體指針從數(shù)據(jù)結(jié)構(gòu)中分解出所需的參數(shù),參數(shù)的這種封裝有利于簡(jiǎn)化參數(shù)的傳遞且更加方便快捷.MQX將底層設(shè)備驅(qū)動(dòng)初始化參數(shù)分為2個(gè)部分:一部分與MCU型號(hào)和開(kāi)發(fā)板密切相關(guān),基本不再改變;另一部分由標(biāo)準(zhǔn)函數(shù)fopen在打開(kāi)設(shè)備時(shí)傳入,可根據(jù)用戶工程需要進(jìn)行動(dòng)態(tài)調(diào)整和改變.
(2)底層設(shè)備驅(qū)動(dòng)初始化參數(shù)分解.底層設(shè)備驅(qū)動(dòng)的初始化參數(shù)在執(zhí)行fopen函數(shù)(已映射到_io_fopen函數(shù))時(shí)傳入,其格式如下:
驅(qū)動(dòng)在注冊(cè)時(shí),IO_OPEN代表device_open函數(shù)指針,因此上面代碼相當(dāng)于調(diào)用device_open函數(shù),其中參數(shù)file_ptr為文件句柄,是指向的結(jié)構(gòu)體中保存了設(shè)備驅(qū)動(dòng)結(jié)點(diǎn)的指針.設(shè)備驅(qū)動(dòng)結(jié)點(diǎn)的DRIVER_INT_PTR指針指向封裝了設(shè)備與BSP相關(guān)的信息,其他指針則指向設(shè)備標(biāo)識(shí)符和相應(yīng)的驅(qū)動(dòng)函數(shù).由此可見(jiàn),只要明確傳入底層驅(qū)動(dòng)函數(shù)的指針含義,并熟悉參數(shù)結(jié)構(gòu)體各成員的作用,即可解析出底層驅(qū)動(dòng)模塊所需的初始化參數(shù).
MQX將底層設(shè)備驅(qū)動(dòng)統(tǒng)一在三層體系結(jié)構(gòu)模型中,雖然設(shè)備驅(qū)動(dòng)的實(shí)現(xiàn)內(nèi)容各有不同,但是在MQX統(tǒng)一模型中設(shè)備驅(qū)動(dòng)計(jì)方法是一致的[10].主要步驟如下:按照嵌入式底層軟件構(gòu)件的設(shè)計(jì)思想,將底層驅(qū)動(dòng)封裝成device.h和device.c軟件構(gòu)件(device表示具體的設(shè)備模塊名);在device.h頭函數(shù)中封裝定義與板級(jí)相關(guān)的驅(qū)動(dòng)模塊參數(shù),定義初始化參數(shù)值;給出用戶可以動(dòng)態(tài)修改的初始化參數(shù)結(jié)構(gòu)體結(jié)構(gòu),以便于調(diào)用fopen函數(shù)時(shí)依據(jù)工程的需要?jiǎng)討B(tài)修改底層模塊的性能;在device.c中編寫(xiě)設(shè)備驅(qū)動(dòng)的各個(gè)功能函數(shù),在初始化設(shè)備功能函數(shù)(一般為device_open)中解析傳入的初始化參數(shù)結(jié)構(gòu)體,獲取初始化參數(shù);編寫(xiě)注冊(cè)安裝設(shè)備驅(qū)動(dòng)函數(shù),主要調(diào)用MQX提供的系統(tǒng)函數(shù)_io_dev_install注冊(cè)設(shè)備驅(qū)動(dòng)到管理隊(duì)列中,但也可以對(duì)初始化參數(shù)進(jìn)一步封裝.
下面通過(guò)一個(gè)串行通信接口(Serial Communication Interface,SCI)設(shè)備驅(qū)動(dòng)實(shí)例來(lái)介紹設(shè)備驅(qū)動(dòng)設(shè)計(jì)過(guò)程.主要步驟如下:
(ⅰ)SCI設(shè)備屬性信息封裝.設(shè)備屬性信息是在操作系統(tǒng)中配置設(shè)備驅(qū)動(dòng)、調(diào)用驅(qū)動(dòng)函數(shù)必須的參數(shù),這些參數(shù)在MQX設(shè)備驅(qū)動(dòng)三層模型中的不同層之間傳遞,對(duì)于調(diào)用的上層應(yīng)用程序是透明的.SCI設(shè)備屬性通常包含設(shè)備號(hào)、模塊時(shí)鐘和通信波特率等,可用SCI_INIT_STRUCT屬性信息結(jié)構(gòu)體進(jìn)行封裝,結(jié)構(gòu)體類型定義放在sci.h文件中.在加載設(shè)備時(shí),MQX將該結(jié)構(gòu)體加載到設(shè)備驅(qū)動(dòng)鏈隊(duì)列的對(duì)應(yīng)SCI設(shè)備結(jié)點(diǎn)中,并由 DRIVER_INIT_PTR類型指針來(lái)指向,實(shí)際使用時(shí)可通過(guò)該指針提取SCI設(shè)備屬性信息.描述SCI設(shè)備屬性的結(jié)構(gòu)體代碼如下:
∥SCI_INIT_STRUCT 結(jié)構(gòu)體
typedef struct _sci_init_struct{
uint_8 SCI_ID;∥SCI設(shè)備號(hào)
uint_32 BUS_CLK;∥模塊工作時(shí)鐘
uint_32 BAUD_RATE;∥通信波特率
} SCI_INIT_STRUCT,*SCI_INIT_PTR;
(ⅱ)編寫(xiě)SCI驅(qū)動(dòng)函數(shù).SCI驅(qū)動(dòng)函數(shù)利用設(shè)備標(biāo)識(shí)符可快速定位到設(shè)備驅(qū)動(dòng)隊(duì)列中的SCI結(jié)點(diǎn),并通過(guò)該節(jié)點(diǎn)中的設(shè)備驅(qū)動(dòng)初始化句柄DRIVER_INIT_PTR解析出設(shè)備屬性信息,由傳入的設(shè)備參數(shù)對(duì)串口模塊進(jìn)行訪問(wèn)以實(shí)現(xiàn)具體的各個(gè)功能.驅(qū)動(dòng)函數(shù)聲明放在sci.h文件中,驅(qū)動(dòng)函數(shù)的實(shí)現(xiàn)放在對(duì)應(yīng)的sci.c文件中.SCI串口驅(qū)動(dòng)包含串口打開(kāi)、關(guān)閉、發(fā)送和接收數(shù)據(jù)等功能,部分串口驅(qū)動(dòng)函數(shù)代碼如下:
∥串口打開(kāi)函數(shù)
_mqx_int _io_sci_open(MQX_FILE_PTRfile_dev_ptr,char_ptr sci_name,char_ptrparams)
∥串口關(guān)閉函數(shù)
_mqx_int_io_sci_close(MQX_FILE_PTRfile_dev_ptr)
∥串口讀取函數(shù)
_mqx_int_io_sci_read(MQX_FILE_PTRfile_dev_ptr,char_ptrbuff,_mqx_intlen)
∥串口寫(xiě)入函數(shù)
_mqx_int_io_sci_write(MQX_FILE_PTRfile_dev_ptr,char_ptrbuff,_mqx_intlen)
其中:參數(shù)file_dev_ptr為關(guān)聯(lián)設(shè)備文件句柄;open_name為設(shè)備標(biāo)識(shí)符;params 為設(shè)備初始化屬性;buff為數(shù)據(jù)緩沖區(qū);len為數(shù)據(jù)長(zhǎng)度.
(ⅲ) 編寫(xiě)SCI驅(qū)動(dòng)注冊(cè)安裝函數(shù).MQX的I/O子系統(tǒng)層提供專門(mén)的API函數(shù)來(lái)管理設(shè)備驅(qū)動(dòng)隊(duì)列,包括_io_dev_install,_io_dev_uninstall,_io_get_handle,_io_init和_io_set_handle等.其中_io_dev_install函數(shù)負(fù)責(zé)將設(shè)備驅(qū)動(dòng)結(jié)點(diǎn)(包含設(shè)備標(biāo)識(shí)符、設(shè)備驅(qū)動(dòng)函數(shù)名和指向設(shè)備屬性信息結(jié)構(gòu)體指針)安裝到設(shè)備管理隊(duì)列中,從而建立I/O設(shè)備驅(qū)動(dòng)的中間轉(zhuǎn)換層.下面代碼段是在MQX/IO/io_inst.c文件中定義的_io_dev_install函數(shù)聲明部分:
_mqx_uint_io_dev_install(char_ptr identifier,∥設(shè)備標(biāo)識(shí)符
_mqx_int(_CODE_PTR_ io_open)∥I/O設(shè)備打開(kāi)函數(shù)
(MQX_FILE_PTR,char_PTR_,char_PTR_),∥I/O設(shè)備關(guān)閉函數(shù)
_mqx_int(_CODE_PTR_o_close)(MQX_FILE_PTR),
_mqx_int(_CODE_PTR_ io_read)∥I/O設(shè)備讀取函數(shù)
(MQX_FILE_PTR,char_PTR_,_mqx_int),∥I/O設(shè)備寫(xiě)函數(shù)
_mqx_int(_CODE_PTR_io_write)(MQX_FILE_PTR,char_PTR_,_mqx_int),
_mqx_int(_CODE_PTR_io_ioctl)∥I/O控制設(shè)備屬性函數(shù)
(MQX_FILE_PTR,_mqx_uint,pointer),∥I/O設(shè)備初始化數(shù)據(jù)結(jié)構(gòu)體
pointer io_init_data_ptr)
對(duì)于驅(qū)動(dòng)函數(shù)注冊(cè)安裝,需要具體設(shè)備的標(biāo)識(shí)符和指向存有設(shè)備屬性信息結(jié)構(gòu)的指針作為參數(shù),并在注冊(cè)驅(qū)動(dòng)函數(shù)內(nèi)部調(diào)用系統(tǒng)API函數(shù)_io_dev_install實(shí)現(xiàn)注冊(cè)安裝.SCI注冊(cè)安裝驅(qū)動(dòng)函數(shù)編寫(xiě)如下:
_mqx_uint io_sci_install(char_ptr identifier,SCI_INIT_PTR sci_init_ptr){
∥調(diào)用系統(tǒng)注冊(cè)安裝API函數(shù)
return_io_dev_install(identifier,_io_sci_open,_io_sci_close,_io_sci_read,_io_sci_write,_io_sci_ioctl,(pointer) sci_init_ptr);}
其中:參數(shù)identifier為SCI 設(shè)備標(biāo)識(shí)符;sci_init_ptr為設(shè)備屬性信息結(jié)構(gòu)體指針._io_dev_install 函數(shù)的形參在實(shí)際調(diào)用時(shí)與第2大部分步驟(ii)中定義的SCI具體驅(qū)動(dòng)功能函數(shù)指針關(guān)聯(lián),安裝成功即將SCI設(shè)備結(jié)點(diǎn)添加到系統(tǒng)的設(shè)備管理隊(duì)列之后.執(zhí)行打開(kāi)SCI設(shè)備文件操作時(shí),I/O子系統(tǒng)以SCI設(shè)備標(biāo)識(shí)符作為索引檢索設(shè)備管理隊(duì)列,定位到設(shè)備后,通過(guò)關(guān)聯(lián)的文件句柄調(diào)用驅(qū)動(dòng)函數(shù)對(duì)SCI進(jìn)行訪問(wèn).
(ⅳ) 在任務(wù)中調(diào)用驅(qū)動(dòng)服務(wù).底層設(shè)備驅(qū)動(dòng)注冊(cè)成功后,就可在MQX的功能任務(wù)中調(diào)用驅(qū)動(dòng)服務(wù).用戶可像對(duì)文件操作一樣,通過(guò)系統(tǒng)I/O層提供的標(biāo)準(zhǔn)函數(shù)對(duì)底層設(shè)備進(jìn)行訪問(wèn)和控制.在調(diào)用設(shè)備之前,需要獲取設(shè)備文件訪問(wèn)句柄,這一操作由標(biāo)準(zhǔn)函數(shù)fopen函數(shù)實(shí)現(xiàn).用戶打開(kāi)設(shè)備時(shí),實(shí)際上是獲取設(shè)備文件的訪問(wèn)句柄,有了設(shè)備訪問(wèn)句柄,其他標(biāo)準(zhǔn)函數(shù)就可以通過(guò)其來(lái)對(duì)設(shè)備進(jìn)行操作.以下是測(cè)試串口驅(qū)動(dòng)調(diào)用代碼:
void task_sci_test(uint_32 init_data)
{
MQX_FILE_PTR file_dev_ptr;
char buff=”This is SCI test!”;
file_dev_ptr=fopen(“sci2”,null);∥打開(kāi)設(shè)備,獲取設(shè)備文件句柄
if(file_dev_ptr){
write(file_dev_ptr,buff,strlen(buff));∥串口輸出字符串
}
fclose(file_dev_ptr);∥關(guān)閉設(shè)備
_task_block();∥任務(wù)阻塞
}
對(duì)于無(wú)操作系統(tǒng)驅(qū)動(dòng)調(diào)用而言,傳入的參數(shù)一般可被驅(qū)動(dòng)函數(shù)直接調(diào)用.而通過(guò)對(duì)MQX系統(tǒng)底層驅(qū)動(dòng)機(jī)制的分析可以發(fā)現(xiàn),在其三層驅(qū)動(dòng)模型中,底層設(shè)備驅(qū)動(dòng)與無(wú)操作系統(tǒng)下設(shè)計(jì)驅(qū)動(dòng)構(gòu)件的主要區(qū)別在于,MQX底層驅(qū)動(dòng)傳入的是結(jié)構(gòu)體類型指針,包含了傳入?yún)?shù)信息的解析操作.這些操作都是由操作系統(tǒng)的API函數(shù)進(jìn)行組織和傳遞的,這樣可以提高設(shè)備驅(qū)動(dòng)與操作系統(tǒng)的粘合性,降低底層設(shè)備驅(qū)動(dòng)的移植和復(fù)用效率,也難以復(fù)用被驗(yàn)證過(guò)的成熟設(shè)備驅(qū)動(dòng)構(gòu)件,導(dǎo)致增加嵌入式軟件的開(kāi)發(fā)難度,同時(shí)也延長(zhǎng)開(kāi)發(fā)周期[11].
對(duì)于底層驅(qū)動(dòng)過(guò)于依附操作系統(tǒng)API函數(shù)的情況,可以將MQX底層設(shè)備驅(qū)動(dòng)程序所需的參數(shù)由專門(mén)的函數(shù)(接口構(gòu)件)進(jìn)行解析后,再提供給底層設(shè)備驅(qū)動(dòng)函數(shù)使用,這樣MQX底層設(shè)備驅(qū)動(dòng)程序就與無(wú)操作系統(tǒng)下的設(shè)備驅(qū)動(dòng)程序趨于一致.同樣地,無(wú)操作系統(tǒng)下的設(shè)備驅(qū)動(dòng)程序只需加上一層負(fù)責(zé)參數(shù)解析的接口構(gòu)件,就可以掛接到MQX操作系統(tǒng)的設(shè)備管理隊(duì)列中,在MQX操作系統(tǒng)環(huán)境下使用.通過(guò)在I/O子系統(tǒng)層和底層設(shè)備驅(qū)動(dòng)層之間增加接口驅(qū)動(dòng)層(圖3),可以使得底層設(shè)備驅(qū)動(dòng)程序不再緊密依附操作系統(tǒng),實(shí)現(xiàn)設(shè)備驅(qū)動(dòng)完全獨(dú)立于MQX操作系統(tǒng).這樣一來(lái),底層驅(qū)動(dòng)就不必為某種操作系統(tǒng)專門(mén)設(shè)計(jì),應(yīng)用成熟的驅(qū)動(dòng)構(gòu)件還可以進(jìn)入構(gòu)件庫(kù),為用戶提供面向底層設(shè)備而不是面向操作系統(tǒng)的驅(qū)動(dòng)構(gòu)件.根據(jù)軟件工程構(gòu)件化開(kāi)發(fā)思想,成熟的構(gòu)件復(fù)用不僅能提高軟件開(kāi)發(fā)效率,還能提高系統(tǒng)的穩(wěn)定性和可靠性[12].
圖3 改進(jìn)的I/O驅(qū)動(dòng)層次結(jié)構(gòu)Fig.3 Improved I/O Driver Hierarchy
根據(jù)前文的分析,接口驅(qū)動(dòng)構(gòu)件可以作為操作系統(tǒng)內(nèi)核與底層驅(qū)動(dòng)程序的連接通道,實(shí)現(xiàn)接口轉(zhuǎn)接功能.其主要職責(zé)可以歸結(jié)為3點(diǎn):(1)接收來(lái)自I/O子系統(tǒng)層傳入的設(shè)備管理隊(duì)列中底層設(shè)備屬性結(jié)構(gòu)體參數(shù);(2)提取分解結(jié)構(gòu)體參數(shù)信息;(3)調(diào)用底層驅(qū)動(dòng)函數(shù)傳入至設(shè)備參數(shù),供其使用.考慮到MQX驅(qū)動(dòng)函數(shù)采用的是統(tǒng)一的模型,操作系統(tǒng)對(duì)設(shè)備驅(qū)動(dòng)屬性信息的解析方式和對(duì)驅(qū)動(dòng)函數(shù)的調(diào)用規(guī)則是一致的,在設(shè)計(jì)接口驅(qū)動(dòng)構(gòu)件時(shí),可復(fù)制工程中成熟的接口驅(qū)動(dòng)構(gòu)件進(jìn)行改寫(xiě),在提高效率的同時(shí)也能使接口驅(qū)動(dòng)構(gòu)件更好地與操作系統(tǒng)銜接.因此,1.3節(jié)中SCI串口打開(kāi)接口驅(qū)動(dòng)函數(shù)可改寫(xiě)如下(其他接口驅(qū)動(dòng)與此類似,不再贅述):
_mqx_int _io_sci_open(MQX_FILE_PTRfile_dev_ptr,char_ptrbuff,_mqx_int len){
∥在設(shè)備管理隊(duì)列中定位設(shè)備驅(qū)動(dòng)結(jié)點(diǎn)
IO_DEVICE_STRUCT_PTRdev_ptr=file_dev_ptr-DEV_PTR;
∥通過(guò)文件句柄訪問(wèn)設(shè)備屬性信息結(jié)構(gòu)體
SCI_INIT_PTR sci_init_ptr=(SCI_INIT_PTR)(dev_ptr-DRIVER_INIT_PTR);
∥提取設(shè)備屬性信息
uint_32 bus_clk=sci_init_ptr-BUS_CLK;
uint_32 b_rate=sci_init_ptr-BAUD_RATE;
∥調(diào)用底層驅(qū)動(dòng)函數(shù)實(shí)現(xiàn)功能
sci_init(dev_id,bus_clk,baud_rate);∥初始化∥串口
sci_send(dev_id,len,buff);∥串口數(shù)據(jù)發(fā)送
…
}
圖4 串口驅(qū)動(dòng)構(gòu)件測(cè)試Fig.4 Test of Serial Port Driver Component
測(cè)試工程使用MQXFW工程框架[2],硬件采用基于ARM Cortex-M0+內(nèi)核的KL25評(píng)估板.用串口轉(zhuǎn)USB線連接PC與KL25評(píng)估板,通過(guò)嵌入式集成開(kāi)發(fā)軟件KDS(Kinetis Design Studio,Kinetis設(shè)計(jì)工作室)將包含SCI驅(qū)動(dòng)構(gòu)件和發(fā)送接收任務(wù)的工程進(jìn)行編譯并下載到KL25啟動(dòng)運(yùn)行.程序的主要功能是KL25定時(shí)向PC機(jī)發(fā)送字符串“This is SCI test!”,并通過(guò)中斷接收來(lái)自PC機(jī)發(fā)送的字符串,然后將字符串回發(fā)給PC機(jī).運(yùn)行在PC機(jī)端的串口測(cè)試軟件顯示接收到的字符串如圖4所示.測(cè)試結(jié)果表明,KL25串口模塊正常接收發(fā)送字符串,所設(shè)計(jì)的SCI驅(qū)動(dòng)構(gòu)件運(yùn)行穩(wěn)定可靠,結(jié)果正確.
在嵌入式操作系統(tǒng)中,設(shè)備是應(yīng)用程序必使用的資源,然而設(shè)備具有多樣性,為了使操作系統(tǒng)下的應(yīng)用程序與設(shè)備無(wú)關(guān),須將設(shè)備的復(fù)雜性和多樣性屏蔽起來(lái),為應(yīng)用程序提供統(tǒng)一的使用接口.在MQX操作系統(tǒng)中采用了三層模型,以設(shè)備驅(qū)動(dòng)隊(duì)列管理器為核心載體實(shí)現(xiàn)統(tǒng)一的驅(qū)動(dòng)管理模式,使得用戶可以使用標(biāo)準(zhǔn)的I/O函數(shù)來(lái)訪問(wèn)控制底層設(shè)備.但從設(shè)備驅(qū)動(dòng)開(kāi)發(fā)、移植和復(fù)用角度來(lái)看,由于設(shè)備參數(shù)信息需要MQX系統(tǒng)API函數(shù)進(jìn)行解析傳遞,因此增加了設(shè)備驅(qū)動(dòng)程序與操作系統(tǒng)的粘合性,一定程度上也增加了設(shè)備驅(qū)動(dòng)的開(kāi)發(fā)難度,降低了驅(qū)動(dòng)構(gòu)件的可移植性和可復(fù)用性.從嵌入式軟件工程構(gòu)件開(kāi)發(fā)角度,在底層設(shè)備驅(qū)動(dòng)外層再次進(jìn)行封裝,通過(guò)接口構(gòu)件來(lái)解析設(shè)備屬性參數(shù)信息,實(shí)現(xiàn)底層驅(qū)動(dòng)與操作系統(tǒng)轉(zhuǎn)接,這樣就可實(shí)現(xiàn)面向底層設(shè)備的驅(qū)動(dòng)設(shè)計(jì),與操作系統(tǒng)無(wú)關(guān),將底層驅(qū)動(dòng)從操作系統(tǒng)中完全獨(dú)立出來(lái).實(shí)驗(yàn)證明,這種底層驅(qū)動(dòng)開(kāi)發(fā)方式有效提高了軟件開(kāi)發(fā)效率,開(kāi)發(fā)的底層驅(qū)動(dòng)構(gòu)件在不同應(yīng)用、不同操作系統(tǒng)間的移植和復(fù)用更加方便快捷.
吉首大學(xué)學(xué)報(bào)(自然科學(xué)版)2020年1期