色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何編寫基于ARM的裸機程序和基于Linux的驅動程序?

FPGA之家 ? 來源:一口Linux ? 作者:一口Linux ? 2021-03-12 15:26 ? 次閱讀

嵌入式開發中,ADC應用比較頻繁,本文主要講解ADC的基本原理以及如何編寫基于ARM的裸機程序和基于Linux的驅動程序。

ARM架構:Cortex-A9Linux內核:3.14

在講述ADC之前,我們需要先了解什么是模擬信號數字信號

模擬信號

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

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

如下圖所示從上到下一次是正弦波、 調幅波、 阻尼震蕩波、 指數衰減波 。

數字信號

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

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

優點:

1. 抗干擾能力強、無噪聲積累

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

隨著傳輸距離的增加,噪聲累積越來越多,以致使傳輸質量嚴重惡化。

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

即在適當的距離采用判決再生的方法,再生成沒有噪聲干擾的和原發送端一樣的數字信號,所以可實現長距離高質量的傳輸。

2. 便于加密處理

信息傳輸的安全性和保密性越來越重要,數字通信的加密處理的比模擬通信容易得多,以話音信號為例,經過數字變換后的信號可用簡單的數字邏輯運算進行加密、解密處理。

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

數字通信的信號形式和計算機所用信號一致,都是二進制代碼,因此便于與計算機聯網,也便于用計算機對數字信號進行存儲、處理和交換,

可使通信網的管理、維護實現自動化、智能化。

4. 設備便于集成化、微型

數字通信采用時分多路復用,不需要體積較大的濾波器。設備中大部分電路是數字電路,可用大規模和超大規模集成電路實現,因此體積小、功耗低。

5. 便于構成綜合數字網和綜合業務數字網

采用數字傳輸方式,可以通過程控數字交換設備進行數字交換,以實現傳輸和交換的綜合。

另外,電話業務和各種非話業務都可以實現數字化,構成綜合業務數字網。

6. 占用信道頻帶較寬

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

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

數字信號與模擬信號的轉化

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

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

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

目前在計算機廣域網中實際傳送的則既有二進制數字信號,也有由數字信號轉換而得的模擬信號。但是更具應用發展前景的是數字信號。

PCM脈沖編碼調制

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

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

抽樣:

就是對模擬信號進行周期性掃描,把時間上連續的信號變成時間上離散的信號。

該模擬信號經過抽樣后還應當包含原信號中所有信息,也就是說能無失真的恢復原模擬信號。

量化:

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

編碼:

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

ADC

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

ADC最早用于對無線信號向數字信號轉換。如電視信號,長短播電臺發接收等。

與之相對應的DAC,Digital-to-Analog Converter,它是ADC模數轉換的逆向過程。

現在市場上的電子產品都集成了傳感器,傳感器要采集數據,他的內部結構里就一定要用到ADC,常見的傳感器如下:

溫濕度:溫度傳感器,DHT11

聲音:音頻芯片進行錄音,WM8906

圖像:索尼IMX386/IMX283傳感器

Exynos4412 A/D轉換器

三星的Exynos4412模塊結構圖如下所示:

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

ADC控制器

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

ADC接口包括如下特性。

10bit/12bit輸出位可選。

微分誤差 1.0LSB。

積分誤差 2.0LSB。

最大轉換速率5Msps.

功耗少,電壓輸入1.8V。

電壓輸入范圍 0~1.8V。

支持偏上樣本保持功能。

通用轉換模式。

模塊圖

4412 A/D轉換器的控制器接口框圖如下:

原理我們并不需要關注,知道即可。

通道選擇

ec9cb6ba-82f4-11eb-8b86-12bb97331649.png

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

A/D控制器寄存器

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

ece795c2-82f4-11eb-8b86-12bb97331649.png

1、A/D控制寄存器ADCCON

ed51f23c-82f4-11eb-8b86-12bb97331649.png

RES : 選擇A/D轉換精度,0:劃分成1024份 1:劃分成4096份

