成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

linuxadc設(shè)備指的是什么

這篇文章主要介紹了linux adc設(shè)備指的是什么的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇linux adc設(shè)備指的是什么文章都會(huì)有所收獲,下面我們一起來(lái)看看吧。

站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到定日網(wǎng)站設(shè)計(jì)與定日網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名與空間、虛擬主機(jī)、企業(yè)郵箱。業(yè)務(wù)覆蓋定日地區(qū)。

linux adc是混雜設(shè)備驅(qū)動(dòng);在linux2.6.30.4中,系統(tǒng)已經(jīng)自帶有了ADC通用驅(qū)動(dòng)文件“arch/arm/plat-s3c24xx/adc.c”,它是以平臺(tái)驅(qū)動(dòng)設(shè)備模型的架構(gòu)來(lái)編寫(xiě)的,里面是一些比較通用穩(wěn)定的代碼。

linux2.6.30.4中,系統(tǒng)已經(jīng)自帶有了ADC通用驅(qū)動(dòng)文件---arch/arm/plat-s3c24xx/adc.c,它是以平臺(tái)驅(qū)動(dòng)設(shè)備模型的架構(gòu)來(lái)編寫(xiě)的,里面是一些比較通用穩(wěn)定的代碼,但是linux2.6.30.4版本的ADC通用驅(qū)動(dòng)文件并不完善,居然沒(méi)有讀函數(shù)。后來(lái)去看了linux3.8版本的ADC通用文件----arch/arm/plat-samsung/adc.c才是比較完善的。

但是本節(jié)并不是分析這個(gè)文件,而是以另外一種架構(gòu)來(lái)編寫(xiě)ADC驅(qū)動(dòng),因?yàn)锳DC驅(qū)動(dòng)實(shí)在是比較簡(jiǎn)單,就沒(méi)有使用平臺(tái)驅(qū)動(dòng)設(shè)備模型為架構(gòu)來(lái)編寫(xiě)了,這次我們使用的是混雜(misc)設(shè)備驅(qū)動(dòng)。

問(wèn):什么是misc設(shè)備驅(qū)動(dòng)?

答:miscdevice共享一個(gè)主設(shè)備號(hào)MISC_MAJOR(10),但次設(shè)備號(hào)不同。所有的miscdevice設(shè)備形成一條鏈表,對(duì)設(shè)備訪問(wèn)時(shí)內(nèi)核根據(jù)設(shè)備號(hào)來(lái)查找對(duì)應(yīng)的miscdevice設(shè)備,然后調(diào)用其file_operations結(jié)構(gòu)體中注冊(cè)的文件操作接口進(jìn)行操作。

struct miscdevice  {
	int minor;				//次設(shè)備號(hào),如果設(shè)置為MISC_DYNAMIC_MINOR則系統(tǒng)自動(dòng)分配
	const char *name;		//設(shè)備名
	const struct file_operations *fops;		//操作函數(shù)
	struct list_head list;
	struct device *parent;
	struct device *this_device;
};

dev_init入口函數(shù)分析:

static int __init dev_init(void)
{
	int ret;

	base_addr=ioremap(S3C2410_PA_ADC,0x20);
	if (base_addr == NULL)
	{
		printk(KERN_ERR "failed to remap register block\n");
		return -ENOMEM;
	}

	adc_clock = clk_get(NULL, "adc");
	if (!adc_clock)
	{
		printk(KERN_ERR "failed to get adc clock source\n");
		return -ENOENT;
	}
	clk_enable(adc_clock);
	
	ADCTSC = 0;

	ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);
	if (ret)
	{
		iounmap(base_addr);
		return ret;
	}

	ret = misc_register(&misc);

	printk (DEVICE_NAME" initialized\n");
	return ret;
}

首先是映射ADC寄存器地址將其轉(zhuǎn)換為虛擬地址,然后獲得ADC時(shí)鐘并使能ADC時(shí)鐘,接著申請(qǐng)ADC中斷,其中斷處理函數(shù)為

