FL2440—独立ADC驱动模块

来源:互联网 发布:橘子vr软件下载 编辑:程序博客网 时间:2024/05/22 02:27

fl2440 ADC驱动编写

前面的学习中多次了解到linux内核对于各种常见驱动的支持相当的好,ADC也不例外。但是为了驱动的学习,参考datasheet的内容以及网友的博客文章,依然自己编写单独的ADC驱动模块。下面对ADC驱动的学习做一个简单的总结。

在s3c2440中集成了一个8通道的10位ADC,其从有4个通道即XP, XM, YP, YM连接到触摸屏的接口,用来检测转换触摸屏的模拟信号。剩下的4个通道A0,A1,A2,A3可以外接设备采集外设的模拟信号。其最高转换速率可达到5KHz.
这里写图片描述
在FL2440的开发板上,ADC的通道0外接一个电位器CN3,当调节电位器CN3的阻值,通道0采集到的电压值会随之在0~3.3V 的范围变化。
这里写图片描述

驱动程序&&测试程序

参考datasheet和网上的博客文章,下面是本人编写的驱动和测试程序。

  • 驱动程序
/******************************************************************************** *      Copyright:  (C) 2017 Li Wanneng<liwjng@gmail.com> *                  All rights reserved. * *       Filename:  s3c_adc.h *    Description:  This head file is a driver for adc * *        Version:  1.0.0(04/21/2017) *         Author:  Li Wanneng <liwjng@gmail.com> *      ChangeLog:  1, Release initial version on "04/21/2017 02:43:21 PM" *                  ********************************************************************************/#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <plat/regs-adc.h>#include <linux/errno.h>#include <asm/uaccess.h>    /* copy_to_user copy_from_user */#include <linux/input.h>#include <linux/serio.h>#include <linux/clk.h>#include <linux/sched.h>#include <linux/cdev.h>#include <linux/wait.h>#include <asm/io.h>#include <linux/ioport.h>#define DRV_AUTHOR          "Liwanneng <liwjng@gmail.com>"#define DRV_DESC            "S3C2440 ADC DRIVER"#define DEV_NAME             "S3C_ADC"/* Set ADC dev major number*/#ifndef ADC_MAJOR#define ADC_MAJOR       0#endif#define DRV_MAJOR_VER             1#define DRV_MINOR_VER             0#define DRV_REVER_VER             0#define DISABLE                   0#define ENABLE                    1#define S3C_ADC_CON              0x58000000#define S3C_CON_LEN              4#define S3C_ADC_DATA             0x5800000C#define S3C_DATA_LEN             4#define PRSC_EN                  1#define PRSC_VAL                 49#define SEL_MUX                  0static void __iomem *adc_con; static void __iomem *adc_data;#define s3c_adc_write(val, reg) __raw_writel((val),(reg))#define s3c_adc_read(reg)       __raw_readl((reg))static struct clk *adc_clk;DEFINE_MUTEX(ADC_CLK); int debug = DISABLE;int dev_cnt = 1;int dev_major = ADC_MAJOR;int dev_minor = 0;static struct cdev *adc_cdev;static ssize_t adc_read(struct file *file, char *buff, size_t count,loff_t *ppos){    unsigned temp;    volatile unsigned long adc_value;    adc_con = ioremap(S3C_ADC_CON, S3C_CON_LEN);    adc_data = ioremap(S3C_ADC_DATA,S3C_DATA_LEN);    temp = s3c_adc_read(adc_con);    temp = (PRSC_EN << 14) | (PRSC_VAL << 6) | (SEL_MUX << 3);/* 0 1 00000011 000 0 0 0 */    s3c_adc_write(temp, adc_con);/* Enable prescaler */    temp = s3c_adc_read(adc_con);    temp = temp | (1 << 0);     s3c_adc_write(temp, adc_con); /* Enable ADC Conversion start */    printk(KERN_INFO "write in kernel.\n");    while(s3c_adc_read(adc_con) &0x1);     printk(KERN_INFO "write in kernel.\n");    while(!(s3c_adc_read(adc_con) &0x8000));     printk(KERN_INFO "will lock in kernel.\n");    mutex_lock(&ADC_CLK); /* Lock */    printk(KERN_INFO "locked in kernel.\n");    adc_value = s3c_adc_read(adc_data) &0x3ff;/* Acquire adc_value */    printk(KERN_INFO "adc_value getted.\n");    copy_to_user(buff, (char *)&adc_value, sizeof(adc_value));    mutex_unlock(&ADC_CLK);/* Unlock */    return sizeof(adc_value);}static int adc_open(struct inode *inode, struct file *file){    int minor = iminor(inode);    file->private_data = (void *)minor;    printk(KERN_INFO "/dev/S3C_ADC%d opened.\n", minor);    return 0;}static int adc_release(struct inode *inode, struct file *file ){    return 0;}static struct file_operations adc_fops = {    .owner = THIS_MODULE,    .open = adc_open,    .read = adc_read,    .release = adc_release,};static int __init s3c_adc_init(void){    int result;    dev_t devno;    if(0!=dev_major)    {        devno = MKDEV(dev_major, 0);        result = register_chrdev_region(devno, dev_cnt, DEV_NAME);    }    else     {        result = alloc_chrdev_region(&devno, dev_minor, dev_cnt, DEV_NAME);        dev_major = MAJOR(devno);    }    if(result<0)    {        printk(KERN_ERR "%s driver can't use major %d\n", DEV_NAME, dev_major);         return -ENODEV;    }    printk(KERN_DEBUG "%s driver use major %d\n", DEV_NAME, dev_major);    adc_clk = clk_get(NULL,"s3c_adc");    if(!adc_clk)    {        printk(KERN_ERR "failed to find adc clock source\n");        return -ENOENT;    }    clk_enable(adc_clk);      if(NULL == (adc_cdev=cdev_alloc()) )     {         printk(KERN_ERR "S3C %s driver can't alloc for the cdev.\n", DEV_NAME);         unregister_chrdev_region(devno, dev_cnt);         return -ENOMEM;     }     adc_cdev->owner = THIS_MODULE;     cdev_init(adc_cdev, &adc_fops);     result = cdev_add(adc_cdev, devno, dev_cnt);     if(0!=result)     {         printk(KERN_INFO "S3C %s driver can't reigster cdev: result=%d\n", DEV_NAME, result);          goto ERROR;     }      printk(KERN_INFO "%s driver[major=%d] version %d.%d.%d installed successfully!\n",DEV_NAME, dev_major, DRV_MAJOR_VER, DRV_MINOR_VER,DRV_REVER_VER);      return 0;ERROR:      printk(KERN_ERR "S3C %s driver installed failure.\n", DEV_NAME);       cdev_del(adc_cdev);       unregister_chrdev_region(devno, dev_cnt);       return result;}static void __exit s3c_adc_exit(void){    dev_t devno = MKDEV(dev_major, dev_minor);    cdev_del(adc_cdev);    unregister_chrdev_region(devno, dev_cnt);    iounmap(adc_con);     iounmap(adc_data);    if(adc_clk)    {        clk_disable(adc_clk);        clk_put(adc_clk); /* ERROR */        printk("exit4\n");        adc_clk = NULL;        printk("exit5\n");    }    printk(KERN_ERR "S3C %s driver version %d.%d.%d removed!\n",DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER,DRV_REVER_VER);    return ;}/* This two function defined in <linux/init.h> */module_init(s3c_adc_init);module_exit(s3c_adc_exit);module_param(debug, int, S_IRUGO);module_param(dev_major, int, S_IRUGO);MODULE_AUTHOR(DRV_AUTHOR);MODULE_DESCRIPTION(DRV_DESC);MODULE_LICENSE("GPL");
  • Makefile