ECFLG :轉換是否結束 0:轉換中 1:轉換完畢;對于輪詢模式需要根據該位判斷數據是否轉換完畢。

PRSCEN:A/D轉換預分頻是否使能

PRSCVL:預分頻的值,轉換公式見下面

STANDBY:待機模式 0:正常工作模式 1:待機模式。處于待機模式時要將PRSCEN設置為0

READ_START: A/D轉換由讀操作觸發,設置為1后,每次讀取A/D值的操作都會觸發一次A/D轉換。

ENABLE_START: 單次開啟A/D轉換,轉換完畢后該位自動清零,當READ_START設置為1的時候,該位無效。

通常設置值為(1 《《 16 | 1 《《 14 | 99 《《6 | 1 《《 1)。

2、A/D轉換數據寄存器ADCDAT0

ee47083a-82f4-11eb-8b86-12bb97331649.png

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

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

eeb4faac-82f4-11eb-8b86-12bb97331649.png

黃色部分可知,中斷例程負責清中斷,中斷結束后寫入任意值就可以清中斷。

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

ef044d64-82f4-11eb-8b86-12bb97331649.png

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

5、ADC中斷ID

參見9.2.2GIC Interrupt Table

ef3c1596-82f4-11eb-8b86-12bb97331649.png

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

6、Combiner中斷控制器

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

7、Combiner分組

參考章節:10.2.1Interrupt CombinerTable 10-1Interrupt Groups of Interrupt Combiner

efe6ec28-82f4-11eb-8b86-12bb97331649.png

可見ADC在INTG10,即第10組。

8、Combiner IESR2

參考章節:10.4.2.9IESR2

f0001eaa-82f4-11eb-8b86-12bb97331649.png

如果要用中斷模式設置為1即可。

9、Combiner IECR2

參考章節:10.4.2.10IECR2

f0a9b49c-82f4-11eb-8b86-12bb97331649.png

此處用于關閉中斷,采用默認值即可,注意,如果設置了1,那么中斷功能就關閉了。

10、A/D轉換的轉換時間計算

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

100MHz/(99+1) = 1MHz

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

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

電路連接圖

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

ADC裸機開發程序實例

ADC數據的讀取通常由2種方法:中斷模式、輪訓模式。

輪訓模式

輪詢模式讀取數據步驟如下:

1.要讀取數據首先向ADC寄存器ADCCON的bit:1寫1,發送轉換命令,采用讀-啟動模式來開啟轉換。

2.當ADC控制器轉換完畢會將ADCCON的bit:15設置為1,

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

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

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

/***********************ADC ******************/

#define ADC_CFG __REG(0x10010118)

#define ADCCON __REG(0x126C0000)

#define ADCDLY __REG(0x126C0008)

#define ADCDAT __REG(0x126C000C)

#define CLRINTADC __REG(0x126C0018)

#define ADCMUX __REG(0x126C001C)

#include “exynos_4412.h”

#include “pwm.h”

#include “uart.h”

unsigned char table[10] = {‘0’,‘1’,‘2’,‘3’,‘4’,‘5’,‘6’,‘7’,‘8’,‘9’};

void mydelay_ms(int time)

{

int i, j;

while(time--)

{

for (i = 0; i 《 5; i++)

for (j = 0; j 《 514; j++);

}

}

adc_init(int temp)

{

ADCCON = (1 《《 16 | 1 《《 14 | 99 《《6 | 1 《《 1);

ADCMUX = 3;

temp = ADCDAT & 0xfff;

}

/*

* 裸機代碼,不同于LINUX 應用層, 一定加循環控制

*/

int main (void)

{

unsigned char bit4,bit3,bit2,bit1;

unsigned int temp = 0;

uart_init();

adc_init(temp);

puts(“開始轉換

”);

while(1)

{

while(!(ADCCON & 0x8000));

temp = ADCDAT & 0xfff;

printf(“U = %d

”,temp);

temp = 1.8 * 1000 * temp/0xfff;

bit4 = temp /1000;

putc(table[bit4]);

bit3 = (temp % 1000)/100?;

putc(table[bit3]);

bit2 = ((temp % 1000)%100)/10;

putc(table[bit2]);

bit1 = ((temp % 1000)%100)%10;

putc(table[bit1]);

puts(“mV”);

putc(‘

’);

mydelay_ms(1000);

}

return 0;

}

