mini6410 实现 linux adc驱动详解--muge0913版

   在嵌入式学习中嵌入式linux驱动占据着十分重要的地位,它不仅牵扯到操作系统、linux内核知识,同时作为开发者你必须了解面对的硬件体系结构和工作原理。在这本人muge0913对linux ad开发做了详细的介绍。

此文章仅供技术交流请勿商用。转载请注明出处:

http://blog.csdn.net/muge0913/article/details/7059241


一、ad转换器介绍

   在这里我们先从adc的工作原理出发,由浅入深的学习,对于已经掌握adc硬件知识的阅读者可跳过此部分。

adc的基础知识我们可直接参考郭天祥老师的教材,免积分下载地址:

http://download.csdn.net/detail/muge0913/3903535


二、ARM中ad转换器介绍

   这里我们以arm11为例:

①简介:

mini6410 实现 linux adc驱动详解--muge0913版_第1张图片.

   10-bit/12-bit的CMOSADC模数转换器一个8通道模拟输入回收设备5MHz的A / D转换时钟最高转换率1MSPS转换10-bit/12-bit二进制数字编码模拟输入信号A / D转换片上采样和保持功能支持省电模式

②特性:
mini6410 实现 linux adc驱动详解--muge0913版_第2张图片

③配置:如果简单的驱动ad,只配置ADCCON寄存器即可,如要实现触摸屏的工能则要其他寄存器
mini6410 实现 linux adc驱动详解--muge0913版_第3张图片

注:在下面代码中我们由此部分的注释

三、linux中的adc驱动程序及注释

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>


#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>

#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/regs-adc.h>
static void __iomem * base_addr;
static struct clk *adc_clock;


#define __ADCREG(name)	(*(volatile unsigned long *)(base_addr + name))
#define ADCCON			__ADCREG(S3C_ADCCON)	// ADC control
#define ADCTSC			__ADCREG(S3C_ADCTSC)	// ADC touch screen control
#define ADCDLY			__ADCREG(S3C_ADCDLY)	// ADC start or Interval Delay
#define ADCDAT0			__ADCREG(S3C_ADCDAT0)	// ADC conversion data 0
#define ADCDAT1			__ADCREG(S3C_ADCDAT1)	// ADC conversion data 1
#define ADCUPDN			__ADCREG(S3C_ADCUPDN)	// 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)

#define DEVICE_NAME "adc_dev"
static int adc_init()
{
	unsigned int preScaler = 0XFF;
	ADCCON = (1<<14)|(preScaler<<6)|(0<<3)|(0<<2);
	ADCCON |= ADC_START; 
	return 0;
}
static int adc_open(struct inode *inode ,struct file *filp)
{
	adc_init();
	return 0;
}
static int adc_release(struct inode *inode,struct file *filp)
{
	return 0;
}
static ssize_t adc_read(struct file *filp,char __user *buff,size_t size,loff_t *ppos)
{
	ADCCON |= ADC_START; 
	while(ADCCON & 0x01);//check if Enable_start is low
	while(!(ADCCON &0x8000));/*检查转换是否结束*/
	return (ADCDAT0 & 0x3ff);
}

static struct file_operations dev_fops =
{
	.owner = THIS_MODULE,
	.open = adc_open,
	.release = adc_release,
	.read = adc_read,
};

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

static int __init dev_init()
{
	int ret;


	base_addr =ioremap(SAMSUNG_PA_ADC,0X20);//地址映射
	if(base_addr == NULL)
	{
		printk(KERN_ERR"failed to remap\n");
		return -ENOMEM;
	}

	adc_clock = clk_get(NULL,"adc");//激活adc时钟模块
	if(!adc_clock)
	{
		printk(KERN_ERR"failed to get adc clock\n");
		return -ENOENT;
	}
	clk_enable(adc_clock);


	ret = misc_register(&misc);//混杂设备注册
	printk("dev_init return ret:%d\n",ret);
	return ret;
}
static void __exit dev_exit()
{
	iounmap(base_addr);//取消映射
	
	if(adc_clock)//disable adc clock取消adc时钟
	{
		clk_disable(adc_clock);
		clk_put(adc_clock);
		adc_clock =NULL;
	}
	misc_deregister(&misc);//注销混杂设备
	
}
module_init(dev_init);
module_exit(dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("MUGE0913");

四、测试程序

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
	int fp,adc_data,i;
	fp = open("/dev/adc_dev",O_RDWR);
	for(i=0;i<100;i++)
	{
	adc_data = read(fp,NULL,0);
	printf("%d\n",adc_data);
	sleep(1);
	}
	close(fp);
	return 0;
}


五、运行效果

mini6410 实现 linux adc驱动详解--muge0913版_第4张图片



你可能感兴趣的:(linux,struct,Module,File,null,linux内核)