精品欧美一区二区三区在线观看 _久久久久国色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ù)棧公眾號

精品久久久久久久免费人妻| 91亚洲国产精品| 中文字幕丰满乱子伦无码专区| 成人看片网站| 亚洲免费观看在线视频| 久久久久久久久久久久久久一区 | 日韩网站在线| 国产欧美日韩在线一区二区 | 5月丁香婷婷综合| 污污污污污污www网站免费| 天堂中文网在线| 久久草av在线| 国产91成人在在线播放| 欧美三级黄色大片| 伊人成综合网yiren22| 欧美一级黄色大片| 一级在线免费视频| 国产美女高潮在线| 亚洲免费观看高清完整版在线观看 | 乱色精品无码一区二区国产盗| 丝袜美腿亚洲综合| 久久久久久久久久久久av| 一二三四在线观看视频| 人妖一区二区三区| 精品国产区一区| 国产三级生活片| 人人视频精品| 精品久久久中文| 8x8x华人在线| 日本综合在线| 国产免费观看久久| 欧美日韩在线不卡一区| 免费av网站在线播放| 韩国女主播成人在线观看| 国产成人精品最新| 亚洲午夜18毛片在线看| 国产精品久久| 9999在线精品视频| 亚洲成人午夜电影| 国产精品久久成人免费观看| www.视频在线.com| 国产三级精品视频| 久久影院理伦片| 三级网站免费观看| 成人久久18免费网站麻豆| 亚洲精品日韩av| 国产精品久久久国产盗摄| 免费黄网站欧美| 国产日韩精品综合网站| 一级一级黄色片| 日韩av电影免费观看高清完整版| 热门国产精品亚洲第一区在线| 日本一区二区网站| 伊人久久亚洲影院| 久久久久久久影院| 日本熟伦人妇xxxx| 国产美女诱惑一区二区| 欧美在线视频网站| 亚洲婷婷综合网| 日韩成人一级大片| 国产日韩精品视频| 国产视频在线免费观看| 国产乱一区二区| 91在线免费看网站| www.亚洲黄色| 成人av在线播放网址| 精品一区二区三区国产| 美国一级片在线免费观看视频 | 石原莉奈一区二区三区在线观看 | 无码人妻丰满熟妇精品| 天堂蜜桃一区二区三区| 国产精品普通话| 一级特黄aaa大片| 国产精品一区二区男女羞羞无遮挡 | 日韩在线观看免费全| 波多野结衣家庭教师| 黑人一区二区三区四区五区| 欧美一级bbbbb性bbbb喷潮片| 国产suv精品一区二区33| 久久国产精品免费| 97久久精品午夜一区二区| 色香蕉在线视频| 国产欧美精品在线观看| 日本a级片在线观看| 91九色美女在线视频| 在线区一区二视频| 久久精品一二三四| 天天躁日日躁成人字幕aⅴ| 这里只有精品视频| 久久免费在线观看视频| 奶水喷射视频一区| 成人精品福利视频| 三级在线观看| 亚洲色图20p| 无码aⅴ精品一区二区三区浪潮| 亚洲精品一区av| 亚洲护士老师的毛茸茸最新章节| 亚洲精品视频网址| 精品二区久久| 国产美女搞久久| 日韩在线视频免费| 国产精品成人一区二区艾草| 伊人成色综合网| 亚洲久草在线| 国产午夜精品全部视频播放| 九九在线观看视频| 日本va欧美va欧美va精品| 国产精品传媒毛片三区| 91porn在线观看| 午夜欧美一区二区三区在线播放| 亚洲精品综合在线观看| 亚洲视频分类| 久久久久久久久久久91| 国产男女无套免费网站| 久久久一区二区| 免费高清一区二区三区| 男人亚洲天堂| 久久久久久久久久久久久久久久久久久久 | 成人亚洲网站| 在线播放日韩| 人人澡人人澡人人看欧美| 国产情侣激情自拍| 久久青青视频| 欧美午夜电影网| 亚洲中文字幕无码一区| 99精品视频在线观看播放| 奇门遁甲1982国语版免费观看高清 | 欧美天天在线| 国产热re99久久6国产精品| 亚洲男同gay网站| 国产成人在线免费| 亚洲精品一区二区三区四区五区 | 日韩伦理一区二区三区| 欧美老女人xx| 国产精品欧美激情在线| 国产精品久久毛片| 亚洲色图38p| 亚洲区小说区| 欧美一区二三区| 天天摸天天碰天天爽天天弄| 亚洲成人自拍网| 97中文字幕在线观看| 欧美福利视频| 亚洲一区二区三区香蕉| 韩国av网站在线| 91精品欧美综合在线观看最新| 日本黄色免费片| 麻豆成人91精品二区三区| 色综合影院在线观看| av一区在线| 国产亚洲精品久久| 亚洲成人av网址| 激情六月天婷婷| 亚洲精品一区二区三区蜜桃| 1区2区3区国产精品| 午夜dv内射一区二区| 欧美日韩播放| 国产精品96久久久久久又黄又硬 | 国产视频久久久久| 天天综合天天干| 久久免费视频色| 日本新janpanese乱熟| 日韩www.| 91久久伊人青青碰碰婷婷| 免费在线国产视频| 亚洲第一区第二区| 人妻丰满熟妇av无码区| 国产免费观看久久| aaaaaaaa毛片| 亚洲三级观看| 麻豆精品蜜桃一区二区三区| 日韩中文视频| 久久最新资源网| 俄罗斯嫩小性bbwbbw| 精品久久久久久久中文字幕| 免费视频91蜜桃| 韩国三级中文字幕hd久久精品| av动漫在线播放| 香蕉久久99| 国产女人精品视频| 高h视频在线播放| 亚洲免费一在线| 国产精品久久久久久久久毛片 | 欧美激情精品久久久久久| 色哟哟中文字幕| 欧美色涩在线第一页| 欧美成人免费观看视频| 91免费观看视频| wwwwwxxxx日本| 亚洲精品一二| 一区二区三视频| 老太脱裤让老头玩ⅹxxxx| gogo高清在线播放免费| 中文字幕成人在线| 东京干手机福利视频| 欧美午夜不卡视频| 日本一区二区不卡在线| 亚洲欧洲日本在线| 国产三级国产精品| 国产精品一区二区男女羞羞无遮挡 | 国产精品密蕾丝袜| 国产成人鲁色资源国产91色综| 天天摸天天碰天天添| 综合一区av| 日本一区二区在线| 丁香婷婷成人| 国产日韩一区在线| 美女100%一区| 欧美国产高跟鞋裸体秀xxxhd| 成在在线免费视频| 国产视频精品xxxx| 亚洲高清在线观看视频| 欧美日韩精品福利| 日本中文字幕在线| 亚洲图片有声小说| 色婷婷在线视频观看| 国产女主播视频一区二区| 李丽珍裸体午夜理伦片| 国产乱妇无码大片在线观看| 亚洲视频在线观看一区二区三区| 99精品国产福利在线观看免费 | 欧美成人女星排行榜| 波多野结衣在线观看视频| 婷婷中文字幕综合| 麻豆亚洲av成人无码久久精品| 国产精品国产三级国产a| 熟女少妇内射日韩亚洲| 91视视频在线直接观看在线看网页在线看 | 唐人社导航福利精品| 97香蕉久久超级碰碰高清版 | 亚洲第一成人在线| 久久久久久久中文字幕| 亚洲日韩欧美一区二区在线| 亚洲区一区二区三| 中文字幕av一区 二区| 亚洲精品午夜视频| 2024国产精品| 无码人妻精品一区二区三区温州 | 91麻豆制片厂| 国产三级精品视频| 精品国产成人亚洲午夜福利| 久久精品男人的天堂| 色哟哟精品观看| 国产午夜精品福利| 人与嘼交av免费| 国产精品乱码一区二三区小蝌蚪| 亚洲女优在线观看| 国产日韩av一区| 99国产精品免费| |精品福利一区二区三区| 欧美日韩色视频| 自拍偷自拍亚洲精品播放| 亚洲天堂黄色片| 一区二区三区在线观看国产| 久草视频在线资源站| 亚洲一区二区视频在线观看| 久草视频精品在线| 福利精品视频在线| 五月婷婷激情五月| 欧美日韩高清一区二区| 国产又大又黄的视频| 欧美一级免费大片| 人妻精品一区二区三区| 日韩精品一区二区视频| 国产亚洲依依| 久久成人精品电影| 6699嫩草久久久精品影院| 欧美洲成人男女午夜视频| 色综合天天色| 99精彩视频在线观看免费| 欧美大胆视频| 天天好比中文综合网| 亚洲成人精品| 分分操这里只有精品| 久久综合激情| 热久久久久久久久| 成人激情校园春色| 成人激情五月天| 亚洲蜜臀av乱码久久精品| 国产精品99re| 欧洲av在线精品| www.黄色av| 精品一区二区三区四区在线| 色哟哟免费在线观看 | 日韩污视频在线观看| 色婷婷av一区二区三区之一色屋| 亚洲一级av毛片| 欧美成人r级一区二区三区| 欧美女优在线观看| 久久久久999| 天堂av在线| 亚洲xxxxx性| 青青久久av| 一区二区在线不卡| 国产精品五区| 日本一二三区在线| www国产精品av| 欧美日韩三级在线观看| 色哟哟日韩精品| 亚洲第九十九页| 中文字幕精品久久久久| 高h视频在线播放| 成人情趣片在线观看免费| 人人精品亚洲| 国产精品igao激情视频| 欧美色视频一区二区三区在线观看| 国产三级一区二区三区| 国产精品1000| 5566中文字幕一区二区电影| 欧美18xxxxx| 欧美高清无遮挡| 国产激情欧美| 欧美理论一区二区| 激情欧美日韩一区| 91精品视频国产| 欧美经典一区二区| 日韩精品无码一区二区| 91精品国产综合久久久蜜臀图片| 久久久久久久久亚洲精品| 欧美日韩成人黄色| 亚洲国产天堂| 欧美日韩亚洲在线| 亚洲精品专区| 风韵丰满熟妇啪啪区老熟熟女| 中文字幕精品三区| 波多野结衣二区三区| 亚洲国模精品一区| heyzo中文字幕在线| 97碰碰视频| 国产精品99一区二区三区| 三年中国国语在线播放免费| 99国产麻豆精品| 国产在线视频在线观看| 日韩欧美视频一区| 国产在线观看免费麻豆| 国产在线拍偷自揄拍精品| 欧美日韩伦理在线免费| 欧美综合在线观看视频| 久久久欧美精品sm网站| av黄色在线看| 亚洲精品大尺度| www.综合网.com| 国产高清精品一区| 狠狠色丁香久久综合频道| 亚洲自拍第三页| 中文字幕一区在线| 亚洲字幕av一区二区三区四区| 这里只有精品久久| 久久伊人国产| 亚洲欧洲日韩精品| 国内精品伊人久久久久av影院 | 日本中文字幕在线观看| 国产免费亚洲高清| **女人18毛片一区二区| 日本人dh亚洲人ⅹxx| 亚洲乱码精品一二三四区日韩在线| 亚洲无码精品国产| 久久精品视频在线| 国产专区精品| 亚洲 自拍 另类小说综合图区| 99这里都是精品| 老熟妇一区二区三区| 伊是香蕉大人久久| 四虎精品永久免费| 一级黄色免费在线观看| 国产成人综合在线观看| 国产精品30p| 亚洲日本成人网| 亚洲美女色播| av女优在线播放| 97精品久久久久中文字幕| 99re这里只有精品在线| 久久精品国产2020观看福利| 成人三级毛片| 男人天堂网视频| 中文字幕一区免费在线观看 | 国产成人av一区二区三区在线| 日产精品久久久久久久| 亚洲视频欧洲视频| 日本电影久久久| 日韩欧美国产综合在线| 久久精品视频一区| 99精品人妻无码专区在线视频区| 欧美国产日韩一区二区三区| 亚洲激情播播| 福利视频999| 五月激情综合婷婷| 日本免费在线视频| 国产精品伊人日日| 蜜桃一区二区三区四区| 一区二区三区免费高清视频| 亚洲视频在线观看免费| 日本在线成人| 国产激情在线观看视频| 亚洲乱码国产乱码精品精的特点| 精品999视频| 成人情视频高清免费观看电影| 日韩av在线免费观看不卡| 国产一级中文字幕| 一区二区三区日韩在线|