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

摘要:
1、 分析原理图和特性图1(图2S5p6818)中的ADC0用于读取电源电压,并通过ADC0将模拟量转换为数字量。

一、分析原理图及特性

十三、【ADC】ADC读取S5p6818电源值第1张十三、【ADC】ADC读取S5p6818电源值第2张

 

                                                       图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

                                      十三、【ADC】ADC读取S5p6818电源值第3张

 

三、相关寄存器分析

十三、【ADC】ADC读取S5p6818电源值第4张

 十三、【ADC】ADC读取S5p6818电源值第5张

十三、【ADC】ADC读取S5p6818电源值第6张

十三、【ADC】ADC读取S5p6818电源值第7张

 四、代码 编写

 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;
}

  

免责声明:文章转载自《十三、【ADC】ADC读取S5p6818电源值》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SQL批处理pgAdmin4下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

关于在Linux下的换行符 和windows下的换行符

linux系统下的换行符是 ,windows系统下的换行符是 。 分别在linux下和windows下创建文件linux.config和windows.config,写入几行内容。 通过打印文件的每一个字符的ASCII可以看出来, 的ascii为10, 的ascii为13。 在linux系统下修改windows.config输入换行,再打印可以发现输入的换...

linux包之iproute之ip命令

[root@localhost ~]# rpm -qf /sbin/ipiproute-2.6.32-31.el6.x86_64ip 是个命令, ip 命令的功能很多!基本上它整合了 ifconfig 与 route 这两个命令ip - show / manipulate routing, devices, policy routing and tunne...

在Linux系统下的虚拟机VMware-Workstation中安装Windows Server 2012

在Linux系统下的虚拟机VMware-Workstation中安装Windows Server 2012 说明: Linux系统:CentOS 5.8 64位 IP地址:192.168.0.98 VMware-Workstation版本:9.0(目前最新版) 具体操作: 一、在Linux系统中安装VMware-Workstation虚拟机软件...

使用Prometheus监控Linux系统各项指标

首先在Linux系统上安装一个探测器node explorer, 下载地址https://prometheus.io/docs/guides/node-exporter/ 这个探测器会定期将linux系统的各项硬件指标和内核参数通过9100端口和url metrics暴露给外部。 启动node explorer,显示在9100端口上监听: 浏览器里输入...

浅谈 Linux 下常用 Socket 选项设置

1.Socket和TCP/IP的关系 "All problems in computer science can be solved by another level of indirection." 为满足应用层需求,系统对TCP/IP层进行细节屏蔽和抽象,Socket层就相当于TCP/IP和应用层之间的中间层。 常用的socket/bind/accep...

Linux 串口驱动设计一

TTY驱动程序架构设计 一 。TTY概念解析   1. dev/ttySAC0     在Linux系统中,终端是一类字符型设备,它包括多种类型,通常使用tty来简称各种类型的终端设备。       •串口终端(/dev/ttyS*)      串口终端是使用计算机串口连接的终端设备。Linux把每个串行端口都看作是一个字符设备。        这些串行端...