摘 要:詳細介紹S3C2410芯片ADC模塊以及Linux的驅動模型,并且通過S3C2410內置的ADC驅動程序設計說明字符型設備驅動開發方法;將驅動編譯為模塊的方式,單獨加載入內核,便于調試。以MINICOM為操作臺,控制驅動模塊的加載和應用程序的運行。并通過實例介紹ADC驅動程序在電阻、電壓等測試中的實際應用;從實驗結果可以看出ADC驅動可以被成功加載和調用;該驅動可以測試電壓、電流等標準工程量信號,或作為工業傳感器接口的一部分對現場標準工程量信號進行采集處理。
關鍵詞:S3C2410;ADC;Linux;字符設備驅動程序
中圖分類號:TP311文獻標識碼:B
文章編號:1004373X(2008)2203303
Implement and Application of ADC Driver about Embedded-Linux
SUN Dehui,LIANG Xin,YANG Yang
(Key Laboratory of Beijing Municipality,The FAT Laboratory,North China University of Technology,Beijing,100041,China)
Abstract:The module of ADC in S3C2410 CMOS chip and the model about Linux drivers are expounded,the method of developing character device drivers are illuminated by realizing an ADC driver.As convenient to debug,compiling the drivers into module and \"insmod\" it into kernel.Updating the drivers module and application by MINICOM,one kind of consoles.Application on testing resistance and voltage using ADC driver are introduced through an example.In the end,it is obviously that ADC drivers module could be \"insmoded\"and called successful from the result of experiment.using the drivers testing resistance,voltage and many other standard signal.ADC drivers can collect the standard signal of plants as one part of interface of industrial sensor.
Keywords:S3C2410;ADC;Linux;character device driver
1 引 言
S3C2410開發板制造商提供了絕大部分的驅動程序,但有時出于實際開發的需要、應用程序的穩定性考慮,用戶往往需要開發一個自己需要的接口驅動程序。下面分析Linux字符設備驅動程序的結構,以及ADC驅動程序的開發。本驅動可以測試電壓、電流等標準工程量信號,或作為工業傳感器接口的一部分對現場標準工程量信號進行采集處理(可以在平臺上為傳感器預留接口,本文在作電路板時已直接將測試用的滑動變阻器與A/D接口相連)。
2 S3C2410X及ADC模塊
S3C2410X是韓國三星電子公司推出的一款基于ARM920T內核的16/32位RISC嵌入式微處理器,該處理器主要面向手持式設備以及高性價比、低功耗方面的應用[1]。S3C2410X芯片集成1個LCD控制器(支持STN和TFT帶有觸摸屏的液晶顯示屏)、SDRAM控制器、3個通道的UART、4個通道的DMA、4個具有PWM功能的計時器和1個內部時鐘、8通道的10位ADC,同時S3C2410X還有豐富的外部接口,例如觸摸屏接口、I2C總線接口、主從USB設備接口、SPI接口、SD/MMC卡接口等[2]。
S3C2410X芯片內部集成了一個8路10位A/D轉換器(其中第5、第6通道可用于支持觸摸屏接口)。ADC模塊是帶采樣保持器的,在25 MHz A/D轉換時鐘下,最高轉換速率是500 kS/s,以片上采樣、保持的方式工作,支持掉電模式,其測量模擬輸入電壓范圍為0~3.3 V。由于ADC轉換模塊和觸摸屏控制是共用的8通道模擬信號輸入,所以要單獨實現A/D轉換功能需要把ADC觸摸屏控制器(ADCTSC)設置成通常工作模式(ADCTSC的AUTO_PST=0,XY_PST=0)[3,4]
A/D轉換時間在PCLK頻率為50 MHz并且預分頻值為49的情況下,轉換10位數據的時間為:
A/D轉換頻率=50 MHz/(49+1)=1 MHz
轉換時間=1/(1 MHz/5 cycles)=1/200 kHz
=5 μs
對ADC操作,主要是對下面的ADC幾組寄存器進行讀寫操作:
ADC控制寄存器:ADCCON(2410ARM平臺下寄存器物理地址是 0X5800000);
ADC觸摸屏控制寄存器:ADCTSC(2410ARM平臺下寄存器物理地址 0X58000004);
ADC數據寄存器:ADCDAT0/1(2410ARM平臺下寄存器物理地址 0X5800000C/0X58000010) [5]。
3 Linux的設備驅動程序模型
目前Linux支持的設備驅動可分為3種:字符設備(character device)、塊設備(block device)、網絡接口設備(network interface)[2]。本文所涉及的ADC摸塊驅動程序就是屬于字符設備驅動程序。字符設備指那些無需緩沖直接存取的設備。在對字符設備發出讀、寫請求時,實際的硬件I/O一般就緊接著發生了,是Linux設備中最簡單的一種。應用程序可以用與存取文件相同的系統調用來打開、讀寫及關閉它。即使此設備是將系統連接到網絡中的PPP后臺進程的modem也是如此。字符設備驅動程序一般要包含open,close,read,write等幾個系統調用[6]。
I/O子系統向內核其他部分提供了一個統一的標準設備接口,這是通過數據結構file_operations[7]來完成的。這個結構中的每一個成員的名字都對應著一個系統調用,用戶進程利用系統調用在對設備文件進行諸如read/write操作時,系統調用通過設備文件的主設備號找到相應的設備驅動程序,然后讀取這個數據結構相應的函數指針,接著把控制權交給該函數,這是Linux的設備驅動程序工作的基本原理。編寫設備驅動程序的主要工作就是編寫子函數,并填file_operations的各個域。
4 ADC底層驅動程序的實現
ADC驅動程序的主要任務,就是把2410的ADC內置模塊的使用傳遞給應用程序,為了便于理解,下面就按照驅動程序加載、使用的順序,來講述ADC底層驅動的實現。
4.1 驅動程序的加載及初始化
驅動程序的加載方式有2種:一種是將其作為內核的一部分,直接編譯到內核中,即靜態編譯,也可以單獨作為一個模塊編譯,在需要時再動態地把它加載入內核,不需要時也可從內核中刪除,即動態連接。由于S3C2410X芯片帶MMU,在此,使用動態連接方式進行加載,也便于調試[8]。
在Linux的相關路徑下,使用指令insmod s3c2410-adc.o 即可將編譯好的ADC驅動程序以模塊的方式加載入內核。當驅動加載入內核之后,首先要調用s3c2410_adc_init()函數。絕大多數驅動程序,都要在XXX_Init()函數中完成驅動程序的初始化,這其中包括物理地址的映射、中斷注冊、管腳和相應寄存器的初始化等。當然也可在open(),read()函數中對寄存器進行初始化,視具體程序要求而定(本文對ADC部分寄存器的初始化是在read部分完成的)。
向系統增加一個驅動程序則意味著要賦予它一個主設備號,這一賦值過程是通過register_chrdev()函數來實現的,這個函數定義在
int register_chrdev(unsigned int major,const char *name,struct file_operations *fops);
register_chrdev()需要3個參數:參數一是希望獲得的設備號,如果是零,系統將選擇一個沒有被占用的設備號返回;參數二是設備文件名,參數三用來登記驅動程序實際執行操作的函數的指針[7](在上文中提到的file_operations結構體中定義)。如果登記成功,返回設備的主設備號,不成功,返回一個負值。
ADC初始化主要代碼如下:
int __init s3c2410_adc_init(void)
{
int ret;
ADCTSC = 0;//將ADCTSC寄存器設成通常工作模式
ret = register_chrdev(0,DEVICE_NAME,s3c2410_fops);
if (ret < 0) {
printk(DEVICE_NAME \" can't get major number\\\\");
return ret;
}//初始化主設備號為0,使系統為此驅動程序動態地分配一個主設備號
adcMajor=ret;
printk (DEVICE_NAME\"\\\initialized\\\\");
return 0;
4.2 打開、讀、寫ADC驅動程序
當應用程序打開ADC驅動程序時,通過指針s3c2410_fops調用對應的s3c2410_adc_open()函數,這個函數比較簡單,不予介紹。S3C2410X有6個通道可做一般功能使用的ADC,在本驅動程序中只使用0,1兩個通道,且在對應的應用程序中進行設置,會在下文中予以介紹。應用程序要讀取某一路的ADC值時,先調用s3c2410_adc_write()函數,把用戶程序要求的通道號channel和預分頻比值prescale傳遞到ADC設備的結構體變量中。這2個結構體成員定義如下:
typedef struct {
struct semaphore lock;
wait_queue_head_t wait;
int channel;// ADC_DEV設備通道號
int prescale; // ADC_DEV設備預分頻比
}ADC_DEV;
s3c2410_adc_write()函數的部分代碼如下:
int data;
copy_from_user(data,buffer,count);
adcdev.channel=ADC_WRITE_GETCH(data);//設置通道號
adcdev.prescale=ADC_WRITE_GETPRE(data); //設置預分頻比
return count;
}
ADC_WRITE_GETCH(data)和ADC_WRITE_GETPRE(data)是2個帶參數的宏,通過簡單的算法處理,將用戶程序要求的通道號和預分頻比分別剃出。
接下來應用程序調用s3c2410_adc_read()函數來啟動某一通道的ADC轉換并讀取轉換后的數據,這一過程是主要對ADC物理寄存器進行操作,主要代碼如下:
ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch));
ADCCON |= ADC_START//開啟ADC轉換
interruptible_sleep_on(adcdev.wait);//休眠用戶進程,等待轉換結束后,再將其喚醒
ret = ADCDAT0; //轉換結束,數據存儲在ADCDAT0寄存器中
ret = 0x3ff;
copy_to_user(buffer,(char *)ret,sizeof(ret));//將轉換結果傳遞給用戶程序
其中PRESCALE_EN,PRSCVL(prescale),DC_INPUT((ch)),ADC_START這幾個宏分別對ADCCON寄存器的相應位進行了設置,copy_to_user()將ret這個在內核空間局部變量中的10 b數據傳遞給用戶空間。
本ADC驅動程序主要的函數介紹完畢,接下來只要完成s3c2410_adc_release(),s3c2410_adc_exit()等其他函數就可以。前文已經提過,字符設備驅動程序所有的系統調用都是通過file_operations結構體[7]集合的,對于本程序,定義如下:
static struct file_operations s3c2410_fops = {
owner:THIS_MODULE,
open:s3c2410_adc_open,
read:s3c2410_adc_read,
write:s3c2410_adc_write,
release:s3c2410_adc_release,
};
用戶程序在調用時只需像使用read,write操作普通文件一樣對底層進行字符設備進行操作。
5 ADC驅動程序的應用
在基于2410的Linux環境下,用這個驅動程序可以實現外部模擬信號到2410數字信號的轉換,下面是一個最基本的電壓測量的運用,原理圖如圖1所示。
通過改變2個滑動變阻器兩端的電壓來分別得到2個模擬輸入信號,通過導線直接連接到S3C2410芯片的AIN0和AIN1引腳(暫不考慮放大和濾波處理)。
在應用程序中,通過一個for循環語句來實現對AIN0和AIN1兩路通道的循環采集數據的。
while( stop==0 )
{
for(i=0;i<=1;i++){ //采樣0~1路A/D值,通道號就是在這里設置的
d=((float)GetADresult(i)*3.3)/1024.0;
printf(\"AIN%d=%8.4f\\\\",i,d);}
}
其中GetADresult()函數即實現read和write系統調用:
static int GetADresult(int channel)
{
int PRESCALE=0X**;
int data=ADC_WRITE(channel,PRESCALE);
write(adc_fd,data,sizeof(data));
read(adc_fd,data,sizeof(data));
return data;
}
GetADresult()的返回值就是通過copy_to_user()傳遞過來的10位A/D轉換結果。根據返回值data來計算模擬電壓為:
date/210×3.3。
在上位機上使用相應的gcc編譯器將驅動程序和應用程序編譯后,下載到開發板上運行,可在minicom或超級終端上看到如圖2所示運行結果。
6 結 語
基于Linux和S3C2410的嵌入式產品運用已經越來越廣泛,分析Linux下ADC驅動程序的開發,通過本文的介紹,讀者可以對Linux的驅動程序的結構、編寫以及實際應用能有一定的了解。
參考文獻
[1]潘巨龍,黃寧.ARM9嵌入式Linux系統構建與應用[M].北京:北京航空航天大學出版社,2007.
[2]孫天澤,袁文菊.嵌入式設計及Linux驅動開發指南[M].2版.北京:電子工業出版社,2007.
[3]舒云.邱紹峰.基于Windows CE.NET的ADC驅動程序實現與應用研究[J].工業控制計算機,2007,20(4):57-58,61.
[4]暢衛功,丁忠林.嵌入式Linux系統中觸摸屏驅動的研究[J].微計算機信息,2007,23(20):103-105.
[5]S3c4210 user′s manual.Samsung Electrionic.2004.
[6]何世烈,陳建.基于嵌入式Linux的設備驅動程序設計[J].單片機與嵌入式系統應用,2007(7):65-67.[7]JonatbanCorbet,Alessandro Rubini,Greg Kroah-Hartman.LINUX設備驅動程序[M].3版.魏永明,譯.北京:中國電力出版社,2005.
[8]宋寶華,華清遠見嵌入式培訓中心.LINUX設備驅動開發詳解[M].北京:人民郵電出版社,2008.
[9]潘輝,賈世祥.基于s3c2410和嵌入式Linux的D/A轉換的實現[J].微計算機信息,2007(20):128-129,130.
[10]劉淼.嵌入式系統接口設計與Linux驅動程序開發[M].北京:北京航空航天大學出版社,2006.
[11]孫婷,田澤,閆效鶯.基于S3C2440的Windows CE設備驅動的研究與實踐\\.現代電子技術,2008,31(6):153-155,158.
作者簡介 孫德輝 男,1962年出生,吉林人,教授,博士。研究方向為網絡控制理論與網絡自動化技術、嵌入式技術與信息家電。
注:本文中所涉及到的圖表、注解、公式等內容請以PDF格式閱讀原文