精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

從0學(xué)ARM,基于Cortex-A9 ADC裸機(jī)驅(qū)動詳解

系統(tǒng) Linux
在嵌入式開發(fā)中,ADC應(yīng)用比較頻繁,本文主要講解ADC的基本原理以及如何編寫基于ARM的裸機(jī)程序和基于Linux的驅(qū)動程序。

 前言

在嵌入式開發(fā)中,ADC應(yīng)用比較頻繁,本文主要講解ADC的基本原理以及如何編寫基于ARM的裸機(jī)程序和基于Linux的驅(qū)動程序。

ARM架構(gòu):Cortex-A9 Linux內(nèi)核:3.14

在講述ADC之前,我們需要先了解什么是模擬信號和數(shù)字信號。

模擬信號

主要是與離散的數(shù)字信號相對的連續(xù)的信號。模擬信號分布于自然界的各個角落,如每天溫度的變化,而數(shù)字信號是人為的抽象出來的在時間上不連續(xù)的信號。電學(xué)上的模擬信號是主要是指幅度和相位都連續(xù)的電信號,此信號可以被模擬電路進(jìn)行各種運(yùn)算,如放大,相加,相乘等。

模擬信號是指用連續(xù)變化的物理量表示的信息,其信號的幅度,或頻率,或相位隨時間作連續(xù)變化,如目前廣播的聲音信號,或圖像信號等。

如下圖所示從上到下一次是正弦波、 調(diào)幅波、 阻尼震蕩波、 指數(shù)衰減波 。


數(shù)字信號

數(shù)字信號指幅度的取值是離散的,幅值表示被限制在有限個數(shù)值之內(nèi)。二進(jìn)制碼就是一種數(shù)字信號。二進(jìn)制碼受噪聲的影響小,易于有數(shù)字電路進(jìn)行處理,所以得到了廣泛的應(yīng)用。

數(shù)字信號:高清數(shù)字電視,MP3,JPG,PNG文件等等。


優(yōu)點(diǎn):

1. 抗干擾能力強(qiáng)、無噪聲積累

在模擬通信中,為了提高信噪比,需要在信號傳輸過程中及時對衰減的傳輸信號進(jìn)行放大,信號在傳輸過程中不可避免地疊加上的噪聲也被同時放大。

隨著傳輸距離的增加,噪聲累積越來越多,以致使傳輸質(zhì)量嚴(yán)重惡化。

對于數(shù)字通信,由于數(shù)字信號的幅值為有限個離散值(通常取兩個幅值),在傳輸過程中雖然也受到噪聲的干擾,但當(dāng)信噪比惡化到一定程度時,

即在適當(dāng)?shù)木嚯x采用判決再生的方法,再生成沒有噪聲干擾的和原發(fā)送端一樣的數(shù)字信號,所以可實(shí)現(xiàn)長距離高質(zhì)量的傳輸。

2. 便于加密處理

信息傳輸?shù)陌踩院捅C苄栽絹碓街匾瑪?shù)字通信的加密處理的比模擬通信容易得多,以話音信號為例,經(jīng)過數(shù)字變換后的信號可用簡單的數(shù)字邏輯運(yùn)算進(jìn)行加密、解密處理。

3. 便于存儲、處理和交換

數(shù)字通信的信號形式和計算機(jī)所用信號一致,都是二進(jìn)制代碼,因此便于與計算機(jī)聯(lián)網(wǎng),也便于用計算機(jī)對數(shù)字信號進(jìn)行存儲、處理和交換,

可使通信網(wǎng)的管理、維護(hù)實(shí)現(xiàn)自動化、智能化。

4. 設(shè)備便于集成化、微型

數(shù)字通信采用時分多路復(fù)用,不需要體積較大的濾波器。設(shè)備中大部分電路是數(shù)字電路,可用大規(guī)模和超大規(guī)模集成電路實(shí)現(xiàn),因此體積小、功耗低。

5. 便于構(gòu)成綜合數(shù)字網(wǎng)和綜合業(yè)務(wù)數(shù)字網(wǎng)

采用數(shù)字傳輸方式,可以通過程控數(shù)字交換設(shè)備進(jìn)行數(shù)字交換,以實(shí)現(xiàn)傳輸和交換的綜合。

另外,電話業(yè)務(wù)和各種非話業(yè)務(wù)都可以實(shí)現(xiàn)數(shù)字化,構(gòu)成綜合業(yè)務(wù)數(shù)字網(wǎng)。

6. 占用信道頻帶較寬

一路模擬電話的頻帶為4kHz帶寬,一路數(shù)字電話約占64kHz,這是模擬通信目前仍有生命力的主要原因。隨著寬頻帶信道(光纜、數(shù)字微波)的大量利用(一對光纜可開通幾千路電話)以及數(shù)字信號處理技術(shù)的發(fā)展(可將一路數(shù)字電話的數(shù)碼率由64kb/s壓縮到32kb/s甚至更低的數(shù)碼率),數(shù)字電話的帶寬問題已不是主要問題了。

常用的數(shù)字信號編碼有不歸零(NRZ)編碼、 曼徹斯特(Manchester)編碼和差分曼徹斯特(Differential Manchester)編碼。


數(shù)字信號與模擬信號的轉(zhuǎn)化

模擬信號和數(shù)字信號之間可以相互轉(zhuǎn)換:模擬信號一般通過PCM脈碼調(diào)制(Pulse Code Modulation)方法量化為數(shù)字信號,

即讓模擬信號的不同幅度分別對應(yīng)不同的二進(jìn)制值,例如采用8位編碼可將模擬信號量化為2^8=256個量級,實(shí)用中常采取24位或30位編碼;

數(shù)字信號一般通過對載波進(jìn)行移相(Phase Shift)的方法轉(zhuǎn)換為模擬信號。計算機(jī)、計算機(jī)局域網(wǎng)與城域網(wǎng)中均使用二進(jìn)制數(shù)字信號,

目前在計算機(jī)廣域網(wǎng)中實(shí)際傳送的則既有二進(jìn)制數(shù)字信號,也有由數(shù)字信號轉(zhuǎn)換而得的模擬信號。但是更具應(yīng)用發(fā)展前景的是數(shù)字信號。

