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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#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值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#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 @   轻轻的吻  阅读(588)  评论(1编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
历史上的今天:
2017-12-25 python中常用模块
2017-12-25 Python os.removedirs() 和shutil.rmtree() 用于删除文件夹
2017-12-25 Python os.remove() 删除文件
2017-12-25 Python os.chdir() 方法
2017-12-25 Python os.access() 方法
2017-12-25 Python replace()方法
2017-12-25 python中的os.listdir()函数
点击右上角即可分享
微信分享提示