查看: 1662|回复: 0

SIN210学习笔记__ADC模块

[复制链接]
  • TA的每日心情
    慵懒
    2016-10-17 12:07
  • 签到天数: 306 天

    连续签到: 1 天

    [LV.8]以坛为家I

    发表于 2015-3-10 15:05:30 | 显示全部楼层 |阅读模式
    分享到:
    ADC,Analog to Digital Converter
    ADC就是模拟信号转换成数字信号的转换器,这个东东和DAC是模拟世界和数字世界的桥梁,如今DAC在单片机上已经是标配了,一般都是10/12可配置的,若不是特殊需求,12bit的分辨率在日常使用中也是够用的。当然也有一些单片机竟然配备了24bit的ADC,一般用于医疗电子。
    S5PV210 内部集成了10 通道 10/12-bit(可选) 多路复用 ADC
    微分线性误差: ± 1.0 LSB (Max.)
    积分线性误差: ± 4.0 LSB (Max.)
    最大转换速率: 1 MSPS
    低功耗

    工作电压: 3.3V
    模拟信号输入范围: 0 ~ 3.3V
    片上集成采样和保持功能

    普通转换模式
    分离 X/Y 转换模式
    自动(连续) X/Y 转换模式
    等待中断模式

    IDLE, DIDLE, STOP 和 DSTOP 唤醒
    两个触摸屏接口

      图10-1:AD和触摸屏框架图

    AD 驱动,三星公司已经写好,路径是:kernel/arch/arm/mach-s5pv210/adc.c 代码如下:

    #include   #include   #include   #include   #include   #include   #include   #include   #include   #include   #include   #include   #include   #include     #include     #include   #include   #include   #include     #define ADC_MINOR   131  #define ADC_INPUT_PIN   _IOW('S', 0x0c, unsigned long)    #define ADC_WITH_TOUCHSCREEN    static struct clk   *adc_clock;    static void __iomem     *base_addr;  static int adc_port;  struct s3c_adc_mach_info *plat_data;      #ifdef ADC_WITH_TOUCHSCREEN  static DEFINE_MUTEX(adc_mutex);    static unsigned long data_for_ADCCON;  static unsigned long data_for_ADCTSC;    static void s3c_adc_save_SFR_on_ADC(void)  {      data_for_ADCCON = readl(base_addr + S3C_ADCCON);      data_for_ADCTSC = readl(base_addr + S3C_ADCTSC);  }    static void s3c_adc_restore_SFR_on_ADC(void)  {      writel(data_for_ADCCON, base_addr + S3C_ADCCON);      writel(data_for_ADCTSC, base_addr + S3C_ADCTSC);  }  #else  static struct resource  *adc_mem;  #endif    static int s3c_adc_open(struct inode *inode, struct file *file)  {      return 0;  }    unsigned int s3c_adc_convert(void)  {      unsigned int adc_return = 0;      unsigned long data0;      unsigned long data1;        writel((adc_port & 0x7), base_addr + S3C_ADCMUX);        udelay(10);        writel(readl(base_addr + S3C_ADCCON) | S3C_ADCCON_ENABLE_START, base_addr + S3C_ADCCON);        do {          data0 = readl(base_addr + S3C_ADCCON);      } while (!(data0 & S3C_ADCCON_ECFLG));        data1 = readl(base_addr + S3C_ADCDAT0);        if (plat_data->resolution == 12)          adc_return = data1 & S3C_ADCDAT0_XPDATA_MASK_12BIT;      else          adc_return = data1 & S3C_ADCDAT0_XPDATA_MASK;        return adc_return;  }      int s3c_adc_get(struct s3c_adc_request *req)  {      unsigned adc_channel = req->channel;      int adc_value_ret = 0;        adc_value_ret = s3c_adc_convert();        req->callback(adc_channel, req->param, adc_value_ret);        return 0;  }  EXPORT_SYMBOL(s3c_adc_get);    static ssize_t  s3c_adc_read(struct file *file, char __user *buffer,          size_t size, loff_t *pos)  {  //  printk("++++++adc read.\n");      int  adc_value = 0;    #ifdef ADC_WITH_TOUCHSCREEN      mutex_lock(&adc_mutex);      s3c_adc_save_SFR_on_ADC();  #endif      printk(KERN_INFO "## delay: %d\n", readl(base_addr + S3C_ADCDLY));      adc_value = s3c_adc_convert();    #ifdef ADC_WITH_TOUCHSCREEN      s3c_adc_restore_SFR_on_ADC();      mutex_unlock(&adc_mutex);  #endif        //  printk("+++++%d\n",adc_value);      if (copy_to_user(buffer, &adc_value, sizeof(unsigned int)))          return -EFAULT;        return sizeof(unsigned int);  }      static int s3c_adc_ioctl(struct inode *inode, struct file *file,      unsigned int cmd, unsigned long arg)  {      cmd = ADC_INPUT_PIN;      switch (cmd) {      case ADC_INPUT_PIN:          adc_port = (unsigned int) arg;          printk("port=%d\n",arg);          if (adc_port >= 4)              printk(KERN_WARNING                  " %d is already reserved for TouchScreen\n",                  adc_port);          return 0;        default:          return -ENOIOCTLCMD;      }  }    static const struct file_operations s3c_adc_fops = {      .owner      = THIS_MODULE,      .read       = s3c_adc_read,      .open       = s3c_adc_open,      .ioctl      = s3c_adc_ioctl,  };    static struct miscdevice s3c_adc_miscdev = {      .minor      = ADC_MINOR,      .name       = "adc",      .fops       = &s3c_adc_fops,  };    static struct s3c_adc_mach_info *s3c_adc_get_platdata(struct device *dev)  {      if (dev->platform_data != NULL)          return (struct s3c_adc_mach_info *) dev->platform_data;      else          return 0;  }    /*  * The functions for inserting/removing us as a module.  */    static int __init s3c_adc_probe(struct platform_device *pdev)  {      printk("+++++++++++++s3c-adc probe.\n");      struct resource *res;      struct device *dev;      int ret;      int size;        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);      dev = &pdev->dev;        if (res == NULL) {          dev_err(dev, "no memory resource specified\n");          return -ENOENT;      }        size = (res->end - res->start) + 1;    #if !defined(ADC_WITH_TOUCHSCREEN)      adc_mem = request_mem_region(res->start, size, pdev->name);      if (adc_mem == NULL) {          dev_err(dev, "failed to get memory region\n");          ret = -ENOENT;          goto err_req;      }  #endif        base_addr = ioremap(res->start, size);      if (base_addr ==  NULL) {          dev_err(dev, "fail to ioremap() region\n");          ret = -ENOENT;          goto err_map;      }        adc_clock = clk_get(&pdev->dev, "adc");        if (IS_ERR(adc_clock)) {          dev_err(dev, "failed to fine ADC clock source\n");          ret = PTR_ERR(adc_clock);          goto err_clk;      }        clk_enable(adc_clock);        /* read platform data from device struct */      plat_data = s3c_adc_get_platdata(&pdev->dev);        if ((plat_data->presc & 0xff) > 0)          writel(S3C_ADCCON_PRSCEN | S3C_ADCCON_PRSCVL(plat_data->presc & 0xff), base_addr + S3C_ADCCON);      else          writel(0, base_addr + S3C_ADCCON);        /* Initialise registers */      if ((plat_data->delay & 0xffff) > 0)          writel(plat_data->delay & 0xffff, base_addr + S3C_ADCDLY);        if (plat_data->resolution == 12)          writel(readl(base_addr + S3C_ADCCON) | S3C_ADCCON_RESSEL_12BIT, base_addr + S3C_ADCCON);        ret = misc_register(&s3c_adc_miscdev);      if (ret) {          printk(KERN_ERR "cannot register miscdev on minor=%d (%d)\n",              ADC_MINOR, ret);          goto err_clk;      }            printk("+++++++++++++s3c-adc probe successful\n");      return 0;    err_clk:      clk_disable(adc_clock);      clk_put(adc_clock);    err_map:      iounmap(base_addr);    #if !defined(ADC_WITH_TOUCHSCREEN)  err_req:      release_resource(adc_mem);      kfree(adc_mem);  #endif        return ret;  }      static int s3c_adc_remove(struct platform_device *dev)  {      return 0;  }    #ifdef CONFIG_PM  static unsigned int adccon, adctsc, adcdly;    static int s3c_adc_suspend(struct platform_device *dev, pm_message_t state)  {      adccon = readl(base_addr + S3C_ADCCON);      adctsc = readl(base_addr + S3C_ADCTSC);      adcdly = readl(base_addr + S3C_ADCDLY);        clk_disable(adc_clock);        return 0;  }    static int s3c_adc_resume(struct platform_device *pdev)  {      clk_enable(adc_clock);        writel(adccon, base_addr + S3C_ADCCON);      writel(adctsc, base_addr + S3C_ADCTSC);      writel(adcdly, base_addr + S3C_ADCDLY);        return 0;  }  #else  #define s3c_adc_suspend NULL  #define s3c_adc_resume  NULL  #endif    static struct platform_driver s3c_adc_driver = {         .probe          = s3c_adc_probe,         .remove         = s3c_adc_remove,         .suspend        = s3c_adc_suspend,         .resume         = s3c_adc_resume,         .driver      = {          .owner  = THIS_MODULE,          .name   = "s3c-adc",      },  };    static char banner[] __initdata = KERN_INFO "S5PV210 ADC driver, (c) 2010 Samsung Electronics\n";    int __init s3c_adc_init(void)  {      printk(banner);      return platform_driver_register(&s3c_adc_driver);  }    void __exit s3c_adc_exit(void)  {      platform_driver_unregister(&s3c_adc_driver);  }    module_init(s3c_adc_init);  module_exit(s3c_adc_exit);    MODULE_AUTHOR("dsfine.ha@samsung.com");  MODULE_DESCRIPTION("S5PV210 ADC driver");  MODULE_LICENSE("GPL");  驱动已经解决,我们就可以直接写ADC的应用了。这次也是让ADC自动采集AD0端口的值,然后输出到Qt中显示
    /*adc.h*/  #ifndef AD_H  #define AD_H  #ifdef __cplusplus  extern "C" {  #endif    extern int adc_open(const char *devname);  extern int adc_ioctl(int ad_ch);  extern int adc_read();  extern int adc_close(void);  extern int adc_fd;    #ifdef __cplusplus  }  #endif  #endif      /*adc.c*/  #include   #include   #include   #include   #include   #include "adc.h"    int adc_fd=0;      int adc_open(const char*devname)  {    adc_fd=open(devname,O_RDWR);    if(adc_fd<0)    {       printf("open device %s failed.\n",devname);       return -1;    }    printf("AD driver is ok\n");    return 0;  }    int adc_ioctl(int adc_ch)  {    if(adc_ch > 4)    {      printf("AD Channel %d is reserved for TouchScreen!\n",adc_ch);      return -1;    }    ioctl(adc_fd,'s',adc_ch);    printf("AD Channel %d is open\n",adc_ch);    return 0;  }  int adc_read()  {     usleep(500*1000);     int i,sum=0,j=10;     while(j--)     {       read(adc_fd, &i, sizeof(int));       sum+=i;     }       printf("AD value :%d\n",i);     return i;  }      int adc_close(void){   if(adc_fd)     close(adc_fd);  }  编写Qt应用程序即可通过adc_read()函数读取adc的值,通过adc_ioctl(int acd_ch) 来选择adc的通道(0~4可选,其它SIN210开发板用于触摸屏了,保留)。
    adc_open(const char*devname)打开adc驱动文件。
    下面是运行的效果图:

                                                       图10-2:AD运行效果图
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-12-19 07:00 , Processed in 0.111979 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.