PCM脈沖編碼調(diào)制

脈沖編碼調(diào)制就是把一個時間連續(xù),取值連續(xù)的模擬信號變換成時間離散,取值離散的數(shù)字信號后在信道中傳輸。

脈沖編碼調(diào)制就是對模擬信號先抽樣,再對樣值幅度量化, 編碼的過程。


抽樣:

就是對模擬信號進(jìn)行周期性掃描,把時間上連續(xù)的信號變成時間上離散的信號。

該模擬信號經(jīng)過抽樣后還應(yīng)當(dāng)包含原信號中所有信息,也就是說能無失真的恢復(fù)原模擬信號。

量化:

就是把經(jīng)過抽樣得到的瞬時值將其幅度離散,即用一組規(guī)定的電平,把瞬時抽樣值用最接近的電平值來表示,通常是用二進(jìn)制表示。

編碼:

就是用一組二進(jìn)制碼組來表示每一個有固定電平的量化值。然而,實(shí)際上量化是在編碼過程中同時完成的,故編碼過程也稱為模/數(shù)變換,可記作A/D。

ADC

ADC,Analog-to-Digital Converter的縮寫,指模/數(shù)轉(zhuǎn)換器或者模數(shù)轉(zhuǎn)換器。是指將連續(xù)變化的模擬信號轉(zhuǎn)換為離散的數(shù)字信號的器件。真實(shí)世界的模擬信號,例如溫度、壓力、聲音或者圖像等,需要轉(zhuǎn)換成更容易儲存、處理和發(fā)射的數(shù)字形式。模/數(shù)轉(zhuǎn)換器可以實(shí)現(xiàn)這個功能,在各種不同的產(chǎn)品中都可以找到它的身影。

ADC最早用于對無線信號向數(shù)字信號轉(zhuǎn)換。如電視信號,長短播電臺發(fā)接收等。

與之相對應(yīng)的DAC,Digital-to-Analog Converter,它是ADC模數(shù)轉(zhuǎn)換的逆向過程。

現(xiàn)在市場上的電子產(chǎn)品都集成了傳感器,傳感器要采集數(shù)據(jù),他的內(nèi)部結(jié)構(gòu)里就一定要用到ADC,常見的傳感器如下:

溫濕度:溫度傳感器,DHT11聲音:音頻芯片進(jìn)行錄音,WM8906圖像:索尼IMX386/IMX283傳感器

Exynos4412 A/D轉(zhuǎn)換器

三星的Exynos4412模塊結(jié)構(gòu)圖如下所示:


Adc控制器集成在exynos4412 soc中,控制器內(nèi)部有一根中斷線連接到中斷控制器combiner,然后路由到GIC(Generic Interrupt Controller),滑動變阻器連接到adc控制器的通道3。

ADC控制器

參考《Exynos 4412 SCP》 的datasheet。ADC控制器是10位或12位CMOS再循環(huán)式模擬數(shù)字轉(zhuǎn)換器,它具有10個通道輸入,并可將模擬量轉(zhuǎn)換至10位或12位二進(jìn)制數(shù)。5Mhz A/D 轉(zhuǎn)換時鐘,最大1Msps的轉(zhuǎn)換速度。A/D轉(zhuǎn)換具備片上采樣保持功能,同時也支持待機(jī)工作模式。

ADC接口包括如下特性。

  • 10bit/12bit輸出位可選。
  • 微分誤差 1.0LSB。
  • 積分誤差 2.0LSB。
  • 最大轉(zhuǎn)換速率5Msps.
  • 功耗少,電壓輸入1.8V。
  • 電壓輸入范圍 0~1.8V。
  • 支持偏上樣本保持功能。
  • 通用轉(zhuǎn)換模式。

模塊圖

4412 A/D轉(zhuǎn)換器的控制器接口框圖如下:


原理我們并不需要關(guān)注,知道即可。

通道選擇


由上圖可知,A/D控制器一共有4個通道,通用寄存器地址為0x126c0000。

A/D控制器寄存器

對ADC控制器的操作主要是通過配置寄存器來實(shí)現(xiàn)的,查看datasheet,必須掌握寄存器的使用。以下是A/D控制器寄存器匯總。


1、A/D控制寄存器ADCCON


  1. RES     : 選擇A/D轉(zhuǎn)換精度,0:劃分成1024份  1:劃分成4096份 
  2.   ECFLG   :轉(zhuǎn)換是否結(jié)束  0:轉(zhuǎn)換中  1:轉(zhuǎn)換完畢;對于輪詢模式需要根據(jù)該位判斷數(shù)據(jù)是否轉(zhuǎn)換完畢。 
  3.   PRSCEN:A/D轉(zhuǎn)換預(yù)分頻是否使能 
  4.   PRSCVL:預(yù)分頻的值,轉(zhuǎn)換公式見下面 
  5.   STANDBY:待機(jī)模式  0:正常工作模式 1:待機(jī)模式。處于待機(jī)模式時要將PRSCEN設(shè)置為0 
  6.   READ_START: A/D轉(zhuǎn)換由讀操作觸發(fā),設(shè)置為1后,每次讀取A/D值的操作都會觸發(fā)一次A/D轉(zhuǎn)換。 
  7.   ENABLE_START: 單次開啟A/D轉(zhuǎn)換,轉(zhuǎn)換完畢后該位自動清零,當(dāng)READ_START設(shè)置為1的時候,該位無效。 

通常設(shè)置值為(1 << 16 | 1 << 14 | 99 <<6 | 1 << 1)。

2、A/D轉(zhuǎn)換數(shù)據(jù)寄存器ADCDAT0


注意該寄存器的值只有低12位有效。

3、A/D清中斷寄存器CLRINTADC


黃色部分可知,中斷例程負(fù)責(zé)清中斷,中斷結(jié)束后寫入任意值就可以清中斷。

4、A/D通道選擇寄存器ADCMUX


每次操作都要先設(shè)置通道,因?yàn)?4個通道是共用同一套寄存器,如果有其他任務(wù)也在使用A/D,就會產(chǎn)生混亂。在此我們選擇通道3,置3即可。

5、ADC中斷ID

參見9.2.2GIC Interrupt Table