[lwn@localhost adc]$ vim Makefile LINUX_SRC?=~/fl2440/kernel/linux-lwn-3.0.1CROSS_COMPILE=/opt/dl/buildroot-2012.08/ARM920t/usr/bin/arm-linux-obj-m := adc.omodules:    @make -C $(LINUX_SRC) M=`pwd` modules    @make cleanclean:    rm -f  *.ko.* *.o *mod.c *.order *.symvers
  • 测试程序
/********************************************************************************* *      Copyright:  (C) 2017 Li Wanneng<liwjng@gmail.com> *                  All rights reserved. * *       Filename:  adc_test.c *    Description:  This file test s3c_adc driver *                  *        Version:  1.0.0(04/21/2017) *         Author:  Li Wanneng <liwjng@gmail.com> *      ChangeLog:  1, Release initial version on "04/21/2017 07:36:33 PM" *                  ********************************************************************************/#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>/******************************************************************************** *  Description: *   Input Args: *  Output Args: * Return Value: ********************************************************************************/int main (int argc, char **argv){    int fd;    fd = open("/dev/S3C_ADC",O_RDONLY);    if(fd<0)    {         printf("open S3C_ADC device failed.\n");         exit(1);    }    printf("fd>0\n");    while(1)    {         int ret;         int data;         printf("while read in user\n");         ret = read(fd, &data, sizeof(data));         printf("readed in user\n");         if(sizeof(data) != ret)         {              if(errno != EAGAIN)              {                   printf("Read ADC Device Faild!\n");              }              continue;         }         else         {             printf("Read ADC value is: %d\n", data);         }         sleep(1);    }    close(fd);    return 0;} /* ----- End of main() ----- */

编译测试

编写好以上程序之后,接下来下载到开发板测试运行。
1.在虚拟机中用make命令和gcc交叉编译器编译驱动程序s3c_adc.c和测试程序test_adc.c:
这里写图片描述

2.接下来将编译生成的驱动文件和测试文件下载到开发板测试ADC(因为我开发板的AD模块坏了,所以在同学的板子上运行,就是界面丑了点蛤)
这里写图片描述

0 0