十三、【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;
}

  

posted @ 2021-12-25 16:49  轻轻的吻  阅读(559)  评论(1编辑  收藏  举报