由此可知,ADC中斷號對應(yīng)的SPI值是10,inturrupt ID 為42。對于終端查詢方式和編寫終端的驅(qū)動需要知道SPI id和inturrupt ID,后面講解基于Linux驅(qū)動還會再分析設(shè)備樹節(jié)點(diǎn)如何填寫。

6、Combiner中斷控制器


combiner的配置寄存器:IMSRn、IECRn、ISERn、ISTRn,類似于GPIO 對中斷源分組。只有中斷模式才需要考慮combiner中斷控制器的操作。

7、Combiner分組

參考章節(jié):10.2.1Interrupt Combiner Table 10-1Interrupt Groups of Interrupt Combiner


可見ADC在INTG10,即第10組。

8、Combiner IESR2

參考章節(jié):10.4.2.9IESR2


如果要用中斷模式設(shè)置為1即可。

9、Combiner IECR2

參考章節(jié):10.4.2.10IECR2


此處用于關(guān)閉中斷,采用默認(rèn)值即可,注意,如果設(shè)置了1,那么中斷功能就關(guān)閉了。

10、A/D轉(zhuǎn)換的轉(zhuǎn)換時間計算

例如:PCLK為100MHz,PRESCALER = 65 ;所有10位轉(zhuǎn)換時間為

100MHz/(99+1) = 1MHz

轉(zhuǎn)化時間為1/(1MHz/5 cycles) = 5us。

完成一次A/D轉(zhuǎn)換需要5個時鐘周期。A/D轉(zhuǎn)換器的最大工作時鐘為5MHz,所以最大采樣率可以達(dá)到1Mit/s.

電路連接圖


由該電路圖可知,外設(shè)是一個滑動變阻器,根據(jù)接觸點(diǎn)的不同,會導(dǎo)致輸入電壓的模擬值不同。連接的A/D控制器通道為3。該電路利用一個電位計輸出電壓到4412的AIN3管腳。輸入的電壓范圍為0~1.8V。

ADC裸機(jī)開發(fā)程序?qū)嵗?/span>

ADC數(shù)據(jù)的讀取通常由2種方法:中斷模式、輪訓(xùn)模式。

輪訓(xùn)模式

輪詢模式讀取數(shù)據(jù)步驟如下:

1.要讀取數(shù)據(jù)首先向ADC寄存器ADCCON的bit:1寫1,發(fā)送轉(zhuǎn)換命令,采用讀-啟動模式來開啟轉(zhuǎn)換。

2.當(dāng)ADC控制器轉(zhuǎn)換完畢會將ADCCON的bit:15設(shè)置為1,

3.輪詢檢測ADCCON的bit:15是否設(shè)置為1,如果設(shè)置為1,就讀走數(shù)據(jù),否則繼續(xù)等待。

這種方式比較占用CPU資源。