adcdone_int_handler,而flags為IRQF_SHARED,即共享中斷,因?yàn)橛|摸屏里也要申請(qǐng)ADC中斷,最后注冊(cè)一個(gè)混雜設(shè)備。

當(dāng)應(yīng)用程序open ("/dev/adc",...)時(shí),就會(huì)調(diào)用到驅(qū)動(dòng)里面的open函數(shù),那么我們來(lái)看看open函數(shù)做了什么?

static int tq2440_adc_open(struct inode *inode, struct file *filp)
{
	/* 初始化等待隊(duì)列頭 */
	init_waitqueue_head(&(adcdev.wait));

	/* 開(kāi)發(fā)板上ADC的通道2連接著一個(gè)電位器 */
	adcdev.channel=2;	//設(shè)置ADC的通道
	adcdev.prescale=0xff;

	DPRINTK( "ADC opened\n");
	return 0;
}

很簡(jiǎn)單,先初始化一個(gè)等待隊(duì)列頭,因?yàn)槿肟诤瘮?shù)里既然有申請(qǐng)ADC中斷,那么肯定要使用等待隊(duì)列,接著設(shè)置ADC通道,因?yàn)門Q2440的ADC輸入通道默認(rèn)是2,設(shè)置預(yù)分頻值為0xff。

當(dāng)應(yīng)用程序read時(shí),就會(huì)調(diào)用到驅(qū)動(dòng)里面的read函數(shù),那么我們來(lái)看看read函數(shù)做了些什么?

static ssize_t tq2440_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
	char str[20];
	int value;
	size_t len;

	/* 嘗試獲得ADC_LOCK信號(hào)量,如果能夠立刻獲得,它就獲得信號(hào)量并返回0 
	 * 否則,返回非零,它不會(huì)導(dǎo)致調(diào)用者睡眠,可以在中斷上下文使用
	 */
	if (down_trylock(&ADC_LOCK) == 0)
	{
		/* 表示A/D轉(zhuǎn)換器資源可用 */
		ADC_enable = 1;

		/* 使能預(yù)分頻,選擇ADC通道,最后啟動(dòng)ADC轉(zhuǎn)換*/
		START_ADC_AIN(adcdev.channel, adcdev.prescale);

		/* 等待事件,當(dāng)ev_adc = 0時(shí),進(jìn)程被阻塞,直到ev_adc>0 */
		wait_event_interruptible(adcdev.wait, ev_adc);

		ev_adc = 0;

		DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ((ADCCON & 0x80) ? 1:0));

		/* 將在ADC中斷處理函數(shù)讀取的ADC轉(zhuǎn)換結(jié)果賦值給value */
		value = adc_data;
		sprintf(str,"%5d", adc_data);
		copy_to_user(buffer, (char *)&adc_data, sizeof(adc_data));

		ADC_enable = 0;
		up(&ADC_LOCK);
	}
	else
	{
		/* 如果A/D轉(zhuǎn)換器資源不可用,將value賦值為-1 */
		value = -1;
	}

	/* 將ADC轉(zhuǎn)換結(jié)果輸出到str數(shù)組里,以便傳給應(yīng)用空間 */
	len = sprintf(str, "%d\n", value);
	if (count >= len)
	{
		/* 從str數(shù)組里拷貝len字節(jié)的數(shù)據(jù)到buffer,即將ADC轉(zhuǎn)換數(shù)據(jù)傳給應(yīng)用空間 */
		int r = copy_to_user(buffer, str, len);
		return r ? r : len;
	}
	else
	{
		return -EINVAL;
	}
}

tq2440_adc_read函數(shù)首先嘗試獲得ADC_LOCK信號(hào)量,因?yàn)橛|摸屏驅(qū)動(dòng)也有使用ADC資源,兩者互有競(jìng)爭(zhēng)關(guān)系,獲得ADC資源后,使能預(yù)分頻,選擇ADC通道,最后啟動(dòng)ADC轉(zhuǎn)換,接著就調(diào)用wait_event_interruptible 函數(shù)進(jìn)行等待,直到ev_adc>0進(jìn)程才會(huì)繼續(xù)往下跑,往下跑就會(huì)將adc_data數(shù)據(jù)讀出來(lái),調(diào)用copy_to_user函數(shù)將ADC數(shù)據(jù)傳給應(yīng)用空間,最后釋放ADC_LOCK信號(hào)量。

