摘 要: 首先介紹了MAX1202的基本性能和特點(diǎn),詳細(xì)闡述了MAX1202在嵌入式Linux中驅(qū)動(dòng)程序的實(shí)現(xiàn)方法,最后介紹了編寫應(yīng)用程序測(cè)試驅(qū)動(dòng)程序的基本方法,為嵌入式Linux系統(tǒng)下的驅(qū)動(dòng)設(shè)計(jì)提供一個(gè)模板。
關(guān)鍵詞: MAX1202;驅(qū)動(dòng)程序;A/D轉(zhuǎn)換;嵌入式Linux
0 引言
科技的進(jìn)步使智能化設(shè)備越來越多地應(yīng)用到工業(yè)生產(chǎn)、農(nóng)業(yè)種植、醫(yī)療衛(wèi)生、航天設(shè)備甚至是居民的日常生活中,智能化設(shè)備要處理一些環(huán)境中的物理量就需要使用相關(guān)傳感器將其轉(zhuǎn)化成電量,如電壓、電流等。但是這些量要送給處理器處理,則必須要通過模/數(shù)轉(zhuǎn)換器進(jìn)行轉(zhuǎn)換。
本文中采用MAX1202模/數(shù)轉(zhuǎn)換器和友善之臂的Micro2440開發(fā)板,開發(fā)板使用三星公司的s3c2440的ARM9微處理器。在Linux系統(tǒng)中開發(fā)MAX1202驅(qū)動(dòng)程序并編寫應(yīng)用程序進(jìn)行驅(qū)動(dòng)程序的測(cè)試。
1 芯片介紹
MAX1202是一款8通道12位串行A/D轉(zhuǎn)換器。串行接口工作頻率最高可以達(dá)到2 MHz[1]。工作采用單端+5 V供電或雙端±5 V供電。內(nèi)部有一個(gè)8通道的多路轉(zhuǎn)換器、高帶寬的跟蹤/保持電路以及高轉(zhuǎn)換速度和低功耗的串行接口,芯片提供了符合SPI通信標(biāo)準(zhǔn)的SPI接口,以便于編程實(shí)現(xiàn)數(shù)據(jù)的轉(zhuǎn)換。
其典型應(yīng)用電路如圖1所示。
2 驅(qū)動(dòng)程序設(shè)計(jì)
Linux驅(qū)動(dòng)程序使用module_init宏中所定義的初始化函數(shù)注冊(cè)該驅(qū)動(dòng)及初始化硬件設(shè)備;使用module_exit宏中定義的注銷函數(shù)注銷設(shè)備,釋放相關(guān)資源。
結(jié)構(gòu)struct file_operations列出了設(shè)備驅(qū)動(dòng)程序可供應(yīng)用程序調(diào)用的所有函數(shù)。其中的成員都是函數(shù)指針,指向該函數(shù)的入口執(zhí)行位置,當(dāng)應(yīng)用程序調(diào)用open、read、write等函數(shù)時(shí),驅(qū)動(dòng)程序會(huì)通過該結(jié)構(gòu)找到對(duì)應(yīng)應(yīng)該執(zhí)行的M1202函數(shù),進(jìn)而根據(jù)傳入的參數(shù)執(zhí)行,以響應(yīng)應(yīng)用程序的調(diào)用。驅(qū)動(dòng)程序的編寫主要就在于file_operations結(jié)構(gòu)體中各驅(qū)動(dòng)函數(shù)的實(shí)現(xiàn),并不是每一個(gè)函數(shù)都要實(shí)現(xiàn)[2],對(duì)于不需要實(shí)現(xiàn)的函數(shù)可以賦值為空,也可以在函數(shù)實(shí)現(xiàn)中直接返回0,或直接調(diào)用系統(tǒng)默認(rèn)的實(shí)現(xiàn)函數(shù)。MAX1202的file_operations結(jié)構(gòu)體定義如下:
static const struct file_operations M1202_fops=
{
.owner=THIS_MODULE,
.open=M1202_open,
.read=M1202_read,
.write=M1202_write,
.ioctl=NULL,
};
2.1 模塊初始化函數(shù)M1202_init
在驅(qū)動(dòng)加載時(shí),系統(tǒng)進(jìn)程會(huì)通過module_init(M1202_init)宏找到所定義的驅(qū)動(dòng)初始化函數(shù)M1202_init(),進(jìn)行驅(qū)動(dòng)程序的加載。主設(shè)備號(hào)可以自已定義,向函數(shù)MKDEV(M1202_major,0)傳遞主次設(shè)備號(hào)產(chǎn)生dev_t類型的devno結(jié)構(gòu)[3];也可以由alloc_chrdev_region(&devno,0,1,M1202_name)函數(shù)自動(dòng)分配主設(shè)備號(hào);本例中自己定義主設(shè)備號(hào),然后由register_chrdev_region(devno,1,M1202_name)函數(shù)在Linux中為驅(qū)動(dòng)程序獲取設(shè)備編號(hào);接著就是向Linux內(nèi)核注冊(cè)字符設(shè)備,指出該驅(qū)動(dòng)可提供給應(yīng)用程序的接口結(jié)構(gòu)。實(shí)現(xiàn)代碼如下:
cdev_init(&M1202Cdev,&M1202_fops);
M1202Cdev.owner=THIS_MODULE;
M1202Cdev.ops=& M1202_fops;
cdev_add(&M1202Cdev,devno,1);
代碼中省去了錯(cuò)誤調(diào)試信息。
2.2 設(shè)備打開函數(shù)M1202_open
s3c2440芯片配備了2組SPI接口[4],Micro2440開發(fā)板引出了一組SPI1,對(duì)應(yīng)是PA7、PA8、PA9、PA10引腳,這是一組可以復(fù)用的端口,既可以用中斷、普通端口,也可以用于SPI通信。MAX1202在外部時(shí)鐘模式下的工作時(shí)序如圖2所示。
查看MAX1202在外部時(shí)鐘模式下的工作時(shí)序可以發(fā)現(xiàn),在控制字送入的8個(gè)時(shí)鐘后,芯片即開始了邊輸出邊轉(zhuǎn)換的過程,相比較內(nèi)部時(shí)鐘模式的轉(zhuǎn)換完成后再讀取輸出結(jié)果而言,有著更快的轉(zhuǎn)換效率,故采用外部時(shí)鐘模式。在控制字輸出后,轉(zhuǎn)換結(jié)果緊跟著輸出,為了減少頻繁對(duì)寄存器的操作,降低編程的難度,采用普通輸出端口輪流輸出高低電平的方法模擬主SPI設(shè)備的時(shí)鐘輸出。使用s3c2410_gpio_cfgpin(S3C2410_GPG11,S3C2410_GPG11_OUTP);將GPG11端配置成輸出端口用于輸出MAX1202工作時(shí)所需的片選信號(hào);類似地用s3c2410_gpio_cfgpin()函數(shù)配置GPG6、GPG7端為輸出端,分別用于產(chǎn)生MAX1202的控制字輸入與時(shí)鐘輸入;使用s3c2410_gpio_cfgpin(S3C2410_GPG5,S3C2410_GPG5_INP);將GPG5端口配置成輸入端口,用于讀取MAX1202的Dout端的輸出結(jié)果。在MAX1202正式工作前需將片選端CS端置為1,相應(yīng)地有s3c2410_gpio_setpin(S3C2410_GPG3,1);函數(shù);另外三個(gè)端口s3c2410_gpio_setpin函數(shù)配置為0。這些就是open函數(shù)所需要完成的端口配置。
2.3 寫函數(shù)M1202_write
設(shè)備打開后,每次轉(zhuǎn)換之前,需要向MAX1202寫控制字,以設(shè)置MAX1202選通的工作通道、時(shí)鐘模式、信號(hào)輸入模式等。MAX1202控制字格式如表1所示。
Bit7:起始位一般選擇1,用于標(biāo)識(shí)控制字的開始;
Bit6~Bit4:是8路通道的選擇,在單端模式下,依據(jù)8421編碼,000對(duì)應(yīng)第0通道CH0,001對(duì)應(yīng)第1通道CH1,010對(duì)應(yīng)第2通道CH2,以此類推;
Bit3:為信號(hào)的單雙極性選擇位,這里選擇1,單極性;
Bit2:為信號(hào)輸入方式選擇位,這里選擇1,單端輸入;
Bit1~Bit0:時(shí)鐘和斷電模式選擇位,這里選擇11,外部時(shí)鐘。
驅(qū)動(dòng)屬于內(nèi)核的一部分,而應(yīng)用程序?qū)儆谟脩艨臻g,內(nèi)核空間和用戶空間的數(shù)據(jù)不能共享,數(shù)據(jù)的傳輸需要使用特定的函數(shù)copy_from_user()和copy_to_user()。因此,由應(yīng)用程序傳入的控制字信息需要使用copy_from_user()傳入內(nèi)核空間。使用循環(huán)移位和與操作,輪流讀取8位控制字的每一位,由s3c2410_gpio_setpin(S3C2410_GPG6,X)函數(shù)將各位值輸出到MAX1202得DIN端,在時(shí)鐘的下降沿由MAX1202讀取,X代表了要傳輸?shù)囊晃恢怠?/p>
2.4 讀函數(shù)M1202_read
在外部時(shí)鐘模式下,控制字輸入完后即可在緊接著的16個(gè)時(shí)鐘周期內(nèi)讀取轉(zhuǎn)換結(jié)果,這16位轉(zhuǎn)換結(jié)果的最低4位為無效位,均為0,雖然無效,但必須在時(shí)鐘的作用下讀取出來,不然會(huì)影響到下一次的轉(zhuǎn)換結(jié)果,故函數(shù)讀取16位后左移4位用于消除低4位的無效位。while函數(shù)的執(zhí)行條件控制讀取次數(shù)為16次,s3c2410_gpio_getpin(S3C2410_GPG5)用于從MAX1202的DOUT端讀入當(dāng)前時(shí)鐘下的輸出值。讀取結(jié)束后,要使用copy_to_user()函數(shù)將得到的結(jié)果傳遞到用戶空間,以供顯示或處理。
2.5 模塊卸載函數(shù)M1202_exit
模塊卸載函數(shù)首先要?jiǎng)h除字符設(shè)備,然后釋放占用的驅(qū)動(dòng)設(shè)備號(hào),以供其他的設(shè)備使用。
cdev_del(&M1202Cdev);
unregister_chrdev_region(MKDEV(M1202_major,0),1);
3 MAX1202在嵌入式系統(tǒng)中的應(yīng)用
3.1 設(shè)備驅(qū)動(dòng)的加載
Linux下的驅(qū)動(dòng)有靜態(tài)加載和動(dòng)態(tài)加載兩種方式[5]。靜態(tài)加載將驅(qū)動(dòng)程序編譯到內(nèi)核里,系統(tǒng)啟動(dòng)后直接可以由應(yīng)用程序調(diào)用,但每次修改驅(qū)動(dòng)程序都必須重新編譯內(nèi)核,較麻煩。動(dòng)態(tài)加載是在系統(tǒng)啟動(dòng)后使用insmod命令,把編譯好的M1202.ko文件加載到系統(tǒng)中,不需要時(shí)可以使用rmmod命令卸載。但是在重新開機(jī)之后,該驅(qū)動(dòng)就沒了,需要重新加載。故靜態(tài)加載適合于驅(qū)動(dòng)開發(fā)完成后的產(chǎn)品量化;而動(dòng)態(tài)加載適合于驅(qū)動(dòng)開發(fā)過程中頻繁的修改。
在開發(fā)板中驅(qū)動(dòng)的動(dòng)態(tài)加載方法:
#cd/lib/modules/2.6.32.3-FriendlyARM
#insmod M1202.ko
#mknod/dev/M1202 c 55 0
在Linux中,設(shè)備被當(dāng)做文件一樣處理,任何可用設(shè)備在/dev/目錄下都會(huì)有一個(gè)對(duì)應(yīng)的設(shè)備文件,使用mknod命令創(chuàng)建設(shè)備節(jié)點(diǎn),在應(yīng)用程序中即可像操作文件一樣操作該設(shè)備。
3.2 數(shù)據(jù)采集
驅(qū)動(dòng)加載并且創(chuàng)建了設(shè)備節(jié)點(diǎn)后就可以編寫應(yīng)用程序進(jìn)行電壓數(shù)據(jù)的采集。
使用open函數(shù)以只讀的方式打開已經(jīng)創(chuàng)建了的M1202節(jié)點(diǎn)即打開了MAX1202硬件。傳入控制字0x8F給write函數(shù),開啟通道0的轉(zhuǎn)換,使用單極性單端輸入外部時(shí)鐘模式,read函數(shù)將轉(zhuǎn)換結(jié)果保存到指針num所指向的地址中,然后就可以打印或者處理轉(zhuǎn)換結(jié)果,最后像關(guān)閉文件一樣使用close()函數(shù)關(guān)閉設(shè)備。使用交叉編譯指令#arm-linux-gcc╞o M1202test M1202test.c編譯后生成應(yīng)用程序文件M1202test,通過串口導(dǎo)入Micro2440中或?qū)?yīng)用程序文件放到網(wǎng)絡(luò)根文件系統(tǒng)中,#chmod+x M1202test增加文件的可執(zhí)行權(quán)限,#./M1202test執(zhí)行可執(zhí)行文件,即可對(duì)通道0引腳的數(shù)據(jù)進(jìn)行采集轉(zhuǎn)換。
部分應(yīng)用程序如下:
int fd=open(“/dev/M1202”,0_RDWR);
int ctlword=0x8F;
write(fd,ctlword,1);
read(fd,&num,2);
printf(“num=%d\n”,num);
close(fd);
在實(shí)際使用中可以使用for(int i=0,i<8,i++)和ctlword=ctlword|(i<<4);改變控制字的Bit6-Bit4位,循環(huán)采集引腳0-7端輸入的電壓,或者根據(jù)需要使用其中部分引腳。經(jīng)測(cè)試,A/D轉(zhuǎn)換結(jié)果較好,在轉(zhuǎn)換誤差范圍內(nèi)。
4 結(jié)論
隨著智能化設(shè)備的發(fā)展,嵌入式系統(tǒng)將涉及生活中的方方面面。本文詳細(xì)介紹了MAX1202在嵌入式Linux系統(tǒng)中的驅(qū)動(dòng)程序的開發(fā)方法,對(duì)于相關(guān)驅(qū)動(dòng)程序的開發(fā)有一定的參考價(jià)值,且該MAX1202的A/D實(shí)現(xiàn)方法也可以應(yīng)用到一些工程實(shí)際中去。
參考文獻(xiàn)
[1] 蔣雙梅,高敦堂,都思丹.8通道12位串行A/D轉(zhuǎn)換器MAX1202及其應(yīng)用[J].微電子學(xué),2000,30(6):437-440.
[2] 韋東山.嵌入式Linux應(yīng)用開發(fā)完全手冊(cè)(第1版)[M].北京:人民郵電出版社,2008.
[3] 付興武,張軍,王洋.基于SPI總線協(xié)議的字符設(shè)備驅(qū)動(dòng)程序[J].計(jì)算機(jī)系統(tǒng)應(yīng)用,2013,22(2):146-150.
[4] 楊小容,陳建政.串口AD嵌入式Linux驅(qū)動(dòng)實(shí)現(xiàn)[J].中國(guó)測(cè)試,2010,36(2):84-87.
[5] 黃智偉,鄧月明,王彥.ARM9嵌入式系統(tǒng)設(shè)計(jì)基礎(chǔ)教程(第1版)[M].北京:北京航空航天大學(xué)出版社,2008.