注:這里使用讀-啟動模式

  1. /***********************ADC ******************/ 
  2. #define   ADC_CFG  __REG(0x10010118) 
  3. #define  ADCCON  __REG(0x126C0000) 
  4. #define  ADCDLY  __REG(0x126C0008) 
  5. #define  ADCDAT  __REG(0x126C000C) 
  6. #define  CLRINTADC __REG(0x126C0018) 
  7. #define  ADCMUX  __REG(0x126C001C) 
  8.  
  9. #include "exynos_4412.h" 
  10. #include "pwm.h" 
  11. #include "uart.h" 
  12.  
  13. unsigned char table[10] = {'0','1','2','3','4','5','6','7','8','9'}; 
  14.  
  15. void mydelay_ms(int time
  16.   int i, j; 
  17.  
  18.   while(time--) 
  19.   { 
  20.     for (i = 0; i < 5; i++) 
  21.     for (j = 0; j < 514; j++); 
  22.   } 
  23.  
  24. adc_init(int temp
  25.   ADCCON = (1 << 16 | 1 << 14 | 99 <<6 | 1 << 1); 
  26.   ADCMUX = 3; 
  27.   temp = ADCDAT & 0xfff; 
  28.  
  29. /* 
  30.  *  裸機(jī)代碼,不同于LINUX 應(yīng)用層, 一定加循環(huán)控制 
  31.  */ 
  32.  
  33. int main (void) 
  34.   unsigned char bit4,bit3,bit2,bit1; 
  35.   unsigned int temp = 0; 
  36.    
  37.   uart_init(); 
  38.   adc_init(temp); 
  39.   puts("開始轉(zhuǎn)換\n"); 
  40.  
  41.   while(1) 
  42.   { 
  43.     while(!(ADCCON & 0x8000)); 
  44.     temp = ADCDAT & 0xfff; 
  45.     printf("U = %d\n",temp); 
  46.     temp = 1.8 * 1000 * temp/0xfff; 
  47.     bit4 = temp /1000; 
  48.     putc(table[bit4]); 
  49.     bit3 = (temp % 1000)/100?; 
  50.     putc(table[bit3]); 
  51.     bit2 = ((temp % 1000)%100)/10; 
  52.     putc(table[bit2]); 
  53.     bit1 = ((temp % 1000)%100)%10; 
  54.     putc(table[bit1]); 
  55.     puts("mV"); 
  56.     putc('\n'); 
  57.     mydelay_ms(1000); 
  58.   } 
  59.   return 0; 

中斷模式

中斷模式讀取數(shù)據(jù)步驟如下:

1.要讀取數(shù)據(jù)首先向ADC寄存器ADCCON的bit:0寫1,發(fā)送轉(zhuǎn)換命令;

2.當(dāng)ADC控制器轉(zhuǎn)換完畢會通過中斷線向CPU發(fā)送中斷信號;

3.在中斷處理函數(shù)中,讀走數(shù)據(jù),并清中斷.

注:中斷對應(yīng)寄存器的設(shè)置,后續(xù)會更新對應(yīng)的文檔。

  1. void do_irq(void) 
  2.        int irq_num; 
  3.  
  4.        irq_num = CPU0.ICCIAR &0x3ff; 
  5.        switch(irq_num) 
  6.        { 
  7.          case 42: 
  8.               adc_num = ADCDAT&0xfff; 
  9.               printf("adc = %d\n",adc_num); 
  10.               CLRINTADC = 0; 
  11.        //    IECR2 = IECR2 | (1 << 19);               打開的話只能讀取一次, 
  12.               //42/32 
  13.               ICDICPR.ICDICPR1 = ICDICPR.ICDICPR1 | (1 << 10);【清GIC中斷標(biāo)志位類似于 ICDISER】 
  14.               break; 
  15.        } 
  16.        CPU0.ICCEOIR = CPU0.ICCEOIR & (~0x3ff) | irq_num; 
  17. void adc_init(void) 
  18. {    //12bit   使能分頻       分頻值                 手動 
  19.        ADCCON = (1 << 16) | (1 << 14) | (0xff << 6) | (1 << 0); 
  20.        ADCMUX = 3; 
  21. void adcint_init(void) 
  22.        IESR2 = IESR2 | (1 << 19); 
  23.        ICDDCR = 1;    //使能分配器 
  24.        //42/32 
  25.        ICDISER.ICDISER1 = ICDISER.ICDISER1 | (1 << 10);//使能相應(yīng)中斷到分配器 
  26.        ICDIPTR.ICDIPTR10 = ICDIPTR.ICDIPTR10 &(~(0xff << 16)) | (0x1 << 16);//發(fā)送到相應(yīng)CPU接口 
  27.        CPU0.ICCPMR = 255;//設(shè)置中斷屏蔽優(yōu)先級 
  28.        CPU0.ICCICR = 1;  //全局使能開關(guān) 
  29. int main (void) 
  30. {  
  31.   adc_init(); 
  32.        adcint_init(); 
  33.        while(1) 
  34.        { 
  35.               ADCCON = ADCCON | 1; 
  36.               delay_ms(1000); 
  37.        } 
  38.    return 0; 

基于Linux驅(qū)動編寫

設(shè)備樹

編寫基于Linux的ADC外設(shè)驅(qū)動,首先需要編寫設(shè)備樹節(jié)點(diǎn)信息,在裸機(jī)程序中,我們只用到了寄存器地址,而編寫基于Linux的驅(qū)動,我們需要用到中斷功能。所以編寫設(shè)備樹節(jié)點(diǎn)需要知道ADC要用到的硬件資源主要包括:寄存器資源和中斷資源。

關(guān)于中斷的使用我們在后續(xù)文章中會繼續(xù)分析,現(xiàn)在我們只需要知道中斷信息如何填寫即可。

ADC寄存器信息填寫

在這里插入圖片描述

由上可知,寄存器基地址為0x126c0000,其他寄存器只需要根據(jù)基地址做偏移即可獲取,所以設(shè)備樹的reg屬性信息如下:

  1. reg = <0x126C0000 0x20>; 

ADC中斷信息填寫

描述中斷連接需要四個屬性:父節(jié)點(diǎn)提供以下信息

  1. interrupt-controller - 一個空的屬性定義該節(jié)點(diǎn)作為一個接收中斷信號的設(shè)備。 
  2. interrupt-cells      - 這是一個中斷控制器節(jié)點(diǎn)的屬性。它聲明了該中斷控制器的中斷指示符中【interrupts】 cell 的個數(shù)(類似于 #address-cells 和 #size-cells)。 

子節(jié)點(diǎn)描述信息

  1. interrupt-parent - 這是一個設(shè)備節(jié)點(diǎn)的屬性,包含一個指向該設(shè)備連接的中斷控制器的 phandle。那些沒有 interrupt-parent 的節(jié)點(diǎn)則從它們的父節(jié)點(diǎn)中繼承該屬性。 
  2. interrupts       - 一個設(shè)備節(jié)點(diǎn)屬性,包含一個中斷指示符的列表,對應(yīng)于該設(shè)備上的每個中斷輸出信號。【設(shè)備的中斷信息放在該屬性中】 

父節(jié)點(diǎn)


首先我們必須知道ADC控制器的中斷線的父節(jié)點(diǎn):

由上圖可知ADC控制器位于soc內(nèi),4個ADC通道公用一根中斷線,該中斷線連接在combiner上,所以我們需要查找到combiner這個父節(jié)點(diǎn)的說明:

進(jìn)入設(shè)備樹文件所在目錄:arch\arm\boot\dts

  1. grep combiner *.* -n 

經(jīng)過篩選得到以下信息,


因?yàn)槲覀兪褂玫陌遄邮莈xynos4412,而exynos系列通用的平臺設(shè)備樹文件是exynos4.dtsi,查看該文件:


上圖列舉了combiner控制器的詳細(xì)信息:

  1. interrupt-cells ; 
  2. interrupt-cells =<2>; 

所以ADC控制器中斷控制器的interrupts屬性應(yīng)該有兩個cell。

interrupts屬性填寫

而設(shè)備的中斷信息填寫方式由內(nèi)核的以下文檔提供:

  1. Documentation\devicetree\bindings\interrupt-controller\interrupts.txt 

  1. 69. b) two cells 
  2.  70.  ------------ 
  3.  71.  The #interrupt-cells property is set to 2 and the first cell 72. defines the 
  4.  73.  index of the interrupt within the controller, while the second cell is used 
  5.  74.  to specify any of the following flags: 
  6.  75.    - bits[3:0] trigger type and level flags 
  7.  76.        1 = low-to-high edge triggered 
  8.  77.        2 = high-to-low edge triggered 
  9.  78.        4 = active high level-sensitive 
  10.  79.        8 = active low level-sensitive 

由以上信息可知,中斷的第一個cell是該中斷源所在中斷控制器的index,第二個cell表示中斷的觸發(fā)方式

*. 1:上升沿觸發(fā) *. 2:下降沿觸發(fā) *. 3:高電平觸發(fā) *. 4:低電平觸發(fā)

那么index應(yīng)該是多少呢?

詳見datasheet的9.2.2 GIC Interrupt Table 節(jié):


此處我們應(yīng)該是填寫左側(cè)的SPI ID:10 還是填寫INTERRUPT ID:42呢?

此處我們可以參考LCD節(jié)點(diǎn)的interrupts填寫方法:

通過查找父節(jié)點(diǎn)為combiner的設(shè)備信息。

繼續(xù)grep combiner . -n


由此可見lcd這個設(shè)備的interrupts屬性index值是11,所以可知ADC控制器中斷線的index是10。中斷信息如下:

  1. interrupt-parent = <&combiner>; 
  2. interrupts = <10 3>; 

ADC外設(shè)設(shè)備樹信息

  1. fs4412-adc{ 
  2.     compatible = "fs4412,adc"
  3.     reg = <0x126C0000 0x20>; 
  4.     interrupt-parent = <&combiner>; 
  5.     interrupts = <10 3>; 
  6. }; 

本文默認(rèn)大家會使用設(shè)備樹,不知道如何使用設(shè)備樹的朋友,后續(xù)會開一篇單獨(dú)講解設(shè)備樹。

【注意】在不支持設(shè)備樹內(nèi)核中,以Cortex-A8為例,中斷信息填寫在以下文件中

  1. 內(nèi)部中斷,Irqs.h (arch\arm\mach-s5pc100\include\mach) 
  2. 外部中斷在Irqs.h (arch\arm\plat-s5p\include\plat) 

ADC屬于內(nèi)部中斷,位于arch\arm\mach-s5pc100\include\mach\Irqs.h中。

寄存器信息填寫在以下位置:

  1. arch\arm\mach-s5pc100\Mach-smdkc100.c 

  1. static struct platform_device *smdkc100_devices[] __initdata = { 
  2.   &s3c_device_adc, 
  3.   &s3c_device_cfcon, 
  4.   &s3c_device_i2c0, 
  5.   &s3c_device_i2c1, 
  6.   &s3c_device_fb, 
  7.   &s3c_device_hsmmc0, 
  8.   &s3c_device_hsmmc1, 
  9.   &s3c_device_hsmmc2, 
  10.   &samsung_device_pwm, 
  11.   &s3c_device_ts, 
  12.   &s3c_device_wdt, 
  13.   &smdkc100_lcd_powerdev, 
  14.   &s5pc100_device_iis0, 
  15.   &samsung_device_keypad, 
  16.   &s5pc100_device_ac97, 
  17.   &s3c_device_rtc, 
  18.   &s5p_device_fimc0, 
  19.   &s5p_device_fimc1, 
  20.   &s5p_device_fimc2, 
  21.   &s5pc100_device_spdif, 
  22. }; 

結(jié)構(gòu)體s3c_device_adc定義在以下文件:

  1. \arch\arm\plat-samsung\Devs.c 

  1. #ifdef CONFIG_PLAT_S3C24XX 
  2. static struct resource s3c_adc_resource[] = { 
  3.   [0] = DEFINE_RES_MEM(S3C24XX_PA_ADC, S3C24XX_SZ_ADC), 
  4.   [1] = DEFINE_RES_IRQ(IRQ_TC), 
  5.   [2] = DEFINE_RES_IRQ(IRQ_ADC), 
  6. }; 
  7.  
  8. struct platform_device s3c_device_adc = { 
  9.   .name    = "s3c24xx-adc"
  10.   .id    = -1, 
  11.   .num_resources  = ARRAY_SIZE(s3c_adc_resource), 
  12.   .resource  = s3c_adc_resource, 
  13. }; 
  14. #endif /* CONFIG_PLAT_S3C24XX */ 
  15.  
  16. #if defined(CONFIG_SAMSUNG_DEV_ADC) 
  17. static struct resource s3c_adc_resource[] = { 
  18.   [0] = DEFINE_RES_MEM(SAMSUNG_PA_ADC, SZ_256), 
  19.   [1] = DEFINE_RES_IRQ(IRQ_TC), 
  20.   [2] = DEFINE_RES_IRQ(IRQ_ADC), 
  21. }; 
  22.  
  23. struct platform_device s3c_device_adc = { 
  24.   .name    = "samsung-adc"
  25.   .id    = -1, 
  26.   .num_resources  = ARRAY_SIZE(s3c_adc_resource), 
  27.   .resource  = s3c_adc_resource, 
  28. }; 
  29. #endif /* CONFIG_SAMSUNG_DEV_ADC */ 

由代碼可知,平臺驅(qū)動對應(yīng)的platform_device具體內(nèi)容由宏CONFIG_PLAT_S3C24XX、CONFIG_SAMSUNG_DEV_ADC來控制。驅(qū)動編寫架構(gòu)和流程如下

  1. read() 
  2.        1、向adc設(shè)備發(fā)送要讀取的命令 
  3.           ADCCON    1<<0 | 1<<14 | 0X1<<16 | 0XFF<<6 
  4.        2、讀取不到數(shù)據(jù)就休眠 
  5.             wait_event_interruptible(); 
  6.        3、等待被喚醒讀數(shù)據(jù) 
  7.           havedata = 0; 
  8. adc_handler() 
  9.        1、清中斷 ADC使用中斷來通知轉(zhuǎn)換數(shù)據(jù)完畢的 
  10.        2、狀態(tài)位置位; 
  11.             havedata=1; 
  12.        3、喚醒阻塞進(jìn)程 
  13.             wake_up() 
  14. probe() 
  15.       1、讀取中斷號,注冊中斷處理函數(shù) 
  16.       2、讀取寄存器的地址,ioremap 
  17.       3、字符設(shè)備的操作 

驅(qū)動需要首先捕獲中斷信號后再去寄存器讀取相應(yīng)的數(shù)據(jù),在ADC控制器沒有準(zhǔn)備好數(shù)據(jù)之前,應(yīng)用層需要阻塞讀取數(shù)據(jù),所以在讀取數(shù)據(jù)的函數(shù)中,需要借助等待隊列來實(shí)現(xiàn)驅(qū)動對應(yīng)用進(jìn)程的阻塞。驅(qū)動程序

驅(qū)動程序?qū)拇嫫鞯牟僮鲄⒖悸銠C(jī)程序,只是基地址需要通過ioremap()做映射,對寄存器的讀寫操作需要用readl、writel。

driver.c

  1. #include <linux/module.h> 
  2. #include <linux/device.h> 
  3. #include <linux/platform_device.h> 
  4. #include <linux/interrupt.h> 
  5. #include <linux/fs.h> 
  6. #include <linux/wait.h> 
  7. #include <linux/sched.h> 
  8. #include <asm/uaccess.h> 
  9. #include <asm/io.h> 
  10. static int major = 250; 
  11.   
  12.   
  13. static wait_queue_head_t wq; 
  14. static int have_data = 0; 
  15. static int adc; 
  16. static struct resource *res1; 
  17. static struct resource *res2; 
  18. static void *adc_base; 
  19.   
  20. #define ADCCON 0x0000 
  21. #define ADCDLY 0x0008 
  22. #define ADCDAT 0x000C 
  23. #define CLRINTADC 0x0018 
  24. #define ADCMUX 0x001C 
  25.   
  26.   
  27. static  irqreturn_t adc_handler(int irqno, void *dev) 
  28.   have_data = 1; 
  29.   
  30.   printk("11111\n"); 
  31.   /*清中斷*/ 
  32.   writel(0x12,adc_base + CLRINTADC); 
  33.   wake_up_interruptible(&wq); 
  34.   return IRQ_HANDLED; 
  35. static int adc_open (struct inode *inod, struct file *filep) 
  36.   
  37.   return 0; 
  38. static ssize_t adc_read(struct file *filep, char __user *buf, size_t len, loff_t *pos) 
  39.     writel(0x3,adc_base + ADCMUX); 
  40.   writel(1<<0 | 1<<14 | 0X1<<16 | 0XFF<<6 ,adc_base +ADCCON ); 
  41.   
  42.   wait_event_interruptible(wq, have_data==1); 
  43.   
  44.   /*read data*/ 
  45.   adc = readl(adc_base+ADCDAT)&0xfff; 
  46.    
  47.   if(copy_to_user(buf,&adc,sizeof(int))) 
  48.   { 
  49.     return -EFAULT; 
  50.   } 
  51.   have_data = 0; 
  52.   return len; 
  53. static  int adc_release(struct inode *inode, struct file *filep) 
  54.   return 0; 
  55. static struct file_operations  adc_ops = 
  56.   .open = adc_open, 
  57.   .release = adc_release, 
  58.   .read = adc_read, 
  59. }; 
  60.   
  61.   
  62. static int hello_probe(struct platform_device *pdev) 
  63.   int ret; 
  64.   printk("match 0k \n"); 
  65.   
  66.   res1 = platform_get_resource(pdev,IORESOURCE_IRQ, 0); 
  67.     res2 = platform_get_resource(pdev,IORESOURCE_MEM, 0); 
  68.       
  69.   ret = request_irq(res1->start,adc_handler,IRQF_DISABLED,"adc1",NULL); 
  70.       adc_base = ioremap(res2->start,res2->end-res2->start); 
  71.   
  72.   register_chrdev( major, "adc", &adc_ops); 
  73.   init_waitqueue_head(&wq); 
  74.    
  75.   return 0; 
  76. static int hello_remove(struct platform_device *pdev) 
  77.   free_irq(res1->start,NULL); 
  78.   free_irq(res2->start,NULL);   
  79.   unregister_chrdev( major, "adc"); 
  80.   return 0; 
  81.   
  82. static struct of_device_id adc_id[]= 
  83.   {.compatible = "fs4412,adc" }, 
  84. }; 
  85.   
  86. static struct platform_driver hello_driver= 
  87.    
  88.   .probe = hello_probe, 
  89.   .remove = hello_remove, 
  90.   .driver ={ 
  91.     .name = "bigbang"
  92.     .of_match_table = adc_id, 
  93.   }, 
  94. }; 
  95.   
  96. static int hello_init(void) 
  97.   printk("hello_init"); 
  98.   return platform_driver_register(&hello_driver); 
  99. static void hello_exit(void) 
  100.   platform_driver_unregister(&hello_driver); 
  101.   printk("hello_exit \n"); 
  102.   return
  103. MODULE_LICENSE("GPL"); 
  104. module_init(hello_init); 
  105. module_exit(hello_exit); 