問(wèn):什么時(shí)候ev_adc>0?默認(rèn)ev_adc = 0

答:在adcdone_int_handler中斷處理函數(shù)里,等數(shù)據(jù)讀出后,ev_adc被設(shè)置為1。

ADC中斷處理函數(shù)adcdone_int_handler

/* ADC中斷處理函數(shù) */
static irqreturn_t adcdone_int_handler(int irq, void *dev_id)
{
	/* A/D轉(zhuǎn)換器資源可用 */
	if (ADC_enable)
	{
		/* 讀ADC轉(zhuǎn)換結(jié)果數(shù)據(jù) */
		adc_data = ADCDAT0 & 0x3ff;

		/* 喚醒標(biāo)志位,作為wait_event_interruptible的喚醒條件 */
		ev_adc = 1;
		wake_up_interruptible(&adcdev.wait);
	}
	return IRQ_HANDLED;
}

當(dāng)AD轉(zhuǎn)換完成后就會(huì)觸發(fā)ADC中斷,就會(huì)進(jìn)入adcdone_int_handler,這個(gè)函數(shù)就會(huì)講AD轉(zhuǎn)換數(shù)據(jù)讀到adc_data,接著將喚醒標(biāo)志位ev_adc置1,最后調(diào)用wake_up_interruptible函數(shù)喚醒a(bǔ)dcdev.wait等待隊(duì)列。
總結(jié)一下ADC的工作流程:

一、open函數(shù)里,設(shè)置模擬輸入通道,設(shè)置預(yù)分頻值

二、read函數(shù)里,啟動(dòng)AD轉(zhuǎn)換,進(jìn)程休眠

三、adc_irq函數(shù)里,AD轉(zhuǎn)換結(jié)束后觸發(fā)ADC中斷,在ADC中斷處理函數(shù)將數(shù)據(jù)讀出,喚醒進(jìn)程

四、read函數(shù)里,進(jìn)程被喚醒后,將adc轉(zhuǎn)換數(shù)據(jù)傳給應(yīng)用程序

ADC驅(qū)動(dòng)參考源碼:

/*************************************

NAME:EmbedSky_adc.c
COPYRIGHT:www.embedsky.net

*************************************/

#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h>
	 
#include <plat/regs-adc.h>
#include <mach/regs-gpio.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>

#include "tq2440_adc.h"

#undef DEBUG
//#define DEBUG
#ifdef DEBUG
#define DPRINTK(x...) {printk(KERN_DEBUG "EmbedSky_adc: " x);}
#else
#define DPRINTK(x...) (void)(0)
#endif

#define DEVICE_NAME	"adc"		/* 設(shè)備節(jié)點(diǎn): /dev/adc */

static void __iomem *base_addr;

typedef struct
{
	wait_queue_head_t wait;		/* 定義等待隊(duì)列頭 */
	int channel;
	int prescale;
}ADC_DEV;

DECLARE_MUTEX(ADC_LOCK);	/* 定義并初始化信號(hào)量,并初始化為1 */
static int ADC_enable = 0;			/* A/D轉(zhuǎn)換器資是否可用標(biāo)志位 */

static ADC_DEV adcdev;				/* 用于表示ADC設(shè)備 */
static volatile int ev_adc = 0;		/* 作為wait_event_interruptible的喚醒條件 */
static int adc_data;

static struct clk	*adc_clock;

#define ADCCON		(*(volatile unsigned long *)(base_addr + S3C2410_ADCCON))	//ADC control
#define ADCTSC		(*(volatile unsigned long *)(base_addr + S3C2410_ADCTSC))	//ADC touch screen control
#define ADCDLY		(*(volatile unsigned long *)(base_addr + S3C2410_ADCDLY))	//ADC start or Interval Delay
#define ADCDAT0		(*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT0))	//ADC conversion data 0
#define ADCDAT1		(*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT1))	//ADC conversion data 1
#define ADCUPDN		(*(volatile unsigned long *)(base_addr + 0x14))			//Stylus Up/Down interrupt status

