feiyang10086 发表于 2011-12-11 16:24

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

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为例:

①简介:


.


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

②特性:


③配置:如果简单的驱动ad,只配置ADCCON寄存器即可,如要实现触摸屏的工能则要其他寄存器


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

三、linux中的adc驱动程序及注释view plaincopy to clipboardprint?
01.#include <linux/kernel.h>   
02.#include <linux/module.h>   
03.#include <linux/slab.h>   
04.#include <linux/input.h>   
05.#include <linux/init.h>   
06.#include <linux/errno.h>   
07.#include <linux/serio.h>   
08.#include <linux/delay.h>   
09.#include <linux/clk.h>   
10.#include <linux/sched.h>   
11.#include <linux/cdev.h>   
12.#include <linux/miscdevice.h>   
13.
14.
15.#include <asm/io.h>   
16.#include <asm/irq.h>   
17.#include <asm/uaccess.h>   
18.
19.#include <mach/map.h>   
20.#include <mach/regs-clock.h>   
21.#include <mach/regs-gpio.h>   
22.#include <plat/regs-adc.h>   
23.static void __iomem * base_addr;
24.static struct clk *adc_clock;
25.
26.
27.#define __ADCREG(name)(*(volatile unsigned long *)(base_addr + name))   
28.#define ADCCON          __ADCREG(S3C_ADCCON)    // ADC control   
29.#define ADCTSC          __ADCREG(S3C_ADCTSC)    // ADC touch screen control   
30.#define ADCDLY          __ADCREG(S3C_ADCDLY)    // ADC start or Interval Delay   
31.#define ADCDAT0         __ADCREG(S3C_ADCDAT0)   // ADC conversion data 0   
32.#define ADCDAT1         __ADCREG(S3C_ADCDAT1)   // ADC conversion data 1   
33.#define ADCUPDN         __ADCREG(S3C_ADCUPDN)   // Stylus Up/Down interrupt status   
34.
35.#define PRESCALE_DIS      (0 << 14)   
36.#define PRESCALE_EN         (1 << 14)   
37.#define PRSCVL(x)         ((x) << 6)   
38.#define ADC_INPUT(x)      ((x) << 3)   
39.#define ADC_START         (1 << 0)   
40.#define ADC_ENDCVT          (1 << 15)   
41.
42.#define DEVICE_NAME "adc_dev"   
43.static int adc_init()
44.{
45.    unsigned int preScaler = 0XFF;
46.    ADCCON = (1<<14)|(preScaler<<6)|(0<<3)|(0<<2);
47.    ADCCON |= ADC_START;   
48.    return 0;
49.}
50.static int adc_open(struct inode *inode ,struct file *filp)
51.{
52.    adc_init();
53.    return 0;
54.}
55.static int adc_release(struct inode *inode,struct file *filp)
56.{
57.    return 0;
58.}
59.static ssize_t adc_read(struct file *filp,char __user *buff,size_t size,loff_t *ppos)
60.{
61.    ADCCON |= ADC_START;   
62.    while(ADCCON & 0x01);//check if Enable_start is low   
63.    while(!(ADCCON &0x8000));/*检查转换是否结束*/
64.    return (ADCDAT0 & 0x3ff);
65.}
66.
67.static struct file_operations dev_fops =
68.{
69.    .owner = THIS_MODULE,
70.    .open = adc_open,
71.    .release = adc_release,
72.    .read = adc_read,
73.};
74.
75.static struct miscdevice misc =
76.{
77.    .minor = MISC_DYNAMIC_MINOR,
78.    .name = DEVICE_NAME,
79.    .fops = &dev_fops,
80.};
81.
82.static int __init dev_init()
83.{
84.    int ret;
85.
86.
87.    base_addr =ioremap(SAMSUNG_PA_ADC,0X20);//地址映射   
88.    if(base_addr == NULL)
89.    {
90.      printk(KERN_ERR"failed to remap\n");
91.      return -ENOMEM;
92.    }
93.
94.    adc_clock = clk_get(NULL,"adc");//激活adc时钟模块   
95.    if(!adc_clock)
96.    {
97.      printk(KERN_ERR"failed to get adc clock\n");
98.      return -ENOENT;
99.    }
100.    clk_enable(adc_clock);
101.
102.
103.    ret = misc_register(&misc);//混杂设备注册   
104.    printk("dev_init return ret:%d\n",ret);
105.    return ret;
106.}
107.static void __exit dev_exit()
108.{
109.    iounmap(base_addr);//取消映射   
110.      
111.    if(adc_clock)//disable adc clock取消adc时钟   
112.    {
113.      clk_disable(adc_clock);
114.      clk_put(adc_clock);
115.      adc_clock =NULL;
116.    }
117.    misc_deregister(&misc);//注销混杂设备   
118.      
119.}
120.module_init(dev_init);
121.module_exit(dev_exit);
122.
123.MODULE_LICENSE("GPL");
124.MODULE_AUTHOR("MUGE0913");
#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");四、测试程序view plaincopy to clipboardprint?
01.#include <stdio.h>   
02.#include <fcntl.h>   
03.#include <unistd.h>   
04.
05.int main()
06.{
07.    int fp,adc_data,i;
08.    fp = open("/dev/adc_dev",O_RDWR);
09.    for(i=0;i<100;i++)
10.    {
11.    adc_data = read(fp,NULL,0);
12.    printf("%d\n",adc_data);
13.    sleep(1);
14.    }
15.    close(fp);
16.    return 0;
17.}
#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;
}五、运行效果


小忻黑夜 发表于 2011-12-22 18:49

学习鸟谢谢分享

Unix-wang 发表于 2012-11-11 18:41

多路接入如何处理?通道选择如何处理?不同通道性能要求不同如何配置?
页: [1]
查看完整版本: mini6410 实现 linux adc驱动详解--muge0913版 .