楊小容,陳建政
(西南交通大學牽引動力國家重點實驗室,四川 成都 610031)
Linux操作系統(tǒng)的迅猛發(fā)展,與其具有的良好特性是分不開的。Linux是一種性能優(yōu)良、源碼公開、多用戶、多任務(wù)操作系統(tǒng),目前主要運用在大型服務(wù)器領(lǐng)域、網(wǎng)絡(luò)處理應用和嵌入式系統(tǒng)。隨著現(xiàn)代智能設(shè)備的不斷升級換代,基于ARM等嵌入式系統(tǒng)等的32位機智能系統(tǒng)在現(xiàn)代生活中的地位也越來越重要。為了加強在嵌入式系統(tǒng)領(lǐng)域的優(yōu)勢,Linux2.6已經(jīng)在內(nèi)核中加入了提高中斷性能和調(diào)度響應時間的改進,包括采用可搶占內(nèi)核、效率更高的調(diào)度算法和同步特性。另外,Linux2.6內(nèi)核加入了包括S3C2440X在內(nèi)的多種微控制器的支持,并開始支持多種流行的無MMU單元的微控制器,如Dragonball、ColdFire、Hitachi H8/300。掌握嵌入式Linux驅(qū)動開發(fā)及AD數(shù)據(jù)采集系統(tǒng)的開發(fā),實現(xiàn)高速、可靠的數(shù)據(jù)采集理念,并可將其用于高速列車的分布式數(shù)據(jù)采集系統(tǒng)中。
S3C2440是三星公司推出的采用RISC結(jié)構(gòu)的16/32位微處理器。它基于ARM920T內(nèi)核,采用五級流水線和哈佛結(jié)構(gòu),開發(fā)板布局簡潔明了,外設(shè)齊全,接口標準,擴展方便。最高頻率可達400MHz,低功耗,高性能,適合于PDA、便攜媒體播放器、衛(wèi)星導航儀等多媒體終端。文件系統(tǒng)采用YAFFS文件系統(tǒng),YAFFS類似于JFFS/JFFS2,是專門為NAND閃存設(shè)計的嵌入式文件系統(tǒng),適用于大容量的存儲設(shè)備[1-2]。
S3C2440有2個SPI口,可實現(xiàn)串行數(shù)據(jù)傳輸,每個SPI接口各有2個移位寄存器分別負責接收和發(fā)送數(shù)據(jù)。發(fā)送數(shù)據(jù)和接收數(shù)據(jù)是同步進行的,傳送的頻率可由相應的控制寄存器設(shè)定。數(shù)據(jù)傳輸時,一個SPI系統(tǒng)作為“主機”控制數(shù)據(jù)流,其他SPI作為“從機”,主機控制數(shù)據(jù)的輸入和輸出。S3C2440的SPI口包括2條數(shù)據(jù)線及2條控制線:
主機輸出從機輸入(SPIMOSI):數(shù)據(jù)線將主機輸出數(shù)據(jù)作為從機輸入。
主機輸入從機輸出(SPIMISO):數(shù)據(jù)線將從機輸出作為主機輸入。傳輸時,只有單從機傳輸數(shù)據(jù)。
串行時鐘(SPICLK):控制線由主機驅(qū)動,用來調(diào)節(jié)數(shù)據(jù)流。主機傳輸數(shù)據(jù)波特率可變,傳輸一位,產(chǎn)生一個SPICLK周期。
從機選擇(NSS):控制線允許硬件開關(guān)從機??膳c譯碼器結(jié)合控制多個外設(shè)。
該文采用 MISO,MOSI,SPICLK0 作為 SPI通信信號,NSS0作為TLC2543的片選信號。如圖1所示為S3C2440與TLC2543的接口電路圖。
圖1 S3C2440與TLC2543的連接圖
TLC2543是TI公司生產(chǎn)的一種12位開關(guān)電容逐次逼近A/D轉(zhuǎn)換器[2-5]。芯片共有11個模擬輸入通道(AIN0~AIN10)。芯片的三個控制端串行三態(tài)輸出數(shù)據(jù)端(DATA OUTPUT)、輸入數(shù)據(jù)端(DATA INPUT)、輸入/出時鐘(I/O CLOCK)能形成與微處理器之間數(shù)據(jù)傳輸較快和較為有效的串行外設(shè)接口(SPI)。片內(nèi)具有一個14通道多路選擇器用于在11個模擬輸入通道和3個內(nèi)部自測試(SELl-TEST)電壓中任選一個??赏ㄟ^對其8位內(nèi)部控制寄存器進行編程完成通道的選擇,并可對輸出結(jié)果的位數(shù)、MSB/LSB導前和極性進行選擇。如圖2是TLC2543時序圖(MSB FIRST),TLC2543在程序中定義16位輸出,但實際轉(zhuǎn)換結(jié)果仍為12位,只不過在數(shù)據(jù)傳送過程中4個LSB位被置為0。
TLC2543的片選信號CS變低時開始轉(zhuǎn)換和傳送過程,I/O CLOCK的前8個上升沿將8個輸入數(shù)據(jù)位鍵入輸入數(shù)據(jù)寄存器,同時它將前一次轉(zhuǎn)換的數(shù)據(jù)的其余11位移出DATA OUT端。TLC2543收到4個時鐘信號后,開始對選定的通道的模擬量進行采樣。并保持到第16個時鐘的下降沿,之后開始對采樣的模擬量進行轉(zhuǎn)換,大約需10 μs,轉(zhuǎn)換的數(shù)據(jù)保存在輸出數(shù)據(jù)寄存器中待下一個工作周期輸出。
設(shè)備驅(qū)動程序是操作系統(tǒng)內(nèi)核和機器硬件之間的接口,它為應用程序屏蔽了硬件的細節(jié),這樣在應用程序看來,硬件設(shè)備只是一個設(shè)備文件。應用程序可以和操作普通文件一樣,只需要進行文件的打開、讀寫和關(guān)閉等操作,就能控制底層的具體硬件設(shè)備[6-10]。在Linux操作系統(tǒng)下有三類主要的設(shè)備文件類型,即字符設(shè)備、塊設(shè)備和網(wǎng)絡(luò)設(shè)備。模數(shù)轉(zhuǎn)換芯片TLC2543屬于字符設(shè)備類(char device),這也是使用最多的設(shè)備類別。
使用一個設(shè)備之前要首先對其進行初始化,A/D設(shè)備驅(qū)動的初始化函數(shù)AD_init_module(void)主要完成兩個部分的操作,第一是對A/D的PIO口進行初始化設(shè)置,并對SPI的工作方式、各控制寄存器和模式寄存器等配置參數(shù);第二是完成A/D設(shè)備驅(qū)動程序向Linux內(nèi)核注冊,為其動態(tài)的申請一個設(shè)備號。
圖2 TLC2543時序圖(MSB FIRST)
初始化工作首先要對S3C2440的SPI控制器編程,設(shè)置SPI工作方式,完成對控制寄存器SPCON設(shè)置、波特率SPPRE設(shè)置和GPIO口的設(shè)置等。由于在Linux下是不允許對設(shè)備的物理地址進行直接訪問的,必須轉(zhuǎn)換為虛擬地址后才能訪問,定義AD_devices=kmalloc(sizeof(structAD_dev),GFP_KERNEL),并動態(tài)分配內(nèi)存 memset(AD_devices,0,sizeof(struct AD_dev))。
設(shè)置完各參數(shù)后還需要將設(shè)備驅(qū)動程序向Linux內(nèi)核注冊,利用函數(shù)int register_chrdev(unsigned int major,constchar*name,struct file_operations*fops)其中:major是感興趣的主編號,name是驅(qū)動的名字(出現(xiàn)在/proc/devices),fops是缺省的 file_operations結(jié)構(gòu)。這樣基本完成了設(shè)備驅(qū)動的初始化函數(shù)。
該驅(qū)動的工作流程如圖3所示。Linux內(nèi)核是通過一個file_perations的結(jié)構(gòu)體來組織對設(shè)備操作的具體實現(xiàn)函數(shù),結(jié)構(gòu)中的成分幾乎全是函數(shù)指針。包含了驅(qū)動程序提供給應用程序訪問硬件設(shè)備的各種方法。每個成員都對應一個系統(tǒng)調(diào)用,當用戶對設(shè)備文件進行操作時,系統(tǒng)調(diào)用通過設(shè)備文件的主設(shè)備號找到相應設(shè)備的驅(qū)動程序,然后找到file_operations中相應的函數(shù)指針,并由該函數(shù)進行以下的控制[2-5,11-12]。需要對SPI端口進行打開、關(guān)閉、接收、發(fā)送、傳輸數(shù)據(jù)操作,因此定義file_operations結(jié)構(gòu)體如下:
int AD_open(struct inode*inode,struct file*filp);
int AD_release(struct inode*inode,struct file*filp);
static ssize_t AD_write (struct file*file,const char*buf,size_t count,loft_t*offset);
其中讀設(shè)備方法主要實現(xiàn)A/D轉(zhuǎn)換后的結(jié)果輸出到用戶空間中,寫設(shè)備方法則相反,它從用戶空間讀取數(shù)據(jù),對A/D設(shè)備寫命令字進行控制。用戶利用SPI接口發(fā)送和接收數(shù)據(jù)時,系統(tǒng)就會分別調(diào)用AD_write和 AD_read函數(shù)及 AD_convert和 spi_tx_data函數(shù)。AD_read函數(shù)中需要注意參數(shù)buf和count。buf是用戶空間緩沖區(qū),read調(diào)用的返回數(shù)據(jù)保存在這里。count是指buf空間的大小,用字節(jié)數(shù)表示。當S3C2440的狀態(tài)寄存器(在此使用的是GPH的數(shù)據(jù)寄存器GPHDAT)設(shè)置為TXD時進行A/D轉(zhuǎn)換,可以通過 copy_to_usr(buf,from,count)函數(shù)將接收的數(shù)據(jù)傳送給用戶程序。AD_write函數(shù)中的buf和count參數(shù)同AD_read函數(shù)中的說明,可通過copy_from_usr(to,buf,count)函數(shù)接收用戶需要發(fā)送的數(shù)據(jù)。
文件的打開(AD_open)和關(guān)閉(AD_release)函數(shù)只是將模塊使用計數(shù)加一、減一。open調(diào)用時如果返回-1則表示打開設(shè)備文件不成功,close調(diào)用時只需關(guān)閉open函數(shù)返回的文件描述字所連的設(shè)備即可。
對于A/D轉(zhuǎn)換及其數(shù)據(jù)傳輸,定義:
void AD_convert(void);
void spi_tx_data(unsigned char data);
A/D轉(zhuǎn)換函數(shù)AD_convert中首先設(shè)置寄存器為發(fā)送狀態(tài),調(diào)用spi_tx_data通過中斷方式完成數(shù)據(jù)發(fā)送。S3C2440的SPI接口設(shè)置為中斷傳送模式進行串行數(shù)據(jù)傳輸:int request_irq(unsigned int irq,irqreturn_t(*handler)(int,void*,structpt_regs*),unsignedlongflags,constchar*dev_name,void*dev_id)。
與設(shè)備初始化函數(shù)相對應,設(shè)備注銷函數(shù)void AD_cleanup_module(void)主要完成釋放內(nèi)存空間、端口等操作,其核心部分是由字符設(shè)備注銷函數(shù)unregister_chrdev (unsigned intmajor,constchar*name)組成的,該函數(shù)完成驅(qū)動程序向Linux內(nèi)核的注銷,當設(shè)備驅(qū)動程序注銷以后,內(nèi)核收回所分配的設(shè)備號。
完成了驅(qū)動程序的編寫,接下來就要對生成的.c文件進行編譯。采用Linux中的交叉編譯工具arm-linux-gcc編譯驅(qū)動程序為目標文件[1,7-10]。驅(qū)動代碼完成后,需要編寫一個makefile:
執(zhí)行make命令后,生成ad.ko。啟動開發(fā)板后,在minicom終端下進入開發(fā)板/tmp目錄,執(zhí)行rz命令,將ad.ko發(fā)送到目標板上。隨后執(zhí)行動態(tài)加載命令:
#insmod ad.ko
這時可以用命令lsmod查看動態(tài)加載模塊:
#lsmod
為了正確使用設(shè)備驅(qū)動程序,必須先創(chuàng)建設(shè)備文件,可以用mknod命令來把設(shè)備映射為一個設(shè)備文件,用戶的應用程序就可以像操作標準文件那樣來訪問硬件設(shè)備了:
#mkmod/dev/ad c major minor
c是指字符設(shè)備,major是主設(shè)備號,minor為次設(shè)備號。
至此,完成了SPI設(shè)備TLC2543的驅(qū)動程序的開發(fā)。配合Linux環(huán)境下的數(shù)據(jù)采集程序?qū)⑵溆糜诟咚賱榆嚱M,這是傳統(tǒng)的單片機數(shù)據(jù)采集系統(tǒng)無法比擬的。
應用帶SPI接口的串行A/D轉(zhuǎn)換器占用較少的微處理器I/O資源,硬件連接簡單,軟件易于實現(xiàn),程序運行效率高。帶有SPI接口的串行A/D轉(zhuǎn)換器和ARM微處理器的結(jié)合可廣泛應用于實現(xiàn)數(shù)據(jù)采集功能的掌上設(shè)備及其他嵌入式的系統(tǒng),如醫(yī)療儀器、通信設(shè)備、抄表設(shè)備等領(lǐng)域。
[1]劉 淼.嵌入式系統(tǒng)接口設(shè)計與Linux驅(qū)動程序開發(fā)[M].北京航空航天大學出版社,2006.
[2]沃爾瓦諾.嵌入式微計算機系統(tǒng):實時接口技術(shù)[M].李 曦,等譯.北京:機械工業(yè)出版社,2003.
[3]魏永明.Linux設(shè)備驅(qū)動程序[M].2版.北京:中國電力出版社,2002.
[4]孫天澤,袁文菊,張海峰.嵌入式設(shè)計及Linux驅(qū)動開發(fā)指南[M].北京:電子工業(yè)出版社,2005.
[5]潘志東,劉增華.串行A/D轉(zhuǎn)換器TLC2543原理及應用[J].電測與儀表,2001,38(3):40-43.
[6]倪繼利.Linux內(nèi)核分析及編程[M].北京:電子工業(yè)出版社,2006.
[7]馮國進.嵌入式Linux驅(qū)動程序設(shè)計從入門到精通[M].北京:清華大學出版社,2008.
[8]孫 瓊.嵌入式Linux應用程序開發(fā)詳解[M].北京:人民郵電出版社,2007.
[9]羅苑堂,楊宗德.嵌入式Linux應用系統(tǒng)開發(fā)實例精講[M].北京:電子工業(yè)出版社,2007.
[10]Robbins A.實戰(zhàn)Linux編程精髓[M].楊明軍,譯.北京:中國電力出版社,2005.
[11]宋寶華.Linux設(shè)備驅(qū)動開發(fā)詳解[M].北京:人民郵電出版社,2005.
[12]李勝朝,黃先祥,謝 建.嵌人式Linux系統(tǒng)中字符設(shè)備驅(qū)動程序的開發(fā)[J].計算機工程,2007,33(4):5-8.