測試程序

test.c

  1. #include <sys/types.h> 
  2. #include <sys/stat.h> 
  3. #include <fcntl.h> 
  4. #include <stdio.h> 
  5.   
  6. main() 
  7.   int fd,len; 
  8.   int adc; 
  9.   fd = open("/dev/hello",O_RDWR); 
  10.   if(fd<0) 
  11.   { 
  12.     perror("open fail \n"); 
  13.     return ; 
  14.   } 
  15.   
  16.   while(1) 
  17.   { 
  18.     read(fd,&adc,4); 
  19.     printf("adc%0.2f V \n",(1.8*adc)/4096); 
  20.   } 
  21.   
  22.   close(fd); 

 

 

責(zé)任編輯:姜華 來源: 一口Linux
相關(guān)推薦

2021-01-08 12:06:59

WDT定時裝置

2020-12-22 11:54:42

C語言Cortex-A9LED匯編

2021-01-26 06:15:42

Cortex-A9 R嵌入式系統(tǒng)啟動代碼

2021-01-19 19:32:01

Cortex-A9 R嵌入式系統(tǒng)i2c 外設(shè)

2020-12-30 15:17:25

Cortex-A9UARTprintf函數(shù)

2021-01-06 05:42:42

Cortex-A9 R嵌入式系統(tǒng) RTC