中斷模式

中斷模式讀取數據步驟如下:

1.要讀取數據首先向ADC寄存器ADCCON的bit:0寫1,發送轉換命令;

2.當ADC控制器轉換完畢會通過中斷線向CPU發送中斷信號;

3.在中斷處理函數中,讀走數據,并清中斷。

注:中斷對應寄存器的設置,后續會更新對應的文檔。

void do_irq(void)

{

int irq_num;

irq_num = CPU0.ICCIAR &0x3ff;

switch(irq_num)

{

case 42:

adc_num = ADCDAT&0xfff;

printf(“adc = %d

”,adc_num);

CLRINTADC = 0;

// IECR2 = IECR2 | (1 《《 19); 打開的話只能讀取一次,

//42/32

ICDICPR.ICDICPR1 = ICDICPR.ICDICPR1 | (1 《《 10);【清GIC中斷標志位類似于 ICDISER】

break;

}

CPU0.ICCEOIR = CPU0.ICCEOIR & (~0x3ff) | irq_num;

}

void adc_init(void)

{ //12bit 使能分頻 分頻值 手動

ADCCON = (1 《《 16) | (1 《《 14) | (0xff 《《 6) | (1 《《 0);

ADCMUX = 3;

}

void adcint_init(void)

{

IESR2 = IESR2 | (1 《《 19);

ICDDCR = 1; //使能分配器

//42/32

ICDISER.ICDISER1 = ICDISER.ICDISER1 | (1 《《 10);//使能相應中斷到分配器

ICDIPTR.ICDIPTR10 = ICDIPTR.ICDIPTR10 &(~(0xff 《《 16)) | (0x1 《《 16);//發送到相應CPU接口

CPU0.ICCPMR = 255;//設置中斷屏蔽優先級

CPU0.ICCICR = 1; //全局使能開關

}

int main (void)

{

adc_init();

adcint_init();

while(1)

{

ADCCON = ADCCON | 1;

delay_ms(1000);

}

return 0;

}

基于Linux驅動編寫

設備樹

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

關于中斷的使用我們在后續文章中會繼續分析,現在我們只需要知道中斷信息如何填寫即可。

ADC寄存器信息填寫

f12916a6-82f4-11eb-8b86-12bb97331649.png

在這里插入圖片描述

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

reg = 《0x126C0000 0x20》;

ADC中斷信息填寫

描述中斷連接需要四個屬性:父節點提供以下信息

interrupt-controller - 一個空的屬性定義該節點作為一個接收中斷信號的設備。

interrupt-cells - 這是一個中斷控制器節點的屬性。它聲明了該中斷控制器的中斷指示符中【interrupts】 cell 的個數(類似于 #address-cells 和 #size-cells)。

子節點描述信息

interrupt-parent - 這是一個設備節點的屬性,包含一個指向該設備連接的中斷控制器的 phandle。那些沒有 interrupt-parent 的節點則從它們的父節點中繼承該屬性。

interrupts - 一個設備節點屬性,包含一個中斷指示符的列表,對應于該設備上的每個中斷輸出信號。【設備的中斷信息放在該屬性中】

父節點

首先我們必須知道ADC控制器的中斷線的父節點:

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

進入設備樹文件所在目錄:archarmootdts

grep combiner *.* -n

經過篩選得到以下信息,

因為我們使用的板子是exynos4412,而exynos系列通用的平臺設備樹文件是exynos4.dtsi,查看該文件:

上圖列舉了combiner控制器的詳細信息:

interrupt-cells ;

interrupt-cells =《2》;

所以ADC控制器中斷控制器的interrupts屬性應該有兩個cell。

interrupts屬性填寫

而設備的中斷信息填寫方式由內核的以下文檔提供:

Documentationdevicetreeindingsinterrupt-controllerinterrupts.txt

69. b) two cells

