zoukankan      html  css  js  c++  java
  • 和菜鸟一起学OK6410之ADC模块

            今天,完善了公司第二版的红外遥控器,并且在android上跑起来时也比较灵敏了,GPIO模拟的SPI也可以工作了,看了会书,修正了会,回到宿舍也已经9点多了。想想,OK6410上还有个AD模块呢。网上找了找资料,发现还是可以去尝试下可不可以实现的。好吧,花了我快一个小时了,哈哈,终于搞定了。

            下面看代码:

     

    #include <linux/module.h>  
    
    #include <linux/types.h>  
    
    #include <linux/fs.h>  
    
    #include <linux/errno.h>  
    
    #include <linux/mm.h>  
    
    #include <linux/sched.h>  
    
    #include <linux/init.h>  
    
    #include <linux/cdev.h>  
    
    #include <asm/io.h>  
    
    #include <asm/system.h>  
    
    #include <asm/uaccess.h>  
    
    #include <linux/device.h> /* device_create()*/  
    
    #include <asm/io.h>     
    
    #include <asm/irq.h>     
    
    #include <asm/uaccess.h>     
    
    #include <mach/map.h>     
    
    #include <plat/regs-adc.h>    
    
    #include <mach/map.h>    
    
         
    
      
    
    static void __iomem *base_addr;  
    
        
    
    #define __ADCREG(name)  (*(volatile unsigned long *)(base_addr + name))    
    
    #define ADCCON          __ADCREG(S3C_ADCCON)    // ADC control    
    
    #define ADCDAT0         __ADCREG(S3C_ADCDAT0)   // ADC conversion data 0    
    
       
    
    #define ADC_START           (1 << 0)     
    
      
    
    #define ADC_SIZE    0x1000      
    
    #define ADC_MAJOR   240      
    
      
    
    static int adc_major = ADC_MAJOR;  
    
    struct adc_dev {  
    
        struct cdev cdev;   
    
        unsigned char mem[ADC_SIZE];   
    
    };  
    
      
    
    struct adc_dev *adc_devp;   
    
       
    
    static int adc_init(void)    
    
    {    
    
        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)  
    
    {
    
    printk("$$$$$%s$$$$$\n", __func__);  
    
        adc_init();    
    
     
    
    return 0;  
    
    }  
    
     
    
    static int adc_release(struct inode *inode, struct file *filp)  
    
    {  
    
    printk("$$$$$$%s$$$$$\n", __func__);
    
        return 0;  
    
    }  
    
        
    
    static ssize_t adc_read(struct file *filp, char __user *buf, size_t size,  
    
        loff_t *ppos)  
    
    {  
    
        unsigned int count = size;  
    
        int ret = 0;  
    
    printk("$$$$$%s$$$$$\n", __func__);
    
        ADCCON |= ADC_START;     
    
        while(ADCCON & 0x01);//check if Enable_start is low     
    
        while(!(ADCCON &0x8000));    
    
        ret = ADCDAT0 & 0x3ff;  
    
        count = copy_to_user(buf,(char *)&ret,sizeof(ret));  
    
      
    
    return sizeof(ret);  
    
    }  
    
      
    
    static const struct file_operations adc_fops = {  
    
        .owner = THIS_MODULE,  
    
        .read = adc_read,  
    
        .open = adc_open,  
    
        .release = adc_release,  
    
    };  
    
      
    
    static void adc_setup_cdev(struct adc_dev *dev, int index)  
    
    {  
    
        int err, devno = MKDEV(adc_major, index);  
    
      
    
        cdev_init(&dev->cdev, &adc_fops);  
    
        dev->cdev.owner = THIS_MODULE;  
    
        err = cdev_add(&dev->cdev, devno, 1);  
    
        if (err)  
    
            printk(KERN_NOTICE "Error %d adding LED%d", err, index);  
    
    }  
    
      
    
    struct class *myclass;  
    
      
    
    int adc_dev_init(void)  
    
    {  
    
        int result;  
    
    printk("$$$$$$%s$$$$$$\n", __func__);    
    
        dev_t devno = MKDEV(adc_major, 0);  
    
      
    
        if (adc_major)  
    
            result = register_chrdev_region(devno, 1, "adc");  
    
        else {   
    
            result = alloc_chrdev_region(&devno, 0, 1, "adc");  
    
            adc_major = MAJOR(devno);  
    
        }  
    
        if (result < 0)  
    
            return result;  
    
      
    
        adc_devp = kmalloc(sizeof(struct adc_dev), GFP_KERNEL);  
    
        if (!adc_devp) {      
    
            result =  - ENOMEM;  
    
            goto fail_malloc;  
    
        }  
    
      
    
        memset(adc_devp, 0, sizeof(struct adc_dev));  
    
      
    
        adc_setup_cdev(adc_devp, 0);  
    
      
    
        myclass = class_create(THIS_MODULE,"test_char");  
    
        device_create(myclass, NULL, MKDEV(adc_major,0), NULL, "adc");     
    
      
    
         base_addr = ioremap(0x7E00B000,0X20);     
    
         if(base_addr == NULL)    
    
           {    
    
               printk("failed to remap\n");    
    
               return -ENOMEM;    
    
           }    
    
          
    
        return 0;  
    
      
    
    fail_malloc:  
    
        unregister_chrdev_region(devno, 1);  
    
        return result;  
    
    }  
    
      
    
    void adc_dev_exit(void)  
    
    {  
    
        cdev_del(&adc_devp->cdev);     
    
        kfree(adc_devp);       
    
        unregister_chrdev_region(MKDEV(adc_major, 0), 1);   
    
        class_destroy(myclass);  
    
        device_destroy(myclass,MKDEV(adc_major,0));  
    
        iounmap(base_addr);    
    
    }  
    
      
    
    MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");  
    
    MODULE_LICENSE("Dual BSD/GPL");  
    
      
    
    module_param(adc_major, int, S_IRUGO);  
    
      
    
    module_init(adc_dev_init);  
    
    module_exit(adc_dev_exit);  
    
    


     

            代码不是本人写的,参考的,然后稍微去掉不必要的,加了些测试打印,用以消化。

    看上面的代码,主要用到的就是那两个寄存器了。

            先看下AD模块的原理图和管脚吧

            其管脚是

     

            再来看看这两个寄存器吧

             

     

           

    ADCCON = (1<<14) | (preScaler<<6) | (0<<3) | (0<<2);  
    


            这里的1<<14就是启动AD转换。preScaler<<6就是ADC预定标器值0xff了,0<<3就表示adc通道0,就是这个AD模块了。然后 0 << 2就是正常运作模式了。

            好了分析完控制寄存器那么就是数据寄存器了。

     

    while(ADCCON & 0x01);//check if Enable_start is low     
    
    while(!(ADCCON &0x8000));    
    
    ret = ADCDAT0 & 0x3ff;
    
    


     

             while(ADCCON & 0x01);判断是否AD转换好了。while(!(ADCCON &0x8000));判断AD转换是否结束。 ret = ADCDAT0 & 0x3ff;,正常的ADC转换后的值。

            就这样,搞定了,很简单?还行吧,差不多吧,只能说。

            接着就是makefile了:

     

    obj-m :=adc.o  
    
     
    
    


          然后建个makemod,代码如下

     

    make -C /home/eastmoon/work/linux2.6.28/ M=`pwd` modules  
    
    


     

            然后只要source makemod就可以编译成buzzer.ko

     

            OK,驱动就这么着了,然后就是应用程序了

     

    #include <stdio.h>     
    
    #include <fcntl.h>     
    
    #include <unistd.h>     
    
       
    
    #define DEVICE "/dev/myadc"
    
     
    
    int main()    
    
    {    
    
        int fp,adc_data,i;  
    
        int ret;  
    
        fp = open(DEVICE, O_RDWR);    
    
        if(fp < 0)  
    
        {
    
            printf("open failed!\n"); 
    
            return -1; 
    
        }
    
          
    
        while(1) 
    
        {    
    
            ret = read(fp,&adc_data,sizeof(adc_data));    
    
            if(ret<0)  
    
            {  
    
                printf("read ADC failed!\n");  
    
                return -1;  
    
            }  
    
            else  
    
            {
    
               printf("Read ADC value is: %d\n",adc_data);    
    
            }
    
            sleep(1);    
    
        }    
    
        close(fp);    
    
    return 0;    
    
    }
    
    


     

            接着makefile

    CC = /usr/local/arm/4.2.2-eabi/usr/bin/arm-linux-gcc 
    
     
    
    adcapp:adcapp.o
    
           $(CC) -o adcapp adcapp.o
    
    adcapp.o:adcapp.c 
    
           $(CC) -c adcapp.c
    
     
    
    clean :
    
           rm adcapp.o
    
    


            终于搞定,于是便是到板子上去调试了。把adc.koadcapp拷贝到SD卡上,然后再拷贝到板子上。开始测试:

            Init进去了,没提示错误,表示一切OK

            接着mknod设备文件

            好了,设备节点OK,接着就是测试程序了。

            一开始电位器的位置是这样的,然后旋转电位器

            再旋转范围大点的:

            最后结束:

     

            OK,测试都通过了,明天就是周五了,又是周末了,天气是越来越热了,继续努力。发现自己的知识体系还远远不够,和同事相比还是有很大的差别啊。加油,come on。。。。

  • 相关阅读:
    DIV3E 基环树
    Codeforces Round #663 (Div. 2) D.505
    统计2进制中1的数量
    bitset 用法笔记
    扩展欧几里得
    KM算法(二分图最大权匹配)
    C1. Errich-Tac-Toe (Easy Version) 米奇妙妙屋
    求逆元
    python——标识符及其命名规则
    python基础——python对象概述
  • 原文地址:https://www.cnblogs.com/wuyida/p/6300082.html
Copyright © 2011-2022 走看看