2020-12-11 09:05:04

ARMMDKGNU

2021-01-13 11:51:25

ARM位置無關(guān)碼

2020-12-10 08:13:15

ARM架構(gòu) 嵌入式

2021-05-25 11:50:32

ARMuboot網(wǎng)絡(luò)協(xié)議棧

2022-10-31 07:33:05

Javafor循環(huán)

2022-10-30 10:14:43

Java循環(huán)語句

2022-09-30 07:32:48

循環(huán)while循環(huán)體

2022-11-26 00:34:57

數(shù)組Java程序

2022-09-22 07:31:14

Java變量計算

2015-02-04 19:13:48

ARMCortex-A 72

2022-09-30 07:32:39

架構(gòu)

2022-09-16 07:32:15

編程計算機(jī)命令

2022-10-28 07:38:06

Javawhile循環(huán)

2023-03-20 16:21:26

ADC數(shù)字轉(zhuǎn)換器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

日韩免费一区二区| 不卡一卡二卡三乱码免费网站| 亚洲一区999| 性久久久久久久久久久久久久| av男人的天堂av| 亚洲欧美综合另类| 欧美mv日韩| 亚洲第一黄色网| 亚洲成人天堂网| 国产伦久视频在线观看| 欧美高清在线一区二区| 99九九视频| 日韩免费av网站| 欧美freesex交免费视频| 亚洲男人第一av网站| 天天干天天色天天干| 成人高潮aa毛片免费| 中文成人av在线| 国产日韩一区欧美| 96亚洲精品久久久蜜桃| 亚洲一区免费| 欧美日本高清一区| 少妇av片在线观看| 欧美电影免费网站| av午夜一区麻豆| 亚洲国产精品成人综合色在线婷婷| 日本不卡视频在线播放| 乱h高h女3p含苞待放| 猛男gaygay欧美视频| 精品国产一二三| 亚洲天堂国产视频| 欧美xxx网站| 精品国产成人av| 黄色特一级视频| 免费人成在线观看播放视频| 久久亚洲二区三区| 国产欧美一区二区三区另类精品 | 中文精品电影| 中日韩美女免费视频网址在线观看| 免费成人蒂法网站| 风间由美性色一区二区三区四区| 欧美精品国产精品| 2024亚洲男人天堂| 亚洲国产欧美一区二区三区不卡| 丰满人妻一区二区三区免费视频| 国内久久精品视频| 成人激情视频在线播放| 久久精品国产亚洲av麻豆蜜芽| 99人久久精品视频最新地址| 久久人91精品久久久久久不卡| 天天综合天天做| 天天做综合网| 欧美猛交免费看| 深夜福利影院在线观看| 亚洲色图欧美| 欧美老女人性生活| 久久久久久久久久一区二区三区| 欧美日本一区| 久久久之久亚州精品露出| 久久精品波多野结衣| 中文字幕一区二区三区久久网站| 欧美成人免费网| 深夜福利影院在线观看| 成人日韩欧美| 亚洲高清极品| 日韩电影免费在线观看中文字幕| 日本成人xxx| 亚洲欧美久久精品| 日韩一区二区三区在线| 欧美国产在线一区| 国产厕拍一区| 日韩av综合网| 怡红院一区二区三区| 欧美裸体在线版观看完整版| 最新国产精品拍自在线播放| 成人一级黄色大片| 欧美久久综合| 91wwwcom在线观看| 青青艹在线观看| 久久99精品国产麻豆不卡| 91在线直播亚洲| 精品人妻aV中文字幕乱码色欲| 豆国产96在线|亚洲| 久久艹中文字幕| 在线视频91p| 成人亚洲一区| 中文字幕+乱码+中文字幕一区| 亚洲一区二区三区欧美| 中国av在线播放| 欧美午夜影院在线视频| 污版视频在线观看| 日韩成人在线看| 亚洲男人天堂视频| 天堂网avav| 国产欧美日本| 成人激情视频小说免费下载| 色综合视频在线| 国产女同性恋一区二区| 欧美另类videosbestsex日本| 国产理论在线| 91精品国产综合久久国产大片| 韩国三级hd两男一女| 欧美一区电影| 韩国19禁主播vip福利视频| 波多野结衣影片| 国产成+人+日韩+欧美+亚洲| 日本不卡高清视频一区| 日本伦理一区二区| 成人一区视频| 国产欧美精品一区| 久青草视频在线播放| 性感美女一区二区在线观看| 日韩欧美高清dvd碟片| 亚洲综合色一区| 欧美午夜不卡| 国产一区二区丝袜| 毛片在线播放网站| 一区二区三区精品视频在线| 杨幂毛片午夜性生毛片| ccyy激情综合| 久久在线免费观看视频| 91porny九色| 91在线观看下载| 黄色一级片国产| 欧美激情不卡| 亚洲人成网在线播放| 在线免费观看毛片| 国产麻豆精品视频| 中文网丁香综合网| 日韩一区二区三区在线免费观看 | 日韩视频精品在线| 欧美日韩在线不卡视频| 爱高潮www亚洲精品| 精品国产依人香蕉在线精品| 成人免费视频国产免费| 99久久99久久免费精品蜜臀| 日韩精品一区二区免费| а天堂中文最新一区二区三区| 亚洲视频在线观看免费| 日本中文字幕第一页| 99这里只有久久精品视频| 日本免费a视频| 国产一区二区视频在线看| 色视频www在线播放国产成人| 伦av综合一区| 久久久精品天堂| 日韩欧美xxxx| 国产亚洲欧美日韩在线观看一区二区 | 国产精品三区在线| 污污影院在线观看| 91精品欧美综合在线观看最新 | 日韩一区二区三区色| 日韩中文字幕在线观看| 真实新婚偷拍xxxxx| 国产亚洲人成网站| 欧美日韩一区二区在线免费观看 | 影音欧美亚洲| 欧美啪啪网站| 久久精品国产久精国产一老狼| 影音先锋国产资源| 亚洲欧洲在线观看av| 在线一区二区不卡| 在线成人激情| 国产精品久久国产精品| 成人黄色动漫| 亚洲视屏在线播放| 91极品身材尤物theporn| 亚洲欧洲成人精品av97| 日本成人xxx| 亚洲欧洲一区| 日本精品一区二区| 久久夜夜久久| 国产精品精品国产色婷婷| xxav国产精品美女主播| 人人爽人人爽人人片av| 久久亚洲私人国产精品va媚药| 欧美日韩亚洲一二三| 日韩一区自拍| 97视频资源在线观看| 国模私拍一区二区国模曼安| 国产亚洲美女久久| 国产亲伦免费视频播放| 午夜欧美2019年伦理| 国产一级久久久久毛片精品| 激情综合五月天| 久久这里只有精品23| 欧美亚洲在线日韩| eeuss一区二区三区| 天天综合av| 久久久91精品国产一区不卡| 熟妇高潮一区二区三区| 欧美亚洲综合在线| 久久艹精品视频| 国产网站一区二区| 麻豆精品国产传媒| 老司机精品导航| 久久www视频| 国产免费av一区二区三区| www..com久久爱| 岛国视频一区免费观看| 亚洲成人av观看| 欧美美女18p| 99re在线视频| 亚洲电影免费观看| 91一区二区视频| 欧美视频一二三| 欧美成人片在线观看| 久久精品欧美日韩| 年下总裁被打光屁股sp| 麻豆国产精品一区二区三区| 国产欧美日韩网站| 久久久久午夜电影| 日本不卡二区| 欧美自拍一区| 成人片在线免费看| 美女久久久久久| 国产成人精品电影久久久| 在线三级中文| www.99久久热国产日韩欧美.com| 天堂网2014av| 欧美一区二区三区思思人| 91青青草视频| 精品成人在线视频| 免费又黄又爽又色的视频| 欧美国产丝袜视频| 亚洲高清色综合| 岳乳丰满一区二区三区| 欧美日韩人人澡狠狠躁视频| 久久久久久久国产精品毛片| 中日韩免费视频中文字幕| 精品无码人妻一区| 99久久精品国产精品久久 | 99久久精品国产网站| 欧美久久久久久久久久久| 国内精品伊人久久久久av影院 | 久久久国产精品麻豆| 在线观看国产三级| 成人av网址在线| 在线精品视频播放| 国产99久久久国产精品免费看| 中文字幕亚洲欧洲| 蜜臀av性久久久久蜜臀aⅴ| 亚洲免费不卡| 欧美成人激情| 国产高清精品软男同| 91精品久久久久久久蜜月 | 成人日批视频| 亚洲高清免费视频| 鬼打鬼之黄金道士1992林正英| 激情亚洲小说| 91精品久久久久久综合乱菊 | 欧美日韩在线播放| 中文字幕精品一区二| 欧美性受xxxx| 亚洲天堂自拍偷拍| 欧美人与z0zoxxxx视频| 一卡二卡三卡在线| 91精品国产综合久久久蜜臀图片| 国产一区二区波多野结衣| 7777精品伊人久久久大香线蕉的| 国产伦精品一区二区三区免.费| 5月丁香婷婷综合| www.日韩在线观看| 亚洲激情在线视频| 毛片在线播放网站| 最近中文字幕日韩精品 | 国产精品卡一卡二| 黑人操日本美女| 一区二区三区精品| 亚洲欧美在线视频免费| 日韩欧美成人精品| 伊人免费在线观看| 日韩一区二区三区免费观看| 免费a视频在线观看| 亚洲欧美成人在线| 午夜视频在线观看网站| 欧美成人免费网| 日韩欧美精品一区二区三区| 国产精品久在线观看| 欧美一区一区| 91久久午夜| 手机看片日韩国产| 亚洲黄色毛片| 国产一二三四在线视频| 国产美女娇喘av呻吟久久| 性活交片大全免费看| 久久久久国产一区二区三区四区| 日本成人免费在线观看| 亚洲伊人伊色伊影伊综合网| 亚洲婷婷综合网| 欧美日产在线观看| 天天操天天爱天天干| 丝袜美腿精品国产二区| 黄页网站大全在线免费观看| 国产精品1234| 99久久香蕉| 亚洲国产精品一区在线观看不卡 | 欧美大尺度在线观看| 神马午夜在线视频| 91精品久久久久久综合乱菊| 日韩av资源网| 国产精品h视频| 久久精品女人天堂| 国产又粗又猛又爽又黄| 国产欧美一区二区三区网站| 国产亚洲精品久久久久久打不开| 在线观看亚洲一区| 天天干天天色天天| 久久夜色撩人精品| 日韩一区二区三区在线免费观看| 国产成人免费观看| 91亚洲国产成人久久精品| 日本黄色三级大片| 国产成人亚洲综合色影视| av免费播放网站| 欧美性猛交xxxx乱大交| 手机在线观看毛片| 欧美另类极品videosbest最新版本| 亚洲国产精品一区二区第一页| 欧美亚视频在线中文字幕免费| 在线播放 亚洲| 久久精品卡一| 欧美性xxxx图片| 亚洲va欧美va人人爽| 精品久久久无码中文字幕| 中文字幕亚洲国产| 日韩电影网站| 欧美日韩国产精品一区二区| 精品成人一区| av漫画在线观看| 亚洲一区二区三区三| 亚洲av无码乱码国产精品久久| 日韩一区二区福利| 88xx成人网| 日韩和欧美的一区二区| 免费精品视频| 亚洲一级中文字幕| 懂色av一区二区三区| 天天操天天射天天舔| 久久免费少妇高潮久久精品99| 91精品久久久久久综合五月天| 300部国产真实乱| 国产成人午夜99999| 欧美日韩中文字幕在线观看| 日韩欧美一二三| 欧美黑人猛交| 国产乱码精品一区二区三区不卡| 激情久久一区| 黑丝av在线播放| 日韩欧美第一页| 超碰国产在线| 樱桃视频在线观看一区| 国产精品jizz| 色视频成人在线观看免| 蜜桃视频在线免费| 国产精品69av| 成人同人动漫免费观看| 天天操天天爽天天射| 成人福利电影精品一区二区在线观看| 久久99久久98精品免观看软件| 亚洲电影天堂av| 2019中文字幕在线电影免费 | 日本在线xxx| 99久久精品免费看| 国模无码国产精品视频| 日韩欧美黄色影院| 欧美xxxx少妇| 久久一区二区精品| 久久亚洲一区| 久久久久久亚洲中文字幕无码| 欧美性生交xxxxxdddd| 在线观看麻豆蜜桃| 91九色综合久久| 亚洲国产午夜| 国产毛片久久久久久久| 亚洲国产综合色| 国产香蕉视频在线看| 国产精品自拍小视频| 亚洲人metart人体| 国产乱淫av麻豆国产免费| 狠狠色香婷婷久久亚洲精品| 国产专区在线| 91原创国产| 99日韩精品| 日韩国产欧美区| 国产黄色在线播放| 亚洲bt天天射| 亚洲国产高清一区| 污污内射在线观看一区二区少妇| 精品视频999| 色婷婷av在线| 日韩精品欧美一区二区三区| 国内久久精品视频| 日本熟女毛茸茸| 日韩亚洲精品电影| 日韩理论电影中文字幕| 一区二区xxx| 精品女厕一区二区三区| 成人在线高清视频| 国产伦精品一区二区三区|