#define PRESCALE_DIS	(0 << 14)
#define PRESCALE_EN		(1 << 14)
#define PRSCVL(x)		((x) << 6)
#define ADC_INPUT(x)	((x) << 3)
#define ADC_START		(1 << 0)
#define ADC_ENDCVT		(1 << 15)


/* 使能預(yù)分頻,選擇ADC通道,最后啟動(dòng)ADC轉(zhuǎn)換*/
#define START_ADC_AIN(ch, prescale) \
	do{ 	ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \
		ADCCON |= ADC_START; \
	}while(0)


/* ADC中斷處理函數(shù) */
static irqreturn_t adcdone_int_handler(int irq, void *dev_id)
{
	/* A/D轉(zhuǎn)換器資源可用 */
	if (ADC_enable)
	{
		/* 讀ADC轉(zhuǎn)換結(jié)果數(shù)據(jù) */
		adc_data = ADCDAT0 & 0x3ff;

		/* 喚醒標(biāo)志位,作為wait_event_interruptible的喚醒條件 */
		ev_adc = 1;
		wake_up_interruptible(&adcdev.wait);
	}
	return IRQ_HANDLED;
}

static ssize_t tq2440_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
	char str[20];
	int value;
	size_t len;

	/* 嘗試獲得ADC_LOCK信號(hào)量,如果能夠立刻獲得,它就獲得信號(hào)量并返回0 
	 * 否則,返回非零,它不會(huì)導(dǎo)致調(diào)用者睡眠,可以在中斷上下文使用
	 */
	if (down_trylock(&ADC_LOCK) == 0)
	{
		/* 表示A/D轉(zhuǎn)換器資源可用 */
		ADC_enable = 1;

		/* 使能預(yù)分頻,選擇ADC通道,最后啟動(dòng)ADC轉(zhuǎn)換*/
		START_ADC_AIN(adcdev.channel, adcdev.prescale);

		/* 等待事件,當(dāng)ev_adc = 0時(shí),進(jìn)程被阻塞,直到ev_adc>0 */
		wait_event_interruptible(adcdev.wait, ev_adc);

		ev_adc = 0;

		DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ((ADCCON & 0x80) ? 1:0));

		/* 將在ADC中斷處理函數(shù)讀取的ADC轉(zhuǎn)換結(jié)果賦值給value */
		value = adc_data;
		sprintf(str,"%5d", adc_data);
		copy_to_user(buffer, (char *)&adc_data, sizeof(adc_data));

		ADC_enable = 0;
		up(&ADC_LOCK);
	}
	else
	{
		/* 如果A/D轉(zhuǎn)換器資源不可用,將value賦值為-1 */
		value = -1;
	}

	/* 將ADC轉(zhuǎn)換結(jié)果輸出到str數(shù)組里,以便傳給應(yīng)用空間 */
	len = sprintf(str, "%d\n", value);
	if (count >= len)
	{
		/* 從str數(shù)組里拷貝len字節(jié)的數(shù)據(jù)到buffer,即將ADC轉(zhuǎn)換數(shù)據(jù)傳給應(yīng)用空間 */
		int r = copy_to_user(buffer, str, len);
		return r ? r : len;
	}
	else
	{
		return -EINVAL;
	}
}

static int tq2440_adc_open(struct inode *inode, struct file *filp)
{
	/* 初始化等待隊(duì)列頭 */
	init_waitqueue_head(&(adcdev.wait));

	/* 開(kāi)發(fā)板上ADC的通道2連接著一個(gè)電位器 */
	adcdev.channel=2;	//設(shè)置ADC的通道
	adcdev.prescale=0xff;

	DPRINTK( "ADC opened\n");
	return 0;
}