70. ------------

71. The #interrupt-cells property is set to 2 and the first cell 72. defines the

73. index of the interrupt within the controller, while the second cell is used

74. to specify any of the following flags:

75. - bits[3:0] trigger type and level flags

76. 1 = low-to-high edge triggered

77. 2 = high-to-low edge triggered

78. 4 = active high level-sensitive

79. 8 = active low level-sensitive

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

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

那么index應該是多少呢?

詳見datasheet的9.2.2 GIC Interrupt Table 節:

ef3c1596-82f4-11eb-8b86-12bb97331649.png

此處我們應該是填寫左側的SPI ID:10 還是填寫INTERRUPT ID:42呢?

此處我們可以參考LCD節點的interrupts填寫方法:

通過查找父節點為combiner的設備信息。

繼續grep combiner 。 -n

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

interrupt-parent = 《&combiner》;

interrupts = 《10 3》;

ADC外設設備樹信息

fs4412-adc{

compatible = “fs4412,adc”;

reg = 《0x126C0000 0x20》;

interrupt-parent = 《&combiner》;

interrupts = 《10 3》;

};

本文默認大家會使用設備樹,不知道如何使用設備樹的朋友,后續會開一篇單獨講解設備樹。【注意】在不支持設備樹內核中,以Cortex-A8為例,中斷信息填寫在以下文件中

內部中斷,Irqs.h (archarmmach-s5pc100includemach)

外部中斷在Irqs.h (archarmplat-s5pincludeplat)

ADC屬于內部中斷,位于archarmmach-s5pc100includemachIrqs.h中。

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

archarmmach-s5pc100Mach-smdkc100.c

static struct platform_device *smdkc100_devices[] __initdata = {

&s3c_device_adc,

&s3c_device_cfcon,

&s3c_device_i2c0,

&s3c_device_i2c1,

&s3c_device_fb,

&s3c_device_hsmmc0,

&s3c_device_hsmmc1,

&s3c_device_hsmmc2,

&samsung_device_pwm,

&s3c_device_ts,

&s3c_device_wdt,

&smdkc100_lcd_powerdev,

&s5pc100_device_iis0,

&samsung_device_keypad,

&s5pc100_device_ac97,

&s3c_device_rtc,

&s5p_device_fimc0,

&s5p_device_fimc1,

&s5p_device_fimc2,

&s5pc100_device_spdif,

};

結構體s3c_device_adc定義在以下文件:

archarmplat-samsungDevs.c

#ifdef CONFIG_PLAT_S3C24XX

static struct resource s3c_adc_resource[] = {

[0] = DEFINE_RES_MEM(S3C24XX_PA_ADC, S3C24XX_SZ_ADC),

[1] = DEFINE_RES_IRQ(IRQ_TC),

[2] = DEFINE_RES_IRQ(IRQ_ADC),

};

struct platform_device s3c_device_adc = {

.name = “s3c24xx-adc”,

.id = -1,

.num_resources = ARRAY_SIZE(s3c_adc_resource),

.resource = s3c_adc_resource,

};

#endif /* CONFIG_PLAT_S3C24XX */

#if defined(CONFIG_SAMSUNG_DEV_ADC)

static struct resource s3c_adc_resource[] = {

[0] = DEFINE_RES_MEM(SAMSUNG_PA_ADC, SZ_256),

[1] = DEFINE_RES_IRQ(IRQ_TC),

[2] = DEFINE_RES_IRQ(IRQ_ADC),

};

struct platform_device s3c_device_adc = {

.name = “samsung-adc”,

.id = -1,

.num_resources = ARRAY_SIZE(s3c_adc_resource),

.resource = s3c_adc_resource,

};

#endif /* CONFIG_SAMSUNG_DEV_ADC */

由代碼可知,平臺驅動對應的platform_device具體內容由宏CONFIG_PLAT_S3C24XX、CONFIG_SAMSUNG_DEV_ADC來控制。驅動編寫架構和流程如下

