• 十三、【ADC】ADC读取S5p6818电源值


    一、分析原理图及特性

     

                                                           图1                                                                            图2

    S5p6818的ADC0是去读取电源电压,通过ADC0将模拟量转化为数字量。

    图2为ADC内部构造图

    ADC特性

    • 分辨率:12bit
    • 最大转换率:1Msps(main clock:6MHZ,sampling clock:1MHZ).
    • 供电0~1.8V
    • 输入频率:DC to 100KHZ

    二、ADC转换流程

    • PCLK Supply: CLKENB.PCLKMODE=1
    • Analog Input Select: ADCCON.ASELADC
    • Power On: ADCCON.STBY=0
    • CLKIN Divide Value: ADCCON.APSV
    • CLKIN On:ADCCON.APE
    • ADC Enable: ADCCON.ADEN
    • AD Conversion Process
    • Read ADCDAT.ADCDAT
    • CLKIN Off
    • ADC Power Off

                                          

     

    三、相关寄存器分析

     

     四、代码 编写

     1、通过读ADC转换器是否转换完成的方式去读ADC值

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/cdev.h>
    #include <linux/fs.h>
    #include <linux/device.h>
    #include <linux/ioport.h>
    #include <linux/io.h>
    #include <linux/uaccess.h>
    #include <linux/types.h>
    #include <linux/gpio.h>
    #include <cfg_type.h>
    #include <linux/miscdevice.h>
    #include <linux/delay.h>
    
    #include <mach/platform.h>
    #include <mach/devices.h>
    #include <mach/soc.h>
    
    #define ADCREG(x) ((x) + IO_ADDRESS(PHY_BASEADDR_ADC))   //物理地址映射到虚拟地址
    #define ADCCON  ADCREG(0)
    #define ADCDAT   ADCREG(0x0004)
    #define ADCINTENB ADCREG(0x0008)
    #define ADCINTCLR ADCREG(0x000C)
    #define PRESCALERCON ADCREG(0x0010)
    
    static ssize_t adc_read(struct file *filp, char __user * buf, size_t size, loff_t *oft)
    {
    
    	  unsigned int adcValue;
      	  unsigned int count=0;
    	  int ret;
    	  if(size!=4)
    	  {
    	  	return -EINVAL;
    	  }
    	  writel((readl(ADCCON)&(~(1<<2))),ADCCON);  //poweron 
    	  writel(readl(ADCCON)|(1<<0),ADCCON);  //start AD conversion 
    	  while(readl(ADCCON)&(1<<0))   //等待
    	  {
    	      count++;
    		 udelay(1); 
    	  	if(count>200)
    	  	{
    	  		 printk(KERN_ERR"adc read error\n");
    			 writel((readl(ADCCON)|(1<<2)),ADCCON);  //poweroff
    			 return  -EAGAIN;
    	  	}
    	  }
    	  adcValue = readl(ADCDAT)&0xfff;
    	  writel((readl(ADCCON)|(1<<2)),ADCCON);  //poweroff
             ret = copy_to_user(buf, &adcValue, sizeof(adcValue));
    	  if(ret != 0)
    	  {
    	  	return (size -ret);
    	  }
    	  return size;
    }
    
    struct file_operations adc_misc_fops=
    {
    	.read= adc_read,
    };
    
    static struct miscdevice adc_misc={
    	.minor = MISC_DYNAMIC_MINOR,
    	.name = "adc_misc",
    	.fops =  &adc_misc_fops,
    	};
    static int __init  adc_init(void)
    {
          int ret;
           printk(KERN_INFO"adc_init\n");
          ret = misc_register(&adc_misc);
          if(ret < 0)
          {
          		printk(KERN_INFO"adc misc register fail.\n");
    		goto misc_register_err;	
          }
    //复位 ADC	  
        nxp_soc_peri_reset_set(RESET_ID_ADC); 
       writel((readl(ADCCON)&~(7<<3)),ADCCON);  //选择通道0
       writel( ( (readl(ADCCON) & (~(0xf<<6))) | (6<<6)  ), ADCCON);//SOC的时序参数6
       writel((readl(ADCCON)|(1<<2)),ADCCON);  //poweroff
       writel((readl(PRESCALERCON)&~(1<<15)),PRESCALERCON);  //prescaler disbale
       writel((readl(PRESCALERCON)&~(0x3ff))|(199<<0),PRESCALERCON);  //200M/(199+1) =1M
        writel((readl(PRESCALERCON)|(1<<15)),PRESCALERCON);  //prescaler enable
    
    
    	return 0;
    
    
    misc_register_err:
    		return ret;
    }
    
    static void __exit adc_exit(void)
    {
        printk(KERN_INFO"adc__exit\n");
         misc_deregister(&adc_misc);	  
    }
    
    module_init(adc_init);
    module_exit(adc_exit);
    MODULE_LICENSE("GPL");
    

    2、通过中断的方式读adc值

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/cdev.h>
    #include <linux/fs.h>
    #include <linux/device.h>
    #include <linux/ioport.h>
    #include <linux/io.h>
    #include <linux/uaccess.h>
    #include <linux/types.h>
    #include <linux/gpio.h>
    #include <cfg_type.h>
    #include <linux/miscdevice.h>
    #include <linux/delay.h>
    #include <mach/platform.h>
    #include <mach/devices.h>
    #include <mach/soc.h>
    
    #define ADCREG(x) ((x) + IO_ADDRESS(PHY_BASEADDR_ADC))   //物理地址映射到虚拟地址
    #define ADCCON  ADCREG(0)
    #define ADCDAT   ADCREG(0x0004)
    #define ADCINTENB ADCREG(0x0008)
    #define ADCINTCLR ADCREG(0x000C)
    #define PRESCALERCON ADCREG(0x0010)
    
    static DECLARE_WAIT_QUEUE_HEAD(adc_wq) ;   //静态定义等待队列
    static bool flag = false;
    
    static ssize_t adc_read(struct file *filp, char __user * buf, size_t size, loff_t *oft)
    {
    	  int ret;
    	  unsigned int adcValue=0;
    	  if(size!=4)
    	  {
    	  	return -EINVAL;
    	  }
    	  writel((readl(ADCCON)&(~(1<<2))),ADCCON);  //poweron 
    	  writel(readl(ADCCON)|(1<<0),ADCCON);  //start AD conversion 
    	wait_event_interruptible(adc_wq, flag);
           flag = false;  //唤醒一次队列后要复位flag的值
    	  adcValue = readl(ADCDAT)&0xfff;
    	  writel((readl(ADCCON)|(1<<2)),ADCCON);  //poweroff
    	ret = copy_to_user(buf, &adcValue, sizeof(adcValue));
    	  if(ret != 0)
    	  {
    	  	return (size -ret);
    	  }
    	  return size;
    }
    
    struct file_operations adc_misc_fops=
    {
    	.read= adc_read,
    };
    
    static struct miscdevice adc_misc={
    	.minor = MISC_DYNAMIC_MINOR,
    	.name = "adc_misc",
    	.fops =  &adc_misc_fops,
    	};
    
    static irqreturn_t adc_irq_handler(int irq, void * dev)
    {
    	writel( ( readl(ADCINTCLR) |(1<<0) ), ADCINTCLR);  //clear interrupt
    	 flag = true;  //设置flag为true
            wake_up_interruptible(&adc_wq); 
             
    	return IRQ_HANDLED;
    }
    static int __init  adc_init(void)
    {
          int ret;
           printk(KERN_INFO"adc_init\n");
          ret = misc_register(&adc_misc);
          if(ret < 0)
          {
          		printk(KERN_INFO"adc misc register fail.\n");
    		goto misc_register_err;	
          }
    	
    //adc转换器转换完成后会触发中断	  
         ret = request_irq(IRQ_PHY_ADC,  adc_irq_handler, 0,   "adc_irq", NULL);
        if(ret < 0)
        {
        	 printk(KERN_INFO"request_irq fail.\n");
                goto irq_request_err;
        }
    //复位 ADC	  
        nxp_soc_peri_reset_set(RESET_ID_ADC); 
       writel((readl(ADCCON)&~(7<<3)),ADCCON);  //选择通道0
       writel( ( (readl(ADCCON) & (~(0xf<<6))) | (6<<6)  ), ADCCON);//SOC的时序参数6
       writel((readl(ADCCON)|(1<<2)),ADCCON);  //poweroff
       writel((readl(PRESCALERCON)&~(1<<15)),PRESCALERCON);  //prescaler disbale
       writel((readl(PRESCALERCON)&~(0x3ff))|(199<<0),PRESCALERCON);  //200M/(199+1) =1M
        writel((readl(PRESCALERCON)|(1<<15)),PRESCALERCON);  //prescaler enable
    
      writel((readl(ADCINTENB)|(1<<0)),ADCINTENB);  //enable 中断
      writel((readl(ADCINTCLR)|(1<<0)),ADCINTCLR);  //清空中断
    	return 0;
    
    irq_request_err:
    	free_irq(IRQ_PHY_ADC,NULL);
    misc_register_err:
    		return ret;
    }
    
    static void __exit adc_exit(void)
    {
        printk(KERN_INFO"adc__exit\n");
        free_irq(IRQ_PHY_ADC,NULL);	 	
         misc_deregister(&adc_misc);	  
    }
    
    module_init(adc_init);
    module_exit(adc_exit);
    MODULE_LICENSE("GPL"); 

    main.c

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/ioctl.h>
    int main()
    {
        int fd,ret;
    
        int  adcvalue;
        fd = open("/dev/adc_misc",O_RDWR);
        if(fd<0)
        {
            perror("open adc_misc error!");        
        }
        while(1)
        {
           ret = read(fd,&adcvalue,4);  
           if(ret != 4)
           	{
           		perror("read adc value error");
    		continue;	
           	}
            printf("adcvalue=0x%x\n",adcvalue);
    	usleep(200*1000);
        }
        
         close(fd);
         return 0;
    }
    

      

  • 相关阅读:
    1015
    1016
    1014
    1002
    1010
    1006
    动态规划1001
    动态规划1002
    使用EF框架调用带有输出参数(output)的存储过程
    工程地质相关知识
  • 原文地址:https://www.cnblogs.com/yuanqiangfei/p/15730928.html
Copyright © 2020-2023  润新知