static int tq2440_adc_release(struct inode *inode, struct file *filp)
{
	DPRINTK( "ADC closed\n");
	return 0;
}


static struct file_operations dev_fops = {
	owner:	THIS_MODULE,
	open:	tq2440_adc_open,
	read:	tq2440_adc_read,	
	release:	tq2440_adc_release,
};

static struct miscdevice misc = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEVICE_NAME,
	.fops = &dev_fops,
};

static int __init dev_init(void)
{
	int ret;

	base_addr=ioremap(S3C2410_PA_ADC,0x20);
	if (base_addr == NULL)
	{
		printk(KERN_ERR "failed to remap register block\n");
		return -ENOMEM;
	}

	adc_clock = clk_get(NULL, "adc");
	if (!adc_clock)
	{
		printk(KERN_ERR "failed to get adc clock source\n");
		return -ENOENT;
	}
	clk_enable(adc_clock);
	
	ADCTSC = 0;

	ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);
	if (ret)
	{
		iounmap(base_addr);
		return ret;
	}

	ret = misc_register(&misc);

	printk (DEVICE_NAME" initialized\n");
	return ret;
}

static void __exit dev_exit(void)
{
	free_irq(IRQ_ADC, &adcdev);
	iounmap(base_addr);

	if (adc_clock)
	{
		clk_disable(adc_clock);
		clk_put(adc_clock);
		adc_clock = NULL;
	}

	misc_deregister(&misc);
}

EXPORT_SYMBOL(ADC_LOCK);
module_init(dev_init);
module_exit(dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("www.embedsky.net");
MODULE_DESCRIPTION("ADC Drivers for EmbedSky SKY2440/TQ2440 Board and support touch");

ADC應(yīng)用測(cè)試參考源碼:

/*************************************

NAME:EmbedSky_adc.c
COPYRIGHT:www.embedsky.net

*************************************/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <errno.h>
#include <string.h>

int main(void)
{
	int fd ;
	char temp = 1;

	fd = open("/dev/adc", 0);
	if (fd < 0)
	{
		perror("open ADC device !");
		exit(1);
	}
	
	for( ; ; )
	{
		char buffer[30];
		int len ;

		len = read(fd, buffer, sizeof buffer -1);
		if (len > 0)
		{
			buffer[len] = '\0';
			int value;
			sscanf(buffer, "%d", &value);
			printf("ADC Value: %d\n", value);
		}
		else
		{
			perror("read ADC device !");
			exit(1);
		}
		sleep(1);
	}
adcstop:	
	close(fd);
}

測(cè)試結(jié)果:

[WJ2440]# ./adc_test 
ADC Value: 693
ADC Value: 695
ADC Value: 694
ADC Value: 695
ADC Value: 702
ADC Value: 740
ADC Value: 768
ADC Value: 775
ADC Value: 820
ADC Value: 844
ADC Value: 887
ADC Value: 937
ADC Value: 978
ADC Value: 1000
ADC Value: 1023
ADC Value: 1023
ADC Value: 1023

關(guān)于“l(fā)inux adc設(shè)備指的是什么”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“l(fā)inux adc設(shè)備指的是什么”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

當(dāng)前名稱:linuxadc設(shè)備指的是什么
鏈接分享:http://jinyejixie.com/article0/ggipio.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)、手機(jī)網(wǎng)站建設(shè)、建站公司、、網(wǎng)站設(shè)計(jì)公司、網(wǎng)站維護(hù)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)
江口县| 商都县| 苍梧县| 台山市| 城固县| 澎湖县| 洛隆县| 大邑县| 喜德县| 昌邑市| 新绛县| 德阳市| 扶余县| 双流县| 馆陶县| 定安县| 沙河市| 阳信县| 岗巴县| 临漳县| 辽阳市| 株洲县| 措勤县| 紫云| 贵溪市| 汝城县| 多伦县| 慈溪市| 栾川县| 安庆市| 新干县| 依兰县| 奉贤区| 翼城县| 平安县| 新竹县| 旺苍县| 修水县| 峨山| 天门市| 吉水县|