read()

{

1、向adc設備發送要讀取的命令

ADCCON 1《《0 | 1《《14 | 0X1《《16 | 0XFF《《6

2、讀取不到數據就休眠

wait_event_interruptible();

3、等待被喚醒讀數據

havedata = 0;

}

adc_handler()

{

1、清中斷 ADC使用中斷來通知轉換數據完畢的

2、狀態位置位;

havedata=1;

3、喚醒阻塞進程

wake_up()

}

probe()

{

1、讀取中斷號,注冊中斷處理函數

2、讀取寄存器的地址,ioremap

3、字符設備的操作

}

驅動需要首先捕獲中斷信號后再去寄存器讀取相應的數據,在ADC控制器沒有準備好數據之前,應用層需要阻塞讀取數據,所以在讀取數據的函數中,需要借助等待隊列來實現驅動對應用進程的阻塞。驅動程序

驅動程序對寄存器的操作參考裸機程序,只是基地址需要通過ioremap()做映射,對寄存器的讀寫操作需要用readl、writel。

driver.c

#include 《linux/module.h》

#include 《linux/device.h》

#include 《linux/platform_device.h》

#include 《linux/interrupt.h》

#include 《linux/fs.h》

#include 《linux/wait.h》

#include 《linux/sched.h》

#include 《asm/uaccess.h》

#include 《asm/io.h》

static int major = 250;

static wait_queue_head_t wq;

static int have_data = 0;

static int adc;

static struct resource *res1;

static struct resource *res2;

static void *adc_base;

#define ADCCON 0x0000

#define ADCDLY 0x0008

#define ADCDAT 0x000C

#define CLRINTADC 0x0018

#define ADCMUX 0x001C

static irqreturn_t adc_handler(int irqno, void *dev)

{

have_data = 1;

printk(“11111

”);

/*清中斷*/

writel(0x12,adc_base + CLRINTADC);

wake_up_interruptible(&wq);

return IRQ_HANDLED;

}

static int adc_open (struct inode *inod, struct file *filep)

{

return 0;

}

static ssize_t adc_read(struct file *filep, char __user *buf, size_t len, loff_t *pos)

{

writel(0x3,adc_base + ADCMUX);

writel(1《《0 | 1《《14 | 0X1《《16 | 0XFF《《6 ,adc_base +ADCCON );

wait_event_interruptible(wq, have_data==1);

/*read data*/

adc = readl(adc_base+ADCDAT)&0xfff;

if(copy_to_user(buf,&adc,sizeof(int)))

{

return -EFAULT;

}

have_data = 0;

return len;

}

static int adc_release(struct inode *inode, struct file *filep)

{

return 0;

}

static struct file_operations adc_ops =

{

.open = adc_open,

.release = adc_release,

.read = adc_read,

};

static int hello_probe(struct platform_device *pdev)

{

int ret;

printk(“match 0k

”);

res1 = platform_get_resource(pdev,IORESOURCE_IRQ, 0);

res2 = platform_get_resource(pdev,IORESOURCE_MEM, 0);

ret = request_irq(res1-》start,adc_handler,IRQF_DISABLED,“adc1”,NULL);

adc_base = ioremap(res2-》start,res2-》end-res2-》start);

register_chrdev( major, “adc”, &adc_ops);

init_waitqueue_head(&wq);

return 0;

}

static int hello_remove(struct platform_device *pdev)

{

free_irq(res1-》start,NULL);

free_irq(res2-》start,NULL);

unregister_chrdev( major, “adc”);

return 0;

}

static struct of_device_id adc_id[]=

{

{.compatible = “fs4412,adc” },

};

static struct platform_driver hello_driver=

{

.probe = hello_probe,

.remove = hello_remove,

.driver ={

.name = “bigbang”,

.of_match_table = adc_id,

},

};

static int hello_init(void)

{

printk(“hello_init”);

return platform_driver_register(&hello_driver);

}

static void hello_exit(void)

