ADC驅(qū)動完全注釋_第1頁
ADC驅(qū)動完全注釋_第2頁
ADC驅(qū)動完全注釋_第3頁
ADC驅(qū)動完全注釋_第4頁
ADC驅(qū)動完全注釋_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、嵌入式Linux之我行,主要講述和總結(jié)了本人在學(xué)習(xí)嵌入式linux中的每個步驟。一為總結(jié)經(jīng)驗,二希望能給想入門嵌入式Linux的朋友提 供方便。如有錯誤之處,謝請指正。一、開發(fā)環(huán)境主 機:VMWare-Fedora 9二、硬件原理分析S3C2440內(nèi)部ADC結(jié)構(gòu)圖我們從上面的結(jié)構(gòu)圖和數(shù)據(jù)手冊可以知道,該ADC模塊總共有8個通道可以進行模擬信號的輸入,分別是AIN0、AIN1、AIN2、AIN3、 YM、YP、XM、XP。那么ADC是怎么實現(xiàn)模擬信號到數(shù)字信號的轉(zhuǎn)換呢?首先模擬信號從任一通道輸入,然后設(shè)定寄存器中預(yù)分頻器的值來確定AD轉(zhuǎn)換器 頻率,最后ADC將模擬信號轉(zhuǎn)換為數(shù)字信號保存到ADC數(shù)

2、據(jù)寄存器0中(ADCDAT0),然后ADCDAT0中的數(shù)據(jù)可以通過中斷或查詢的方式來訪問。 對于ADC的各寄存器的操作和注意事項請參閱數(shù)據(jù)手冊。上圖是mini2440上的ADC應(yīng)用實例,開發(fā)板通過一個10K的電位器(可變電阻)來產(chǎn)生電壓模擬信號,然后通過第一個通道(即:AIN0)將 模擬信號輸入ADC。三、實現(xiàn)步驟ADC設(shè)備在Linux中可以看做是簡單的字符設(shè)備,也可以當(dāng)做是一混雜設(shè)備(misc設(shè)備),這里我們就看做是misc設(shè)備來實現(xiàn)ADC的驅(qū)動。 注意:這里我們獲取AD轉(zhuǎn)換后的數(shù)據(jù)將采用中斷的方式,即當(dāng)AD轉(zhuǎn)換完成后產(chǎn)生AD中斷,在中斷服務(wù)程序中來讀取ADCDAT0的第0-9位的值(即AD

3、 轉(zhuǎn)換后的值)。1、建立驅(qū)動程序文件my2440_adc.c,實現(xiàn)驅(qū)動的初始化和退出,代碼如下:1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 13 /*定義了一個用來保存經(jīng)過虛擬映射后的內(nèi)存地址*/ 14 static void _iomem *adc_base; 15 16 /*保存從平臺時鐘隊列中獲取ADC的時鐘*/ 17 static struct clk *adc_clk; 18 1

4、9 /*申明并初始化一個信號量ADC_LOCK,對ADC資源進行互斥訪問*/ 20 DECLARE_MUTEX(ADC_LOCK); 21 22 static int _init adc_init(void) 23 24 int ret; 25 26 /*從平臺時鐘隊列中獲取ADC的時鐘,這里為什么要取得這個時鐘,因為ADC的轉(zhuǎn)換頻率跟時鐘有關(guān)。 27 系統(tǒng)的一些時鐘定義在arch/arm/plat-s3c24xx /s3c2410-clock.c中*/ 28 adc_clk = clk_get(NULL, adc); 29 if (!adc_clk) 30 31 /*錯誤處理*/ 32 pr

5、intk(KERN_ERR failed to find adc clock sourcen); 33 return -ENOENT; 34 35 36 /*時鐘獲取后要使能后才可以使用,clk_enable定義在arch/arm/plat-s3c/clock.c中*/ 37 clk_enable(adc_clk); 38 39 /*將ADC的IO端口占用的這段 IO空間映射到內(nèi)存的虛擬地址,ioremap定義在io.h中。 40 注意:IO空間要映射后才能使用,以后對虛擬地址的操作就是對IO空間的操作, S3C2410_PA_ADC41 是ADC控制器的基地址,定義在mach-s3c2410

6、/include/mach/map.h中,0x20是虛擬地址長度大小*/ 42 adc_base = ioremap(S3C2410_PA_ADC, 0x20); 43 if (adc_base = NULL) 44 45 /*錯誤處理*/ 46 printk(KERN_ERR Failed to remap register blockn); 47 ret = -EINVAL; 48 goto err_noclk; 49 50 51 /*把看ADC注冊成為misc設(shè)備,misc_register定義在miscdevice.h中adc_miscdev結(jié)構(gòu)體定義 52 及內(nèi)部接口函數(shù)在第步中講,

7、MISC_DYNAMIC_MINOR是次設(shè)備號,定義在miscdevice.h中*/ 53 ret = misc_register(&adc_miscdev); 54 if (ret) 55 56 /*錯誤處理*/ 57 printk(KERN_ERR cannot register miscdev on minor=%d (%d)n,58 MISC_DYNAMIC_MINOR, ret); 59 goto err_nomap; 60 61 62 printk(DEVICE_NAME initialized!n); 63 64 return 0; 65 66 /以下是上面錯誤處理的跳轉(zhuǎn)點 67

