郭小梅
(南京曉莊學(xué)院,南京210001)
郭小梅(副教授),主要研究領(lǐng)域計(jì)算機(jī)軟件與理論、嵌入式應(yīng)用技術(shù)。
當(dāng)今的電子消費(fèi)領(lǐng)域,重力感應(yīng)技術(shù)正以其迅猛的速度在發(fā)展。它在游戲機(jī)、移動(dòng)存儲(chǔ)設(shè)備、智能電動(dòng)車(chē)中有著廣泛的應(yīng)用;在高端智能手機(jī)、平板電腦等嵌入式移動(dòng)產(chǎn)品中,其應(yīng)用也越來(lái)越普及,它將給人們帶來(lái)更為方便、有趣、實(shí)用、豐富的全新體驗(yàn)。
MX51是飛思卡爾半導(dǎo)體基于ARM Cortex-A8內(nèi)核的高端ARM嵌入式多媒體處理器,它支持豐富的多媒體功能組合和外圍設(shè)備,處理器接口支持與所有常用外部存儲(chǔ)的連接,在工作和各種低功耗模式下實(shí)現(xiàn)最小的系統(tǒng)功耗,滿(mǎn)足操作系統(tǒng)和游戲系統(tǒng)越來(lái)越多的MIPS需求。嵌入式Linux操作系統(tǒng)以其免費(fèi)、開(kāi)源及功能強(qiáng)大等特點(diǎn),被廣泛應(yīng)用于各類(lèi)便攜式產(chǎn)品中,由于 Linux操作系統(tǒng)只提供相關(guān)設(shè)備的驅(qū)動(dòng)接口,實(shí)際應(yīng)用中,需針對(duì)具體芯片開(kāi)發(fā)相關(guān)的驅(qū)動(dòng)程序。本文以 Linux2.6.31內(nèi)核和MX51為系統(tǒng)的軟、硬件平臺(tái),討論了重力感應(yīng)驅(qū)動(dòng)程序的實(shí)現(xiàn)技術(shù)。
G-sensor表示重力傳感器,它是一種可以將運(yùn)動(dòng)或重力轉(zhuǎn)換為電信號(hào)的傳感器。重力感應(yīng)利用壓電效應(yīng)實(shí)現(xiàn),通過(guò)測(cè)量?jī)?nèi)部一片重物(重物和壓電片做成一體)重力正交兩個(gè)方向的分力大小,來(lái)判斷水平方向。G-sensor內(nèi)置3軸(X、Y和Z軸)加速計(jì),實(shí)際應(yīng)用中通常以這3個(gè)軸(或任意兩個(gè)軸)所構(gòu)成的角度來(lái)計(jì)算物體的傾斜角度,從而計(jì)算出重力加速度的值。
當(dāng)物體位置發(fā)生變化,如晃動(dòng)、跌落、旋轉(zhuǎn)、上升、下降時(shí),其所產(chǎn)生的加速力被G-sensor轉(zhuǎn)化為電信號(hào),通過(guò)微處理器的計(jì)算分析后,可完成設(shè)計(jì)中的特定功能。重力感應(yīng)技術(shù)應(yīng)用在移動(dòng)存儲(chǔ)設(shè)備上,利用重力加速度原理,一旦偵測(cè)到意外,能在摔落的瞬間將磁頭撤至安全停泊區(qū),有效確保工作狀態(tài)下的產(chǎn)品安全。在手機(jī)中應(yīng)用此項(xiàng)技術(shù),可以根據(jù)使用者的動(dòng)作實(shí)現(xiàn)屏幕圖像翻轉(zhuǎn)、功能選擇、游戲控制等。
本設(shè)計(jì)采用飛思卡爾半導(dǎo)體的MX51多媒體應(yīng)用處理器開(kāi)發(fā)板。處理器集成了3個(gè)I2C接口:I2C1和I2C2是普通I2C總線(xiàn),HSI2C是高速I(mǎi)2C總線(xiàn)。G-sensor芯片LIS33DE通過(guò)I2C2接口連接到MX51的總線(xiàn)上。圖1為硬件連接圖。
圖1 LⅠS33DE的硬件平臺(tái)
LIS33DE是ST(意法半導(dǎo)體)公司的重力感應(yīng)芯片,這是一款超緊湊,低功耗的三維線(xiàn)性加速度傳感器。芯片采用LGA封裝,16引腳,3×3×1 mm3大小,要求的額定輸入電壓范圍為2.16~3.6 V,電路中的供電電壓為2.775 V。LIS33DE的功耗小于1 mW,控制接口支持I2C和SPI接口。設(shè)計(jì)中采用I2C接口進(jìn)行數(shù)據(jù)通信。LIS33DE內(nèi)置可編程中斷發(fā)生器,軟件可采用中斷或查詢(xún)方式讀取重力感應(yīng)的狀態(tài)信息。
LIS33DE的主要寄存器包括控制寄存器CTRL_REG1~CTRL_REG3,狀態(tài)寄存器 STATUS_REG,數(shù)據(jù)寄存器OUT_X、OUT_Y和 OUT_Z。它們用來(lái)控制G-sensor的行為,存放加速度的值。系統(tǒng)通過(guò)I2C接口訪(fǎng)問(wèn)這些寄存器。
控制寄存器CTRL_REG1(20h):DR位(bit7)控制輸出數(shù)據(jù)的速率,可以選擇100 Hz或400 Hz;PD位(bit6)控制芯片的工作狀態(tài):power down或active;Zen、Yen和Xen位(bit2~0),控制Z、Y和X軸的使能:1為enable,0為disable。
控制寄存器CTRL_REG2(21h):BOOT位(bit6)控制為復(fù)位寄存器內(nèi)容,0為正常模式,1為復(fù)位寄存器內(nèi)容。BOOT位用來(lái)恢復(fù)LIS33DE寄存器的默認(rèn)值。
控制寄存器CTRL_REG3(22h):IHL位(bit7)控制中斷有效電平,0為高電平有效,1為低電平有效。
狀態(tài)寄存器STATUS_REG(27h):高4位表示X、Y、Z軸的數(shù)據(jù)是否有溢出,低4位表示X、Y、Z軸的數(shù)據(jù)是否有效。
數(shù)據(jù)寄存器OUT_X(29h):以二進(jìn)制補(bǔ)碼格式存儲(chǔ)X軸數(shù)據(jù)。
數(shù)據(jù)寄存器OUT_Y(2Bh):以二進(jìn)制補(bǔ)碼格式存儲(chǔ)Y軸數(shù)據(jù)。
數(shù)據(jù)寄存器OUT_Z(2Dh):以二進(jìn)制補(bǔ)碼格式存儲(chǔ)Z軸數(shù)據(jù)。
當(dāng)物體位置發(fā)生變化時(shí),LIS33DE實(shí)時(shí)檢測(cè)、判斷出各個(gè)方向軸上重力加速度的變化,并將其值存入數(shù)據(jù)寄存器OUT_X、OUT_Y和OUT_Z。驅(qū)動(dòng)程序裝載運(yùn)行后,以查詢(xún)方式定時(shí)調(diào)用工作隊(duì)列中的任務(wù)處理函數(shù):讀數(shù)據(jù)寄存器,向系統(tǒng)報(bào)告事件及變化的坐標(biāo)值。MX51通過(guò)I2C2接口與LIS33DE芯片進(jìn)行數(shù)據(jù)通信,使用一個(gè)總線(xiàn)設(shè)備,除了為其設(shè)計(jì)驅(qū)動(dòng)程序,還須向Linux內(nèi)核注冊(cè)此設(shè)備。
在 arch/arm/mach-mx51/mx51_3stack.c中,定義struct i2c_board_info結(jié)構(gòu)變量,用于描述I2C設(shè)備特性:
其中type為定義的I2C設(shè)備名稱(chēng),addr為I2C設(shè)備地址。然后,調(diào)用如下函數(shù)注冊(cè)此設(shè)備:
i2c_register_board_info(1,mxc_i2c1_board_info,ARRAY_SIZE(mxc_i2c1_board_info));
系統(tǒng)初始化時(shí),會(huì)根據(jù)板級(jí)I2C設(shè)備配置信息,創(chuàng)建I2C客戶(hù)端設(shè)備i2c_client,并將其添加到I2C子系統(tǒng)中。
I2C總線(xiàn)上的數(shù)據(jù)通信由I2C設(shè)備驅(qū)動(dòng)實(shí)施,設(shè)備驅(qū)動(dòng)通過(guò)I2C總線(xiàn)與具體設(shè)備進(jìn)行交互。一個(gè)設(shè)備驅(qū)動(dòng)需由2個(gè)結(jié)構(gòu)struct i2c_driver和struct i2c_client來(lái)描述。其中i2c_driver表示一個(gè)I2C設(shè)備驅(qū)動(dòng),i2c_client表示使用i2c_driver驅(qū)動(dòng)的設(shè)備。
在drivers/i2c/chips/lis33de.c中作如下定義:
lis33de_driver表示管理I2C設(shè)備的驅(qū)動(dòng)程序。在驅(qū)動(dòng)入口函數(shù) lis33de_init中調(diào)用函數(shù)i2c_add_driver(&lis33de_driver)注冊(cè)這個(gè)設(shè)備驅(qū)動(dòng)。驅(qū)動(dòng)成功加載后,系統(tǒng)會(huì)自動(dòng)調(diào)用探測(cè)函數(shù)lis33de_probe,該函數(shù)原型如下:
static int lis33de_probe(struct i2c_client*client,const struct i2c_device_id*id);
其中參數(shù)i2c_client*client表示此前已向系統(tǒng)注冊(cè)過(guò)的I2C設(shè)備,即lis33de芯片。
Linux內(nèi)核提供了輸入子系統(tǒng)(Input Subsystem),常用輸入設(shè)備如鍵盤(pán)、鼠標(biāo)、觸摸屏等都可以利用輸入子系統(tǒng)的接口函數(shù)來(lái)實(shí)現(xiàn)設(shè)備驅(qū)動(dòng),重力感應(yīng)驅(qū)動(dòng)亦可納入輸入子系統(tǒng)框架。輸入子系統(tǒng)由核心層、驅(qū)動(dòng)層和事件處理層三部分組成,它們之間通過(guò)事件進(jìn)行通信。我們將重力感應(yīng)芯片LIS33DE作為一個(gè)輸入設(shè)備,利用輸入子系統(tǒng)實(shí)現(xiàn)重力感應(yīng)驅(qū)動(dòng),需做以下工作:
◆在驅(qū)動(dòng)模塊加載函數(shù)中申請(qǐng)一個(gè)輸入設(shè)備。
◆設(shè)置輸入子系統(tǒng)所支持的事件類(lèi)型。
◆設(shè)置坐標(biāo)的取值范圍。
◆注冊(cè)輸入設(shè)備。
◆報(bào)告發(fā)生的事件及對(duì)應(yīng)的坐標(biāo)。
通過(guò)輸入子系統(tǒng)實(shí)現(xiàn)重力感應(yīng)驅(qū)動(dòng),需要在drivers/i2c/chips/lis33de.c中定義設(shè)備結(jié)構(gòu),對(duì) lis33de進(jìn)行描述:
結(jié)構(gòu)input_dev定義在<Linux/input.h>中,用于描述輸入設(shè)備的驅(qū)動(dòng)結(jié)構(gòu),主要包括響應(yīng)的事件類(lèi)型、按鍵內(nèi)容、數(shù)據(jù)相對(duì)值的范圍及一些處理函數(shù)。設(shè)備驅(qū)動(dòng)的主要任務(wù)在以下函數(shù)中完成。
3.4.1探測(cè)函數(shù)lis33de_probe
在入口函數(shù)lis33de_init中成功加載設(shè)備驅(qū)動(dòng)后,探測(cè)函數(shù)lis33de_probe開(kāi)始執(zhí)行。函數(shù)主要實(shí)現(xiàn)以下操作:
①定義結(jié)構(gòu)指針“struct lis33de_data*sensor_data;”和“struct input_dev*input;” ,申請(qǐng)?jiān)O(shè)備所需空間 。
②設(shè)置事件類(lèi)型。
④注冊(cè)輸入設(shè)備。
⑤創(chuàng)建工作隊(duì)列,構(gòu)建任務(wù)并提交到工作隊(duì)列。
其中g(shù)lb_sensor為已定義的全局struct lis33de_data類(lèi)型的指針,glb_sensor-﹥gsensor_work為任務(wù)名稱(chēng),sensor_workqueue_func為函數(shù)名,表示執(zhí)行該任務(wù)時(shí)從工作隊(duì)列中調(diào)用的函數(shù)。用queue_delayed_work函數(shù)提交任務(wù)到工作隊(duì)列,LONG_DELAY_TIME為指定的delay,定義為HZ*12,在lis33de_probe函數(shù)調(diào)用12 s后,自動(dòng)執(zhí)行任務(wù)處理函數(shù)sensor_workqueue_func。
⑥電源管理。在嵌入式手持設(shè)備里,電源管理的實(shí)現(xiàn)和節(jié)電非常重要,重力感應(yīng)驅(qū)動(dòng)需要很好的電源管理。由于LIS33DE屬于輸入設(shè)備,我們需要實(shí)現(xiàn)early suspend和late resume。對(duì)已定義的全局變量“struct early_suspend gsensor_early_suspend;”進(jìn)行初始化:
lis33de_early_suspend()和 lis33de_late_resume()函數(shù)是相應(yīng)電源管理系統(tǒng)休眠時(shí)和喚醒后分別調(diào)用的函數(shù)。在lis33de_early_suspend()函數(shù)中,首先使LIS33DE進(jìn)入Power Down狀態(tài),然后取消對(duì)應(yīng)的工作隊(duì)列。
在lis33de_late_resume()函數(shù)中,首先寫(xiě)LIS33DE的寄存器0x20,使其進(jìn)入active模式,然后把工作隊(duì)列加入工作隊(duì)列。
3.4.2數(shù)據(jù)處理函數(shù)sensor_workqueue_func
lis33de_probe函數(shù)執(zhí)行12 s后,隊(duì)列中的任務(wù)處理函數(shù)sensor_workqueue_fun被首次調(diào)用。函數(shù)的主要任務(wù)是讀取G-sensor數(shù)據(jù)寄存器中的重力感應(yīng)數(shù)據(jù),經(jīng)處理后向上層發(fā)送:
讀取的值在變量DX8、DY8、DZ8中,用以下代碼對(duì)坐標(biāo)值進(jìn)行處理。
通過(guò)input_report_abs()向上層發(fā)送。
為了持續(xù)不斷地查詢(xún)下去,在sensor_workqueue_func()函數(shù)的最后,再次提交任務(wù)到工作隊(duì)列:
queue_delayed_work(glb_sensor-﹥gsensor_wq,&glb_sensor-﹥gsensor_work,DELAY_TIME);其中 DELAY_TIME定義為40 ms。以后,系統(tǒng)以固定的時(shí)間間隔(40 ms)反復(fù)調(diào)用任務(wù)處理函數(shù),只要系統(tǒng)運(yùn)行,就存在重力感應(yīng)的輸入數(shù)據(jù)報(bào)告。
3.4.3 設(shè)備初始化函數(shù)lis_init
函數(shù)主要實(shí)現(xiàn)對(duì)LIS33DE寄存器初始化。
在android 2.2系統(tǒng)下進(jìn)行重力感應(yīng)驅(qū)動(dòng)測(cè)試。打開(kāi)gallery圖片瀏覽程序,旋轉(zhuǎn)平板電腦,可以發(fā)現(xiàn),圖片也隨之旋轉(zhuǎn),能夠始終保持正確的瀏覽姿態(tài)。
MX51處理器通過(guò)I2C接口與LIS33DE重力感應(yīng)芯片連接,以L(fǎng)inux輸入設(shè)備驅(qū)動(dòng)形式開(kāi)發(fā)該驅(qū)動(dòng),設(shè)計(jì)中使用了查詢(xún)、隊(duì)列等技術(shù)。本文對(duì)重力感應(yīng)驅(qū)動(dòng)程序的架構(gòu)及主要實(shí)現(xiàn)技術(shù)進(jìn)行了討論,該驅(qū)動(dòng)有著較為清晰的結(jié)構(gòu),針對(duì)具體硬件,修改底層初始化和坐標(biāo)讀取代碼,可以方便地移植到多種嵌入式Linux系統(tǒng)平臺(tái)。
[1]Linux設(shè)備驅(qū)動(dòng)程序[M].魏永明,譯.3版.北京:中國(guó)電力出版社,2006.
[2]Linux內(nèi)核編程指南[M].張瑜,等譯.3版.北京:清華大學(xué)出版社,2004.
[3]劉淼.嵌入式系統(tǒng)接口設(shè)計(jì)與Linux驅(qū)動(dòng)程序開(kāi)發(fā)[M].北京:北京航空航天大學(xué)出版社,2006.
[4]潘巨龍,黃寧,姚伏天,等.ARM9嵌入式Linux系統(tǒng)構(gòu)建與應(yīng)用[M].北京:北京航空航天大學(xué)出版社,2006.
[5]馮國(guó)進(jìn).嵌入式 Linux驅(qū)動(dòng)程序設(shè)計(jì)[M].北京:清華大學(xué)出版社,2008.