{

platform_driver_unregister(&hello_driver);

printk(“hello_exit

”);

return;

}

MODULE_LICENSE(“GPL”);

module_init(hello_init);

module_exit(hello_exit);

測試程序

test.c

#include 《sys/types.h》

#include 《sys/stat.h》

#include 《fcntl.h》

#include 《stdio.h》

main()

{

int fd,len;

int adc;

fd = open(“/dev/hello”,O_RDWR);

if(fd《0)

{

perror(“open fail

”);

return ;

}

while(1)

{

read(fd,&adc,4);

printf(“adc%0.2f V

”,(1.8*adc)/4096);

}

close(fd);

}

原文標題:16.從0學arm,基于Cortex-A9 ADC裸機驅動詳解

文章出處:【微信公眾號:FPGA之家】歡迎添加關注!文章轉載請注明出處。

責任編輯:haq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • adc
    adc
    +關注

    關注

    98

    文章

    6514

    瀏覽量

    545057
  • 驅動
    +關注

    關注

    12

    文章

    1844

    瀏覽量

    85368

原文標題:16.從0學arm,基于Cortex-A9 ADC裸機驅動詳解

文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    適用于Oracle的dbExpress驅動程序

    (包括社區版)快速訪問 Oracle macOS(32 位和 64 位)和 Linux(64 位)平臺。對于此服務器,dbExpress 將驅動程序作為實現通用 dbExpress 的獨立庫提供 用于
    的頭像 發表于 01-09 16:04 ?53次閱讀
    適用于Oracle的dbExpress<b class='flag-5'>驅動程序</b>

    Linux驅動程序程序員指南

    電子發燒友網站提供《Linux驅動程序程序員指南.pdf》資料免費下載
    發表于 11-22 15:53 ?0次下載
    <b class='flag-5'>Linux</b><b class='flag-5'>驅動程序</b><b class='flag-5'>程序</b>員指南

    pcie設備驅動程序安裝步驟

    PCIe(Peripheral Component Interconnect Express)是一種高速串行計算機擴展總線標準,用于計算機內部硬件組件之間的連接。安裝PCIe設備驅動程序是確保硬件
    的頭像 發表于 11-13 10:32 ?1029次閱讀

    Wilink8 Linux Wi-Fi驅動程序R8.8版用戶指南

    電子發燒友網站提供《Wilink8 Linux Wi-Fi驅動程序R8.8版用戶指南.pdf》資料免費下載
    發表于 11-05 09:19 ?0次下載
    Wilink8 <b class='flag-5'>Linux</b> Wi-Fi<b class='flag-5'>驅動程序</b>R8.8版用戶指南

    硬盤電機怎么驅動程序?它有什么典型特征?

    硬盤電機的驅動程序是硬盤中一個非常重要的組成部分,它負責控制硬盤電機的啟動、停止、轉速調節等操作。硬盤電機驅動程序的設計和實現涉及到電機控制理論、電子技術、計算機編程等多個領域的知識。 一、硬盤電機
    的頭像 發表于 10-22 11:10 ?413次閱讀

    用于bq275xx電量計的WinCE/Linux驅動程序

    電子發燒友網站提供《用于bq275xx電量計的WinCE/Linux驅動程序.pdf》資料免費下載
    發表于 10-17 11:17 ?0次下載
    用于bq275xx電量計的WinCE/<b class='flag-5'>Linux</b><b class='flag-5'>驅動程序</b>

    LSP 2.10 DaVinci Linux驅動程序

    電子發燒友網站提供《LSP 2.10 DaVinci Linux驅動程序.pdf》資料免費下載
    發表于 10-09 09:30 ?0次下載
    LSP 2.10 DaVinci <b class='flag-5'>Linux</b><b class='flag-5'>驅動程序</b>

    Linux設備驅動程序分類有哪些

    Linux設備驅動程序是操作系統與硬件設備之間的橋梁,負責實現硬件設備與操作系統之間的通信和控制。Linux設備驅動程序的分類繁多,可以根據不同的標準進行分類。 按硬件類型分類
    的頭像 發表于 08-30 15:11 ?613次閱讀

    linux驅動程序如何加載進內核

    Linux系統中,驅動程序是內核與硬件設備之間的橋梁。它們允許內核與硬件設備進行通信,從而實現對硬件設備的控制和管理。 驅動程序編寫 驅動程序
    的頭像 發表于 08-30 15:02 ?521次閱讀

    linux驅動程序主要有哪些功能

    Linux驅動程序是操作系統與硬件設備之間進行通信的橋梁,負責實現硬件設備與操作系統之間的數據交換和控制。Linux驅動程序的主要功能包括以下幾個方面: 設備識別與初始化
    的頭像 發表于 08-30 14:47 ?397次閱讀

    linux驅動程序的編譯方法是什么

    Linux驅動程序的編譯方法主要包括兩種: 與內核一起編譯 和 編譯成獨立的內核模塊 。以下是對這兩種方法的介紹: 一、與內核一起編譯 與內核一起編譯意味著將驅動程序的源代碼直接集成到Linu
    的頭像 發表于 08-30 14:46 ?663次閱讀

    linux驅動程序的編譯方法有哪兩種

    Linux驅動程序的編譯方法主要可以歸納為兩種: 手動編譯 和 使用內核構建系統(Makefile)自動編譯 。 1. 手動編譯 手動編譯驅動程序通常涉及直接使用GCC(GNU Compiler
    的頭像 發表于 08-30 14:39 ?806次閱讀

    linux驅動程序運行在什么空間

    Linux 驅動程序是操作系統的一部分,負責管理硬件設備與操作系統之間的交互。驅動程序運行在內核空間(Kernel Space),這是操作系統的核心部分,與用戶空間(User Space)相對。內核
    的頭像 發表于 08-30 14:37 ?455次閱讀

    虹科技術 Linux環境再升級:PLIN驅動程序正式發布

    Linux驅動程序領域再添新成員,PLIN驅動程序現已正式發布。
    的頭像 發表于 06-28 13:34 ?380次閱讀
    虹科技術 <b class='flag-5'>Linux</b>環境再升級:PLIN<b class='flag-5'>驅動程序</b>正式發布

    怎么編寫Framebuffer驅動程序

    Framebuffer 驅動程序框架 分為上下兩層: fbmem.c:承上啟下 實現、注冊 file_operations 結構體 把 APP 的調用向下轉發到具體的硬件驅動程序
    的頭像 發表于 03-22 09:13 ?578次閱讀
    怎么<b class='flag-5'>編寫</b>Framebuffer<b class='flag-5'>驅動程序</b>
    主站蜘蛛池模板: 内射少妇36P亚洲区| qvod电影| 久久中文电影| 粉嫩AV国产一区二区福利姬| 伊人青青久久| 午夜宅宅伦电影网| 男同志china免费视频| 极品少妇伦理一区二区| 福利啪啪吧| 999久久免费高清热精品| 亚洲国产综合另类视频| 揉抓捏打抽插射免费视频| 美女扒开尿孔| 九九99国产香蕉视频| 国产国拍精品AV在线观看| proburn中文破解版下载| 在线视频a| 亚洲野狼综合网站| 午夜天堂一区人妻| 日日噜噜噜夜夜爽爽狠狠图片| 蜜芽TV影院在线视频 | 精品免费在线视频| 国产精品免费观看视频播放| zooskoo1videos人与狗| 99九九精品视频| 97成人精品视频在线播放| 中文字幕午夜福利片| 在线精彩视频在线观看免费| 一本道久在线综合色姐| 亚洲色噜噜狠狠网站| 亚洲精品在线影院| 亚洲国产中文字幕在线视频| 香蕉59tv视频| 亚洲AV 日韩 国产 有码| 无码欧美XXXXX在线观看裸| 日韩 国产 欧美视频二区| 秋霞电影在线观看午夜伦| 青青青青草原国产免费| 人妻满熟妇AV无码区国产| 人妻换人妻AA视频| 肉欲横流(NP高H)|