8、 err_noclk: 68 clk_disable(adc_clk); 69 clk_put(adc_clk); 70 71 err_nomap: 72 iounmap(adc_base); 73 74 return ret; 75 76 77 static void _exit adc_exit(void) 78 79 free_irq(IRQ_ADC, 1);/*釋放中斷*/ 80 iounmap(adc_base);/*釋放虛擬地址映射空間*/ 81 82 if (adc_clk)/*屏蔽和銷毀時鐘*/ 83 84 clk_disable(adc_clk); 85 clk_put(ad

9、c_clk); 86 adc_clk = NULL; 87 88 89 misc_deregister(&adc_miscdev);/*注銷misc設(shè)備*/ 90 91 92 /*導(dǎo)出信號量ADC_LOCK在觸摸屏驅(qū)動中使用,因為觸摸屏驅(qū)動和ADC驅(qū)動公用 93 相關(guān)的寄存器,為了不產(chǎn)生資源競態(tài),就用信號量來保證資源的互斥訪問*/ 94 EXPORT_SYMBOL(ADC_LOCK); 95 96 module_init(adc_init); 97 module_exit(adc_exit); 98 99 MODULE_LICENSE(GPL); 100 MODULE_AUTHOR(Huang

10、 Gang); 101 MODULE_DESCRIPTION(My2440 ADC Driver); 2、adc_miscdev結(jié)構(gòu)體定義及內(nèi)部各接口函數(shù)的實現(xiàn),代碼如下:102 #include 103 104 /*設(shè)備名稱*/ 105 #define DEVICE_NAME my2440_adc 106 107 /*定義并初始化一個等待隊列adc_waitq,對ADC資源進行阻塞訪問*/ 108 static DECLARE_WAIT_QUEUE_HEAD(adc_waitq); 109 110 /*用于標(biāo)識AD轉(zhuǎn)換后的數(shù)據(jù)是否可以讀取,0表示不可讀取*/ 111 static volat

11、ile int ev_adc = 0; 112 113 /*用于保存讀取的AD轉(zhuǎn)換后的值,該值在ADC中斷中讀取*/ 114 static int adc_data; 115 116 /*misc設(shè)備結(jié)構(gòu)體實現(xiàn)*/ 117 static struct miscdevice adc_miscdev = 118 119 .minor = MISC_DYNAMIC_MINOR, /*次設(shè)備號,定義在 miscdevice.h中,為255*/ 120 .name = DEVICE_NAME, /* 設(shè)備名稱*/ 121 .fops = &adc_fops, /*對ADC設(shè)備文件操作*/ 122 ; 1

