十三、【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; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于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()函数