12、23 124 /*字符設(shè)備的相關(guān)操作實現(xiàn)*/ 125 static struct file_operations adc_fops = 126 127 .owner = THIS_MODULE, 128 .open = adc_open, 129 .read = adc_read, 130 .release = adc_release, 131 ; 132 133 /*ADC設(shè)備驅(qū)動的打開接口函數(shù)*/ 134 static int adc_open(struct inode *inode, struct file *file) 135 136 int ret; 137 138 /*申請ADC中

13、斷服務(wù),這里使用的是共享中斷:IRQF_SHARED,為什么要使用共享中斷,因為在觸摸屏驅(qū)動中 139 也使用了這個中斷號。中斷服務(wù)程序為:adc_irq在下面實現(xiàn),IRQ_ADC是ADC的中斷號,這里注意: 140 申請中斷函數(shù)的最后一個參數(shù)一定不能為NULL,否則中斷申請會失敗,如果中斷服務(wù)程序中用不到這個 141 參數(shù),就隨便給個值就好了,我這里就給個1*/ 142 ret = request_irq(IRQ_ADC, adc_irq, IRQF_SHARED, DEVICE_NAME, 1); 143 if (ret) 144 145 /*錯誤處理*/ 146 printk(KERN_

14、ERR IRQ%d error %dn, IRQ_ADC, ret); 147 return -EINVAL; 148 149 150 return 0; 151 152 153 /*ADC中斷服務(wù)程序,該服務(wù)程序主要是從ADC數(shù)據(jù)寄存器中讀取AD轉(zhuǎn)換后的值*/ 154 static irqreturn_t adc_irq(int irq, void *dev_id) 155 156 /*保證了應(yīng)用程序讀取一次這里就讀取 AD轉(zhuǎn)換的值一次, 157 避免應(yīng)用程序讀取一次后發(fā)生多次中斷多次讀取AD轉(zhuǎn)換值*/ 158 if(!ev_adc) 159 160 /*讀取AD轉(zhuǎn)換后的值保存到全局變量ad

15、c_data 中,S3C2410_ADCDAT0定義在regs-adc.h中, 161 這里為什么要與上一個0x3ff,很簡單,因為AD轉(zhuǎn)換后的數(shù)據(jù)是保存在ADCDAT0的第0-9位, 162 所以與上0x3ff(即:1111111111)后就得到第0-9位的數(shù)據(jù),多余的位就都為0*/ 163 adc_data = readl(adc_base + S3C2410_ADCDAT0) & 0x3ff; 164 165 /*將可讀標(biāo)識為1,并喚醒等待隊列*/ 166 ev_adc = 1; 167 wake_up_interruptible(&adc_waitq); 168 169 170 ret

16、urn IRQ_HANDLED; 171 172 173 /*ADC設(shè)備驅(qū)動的讀接口函數(shù)*/ 174 static ssize_t adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos) 175 176 /*試著獲取信號量(即:加鎖)*/ 177 if (down_trylock(&ADC_LOCK) 178 179 return -EBUSY; 180 181 182 if(!ev_adc)/*表示還沒有AD轉(zhuǎn)換后的數(shù)據(jù),不可讀取*/ 183 184 if(filp-f_flags & O_NONBLOCK)

17、 185 186 /*應(yīng)用程序若采用非阻塞方式讀取則返回錯誤*/ 187 return -EAGAIN; 188 189 else/*以阻塞方式進行讀取*/ 190 191 /*設(shè)置ADC控制寄存器,開啟AD轉(zhuǎn)換*/ 192 start_adc(); 193 194 /*使等待隊列進入睡眠*/ 195 wait_event_interruptible(adc_waitq, ev_adc); 196 197 198 199 /*能到這里就表示已有AD轉(zhuǎn)換后的數(shù)據(jù),則標(biāo)識清0,給下一次讀做判斷用*/ 200 ev_adc = 0; 201 202 /*將讀取到的AD轉(zhuǎn)換后的值發(fā)往到上層應(yīng)用程序*/

18、 203 copy_to_user(buffer, (char *)&adc_data, sizeof(adc_data); 204 205 /*釋放獲取的信號量(即:解鎖)*/ 206 up(&ADC_LOCK); 207 208 return sizeof(adc_data); 209 210 211 /*設(shè)置ADC控制寄存器,開啟AD轉(zhuǎn)換*/ 212 static void start_adc(void) 213 214 unsigned int tmp; 215 216 tmp = (1 14) | (255 6) | (0 3);/* 0 1 00000011 000 0 0 0 *

19、/ 217 writel(tmp, adc_base + S3C2410_ADCCON); /*AD預(yù)分頻器使能、模擬輸入通道設(shè)為AIN0*/ 218 219 tmp = readl(adc_base + S3C2410_ADCCON); 220 tmp = tmp | (1 0); /* 0 1 00000011 000 0 0 1 */ 221 writel(tmp, adc_base + S3C2410_ADCCON); /*AD轉(zhuǎn)換開始*/ 222 223 224 /*ADC設(shè)備驅(qū)動的關(guān)閉接口函數(shù)*/ 225 static int adc_release(struct inode *inode, struct file *filp) 226 227 return 0; 228 注意:在上面實現(xiàn)的每步中,為了讓代碼邏輯更加有條理和容易理解,就沒有考慮代碼的順序,比如函數(shù)要先定義后調(diào)用。如果要編譯此代碼,請嚴(yán)格按照C 語言的規(guī)范來調(diào)整代碼的順序。3、編寫用戶應(yīng)用程序測試my2440_adc驅(qū)動。建立應(yīng)用程序adc_test.c,代碼如下:229 #include

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論