模數轉換電路
時間:2018-03-30作者:華清遠見
一、Exynos4412 A/D轉換器概述
1. 概述 ADC(Analog-to-Digital Converter),就是模數轉換器。從字面上看,A我們稱為模擬信號(Analog signal),D我們稱為數字信號(digital signal)。 模數轉換器,在電子技術中即是將模擬信號轉換成數字信號,也稱為數字量化。當然還有一種叫DAC,就是數模轉換,意思相反,即是將數字信號轉換成模擬信號。 在我們的日常生活中,會遇到很多的物理量,遇到很多的物理參數,其中,我們經常遇到的物理參數,如電流、電壓、溫度、壓力、速度等電量或非電量都是模擬量。 模擬量的大小是連續分布的,且經常也是時間上的連續函數。要使計算機或數字儀表能識別、處理這些信號,必須首先將這些模擬信號轉換成數字信號;而經計算機分析、處理后輸出的數字量也往往需要將其轉換為相應模擬信號才能為執行機構所接受。這樣,就需要一種能在模擬信號與數字信號之間起橋梁作用的電路—模數和數模轉換器。 2. 分類 目前常見的A/D轉換器中,有:權電阻網絡D/A轉換器、倒T型電阻網絡D/A轉換器、權電流型D/A轉換器、權電容網絡D/A轉換器、開關樹形D/A轉換器。 3. A/D轉換主要技術指標 1)分辨率 A/D轉換器的分辨率用輸出二進制數的位數表示,位數越多,誤差越小,轉換精度越高。 2)量化誤差 在A/D轉換中由于整量化產生的固有誤差。量化誤差在±1/2LSB(最低有效位)之間。 3)轉換時間 轉換時間是指A/D轉換器完成一次轉換所需的時間。轉換時間是指從接到轉換控制信號開始,到輸出端得到穩定的數字輸出信號所經過的這段時間。 4)偏移誤差 輸入信號為零時輸出信號不為零的值,可外接電位器調至最小。 5)滿刻度誤差 滿刻度輸出時對應的輸入信號與理想輸入信號值之差。 6)線性度 實際轉換器的轉移函數與理想直線的最大偏移,不包括以上3種誤差。 其他指標還有:絕對精度(Absolute Accuracy)、相對精度(Relative Accuracy)、微分非線性、單調性和無錯碼、總諧波失真(Total Harmonic Distortion,THD)和積分非線性。 二、Exynos 4412 A/D轉換器簡介 1.簡述 10位或12位CMOS再循環式模擬數字轉換器,它具有10通道輸入,并可將模擬量轉換至10位或12位二進制數。5Mhz A/D 轉換時鐘時,最大1Msps的轉換速度。A/D轉換具備片上采樣保持功能,同時也支持待機工作模式。 2.特性 ADC接口包括如下特性。 1)10bit/12bit輸出位可選。 2)微分誤差 1.0LSB。 3)積分誤差 2.0LSB。 4)最大轉換速率5Msps. 5) 功耗少,電壓輸入1.8V。 6)電壓輸入范圍 0~1.8V。 7)支持偏上樣本保持功能。 8)通用轉換模式。 3. A/D功能模塊圖 ![]()
圖1 ADC Functional Block Diagram
2. Exynos4412 A/D 控制器寄存器
1)A/D控制寄存器ADCCON ![]()
2)A/D數據寄存器
![]()
3)A/D通道Mux寄存器
![]()
三、A/D轉換器實例
1. 電路連接如下: 利用一個電位計輸出電壓到4412的AIN3管腳。輸入的電壓范圍為0~1.8V。 ![]()
1. 代碼如下:
#include <asm/ioctl.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/uaccess.h> #include <asm/io.h> #define ADC_MAGIC 'A' #define CMD_ONE 1 #define ADC_CMD_GET _IOR(ADC_MAGIC, CMD_ONE, int) //寄存器定義 #define ADC_CFG (0x10010118) #define ADCCON (0x126C0000) #define ADCDAT (0x126C000C) #define ADCMUX (0x126C001C) dev_t dev; int minor_base = 0; int adc_count = 1; char adc_name[] = "adc"; struct cdev *pcdev = NULL; struct class *pcls = NULL; static unsigned int *adccfg; static unsigned int *adcmux; static unsigned int *adccon; static unsigned int *adcdat; int AdcInit(void) { int ret = 0; adccfg = ioremap(ADC_CFG, 4); if (adccfg == NULL) { printk("ioremap adccfg\n"); ret = -ENOMEM; return ret; } adcmux = ioremap(ADCMUX, 4); if (adcmux == NULL) { printk("ioremap adcmux\n"); ret = -ENOMEM; goto ERR1; } adccon = ioremap(ADCCON, 4); if (adccon == NULL) { printk("ioremap adccon\n"); ret = -ENOMEM; goto ERR2; } adcdat = ioremap(ADCDAT, 4); if (adcdat == NULL) { printk("ioremap adcdat\n"); ret = -ENOMEM; goto ERR3; } //ADC_CFG &= ~(0x1 << 16); writel(readl(adccfg) & ~(0x1<<16), adccfg); //Bit_16:Select ADC Mux 0:General ADC, 1:MTCADC //ADCMUX = 0x3; writel(3, adcmux); //0x3: 0011 = AIN3 //原理圖管腳查到XadcAIN3 //12bit A/D conversion; enable A/D converter prescaler; prescaler value:20; A/D conversion start by read //ADCCON = (0x1<<16) | (0x1<<14) | (19<<6) | 0x1<<1; //ADCDAT & 0xfff; writel((0x1<<16) | (0x1<<14) | (19<<6) | 0x1<<1, adccon); return 0; ERR3: iounmap(adccon); ERR2: iounmap(adcmux); ERR1: iounmap(adccfg); return ret; } unsigned int adc_get(void) { unsigned int adc_value; unsigned int temp_value; readl(adcdat); while(!(readl(adccon) & (0x1<<15))); adc_value = readl(adcdat) & 0xfff; temp_value = 9999 * adc_value / 4095; return temp_value; } long adc_ioctl (struct file *filp, unsigned int cmd, unsigned long arg) { //printk("%s:%s:%d\n", __FILE__, __func__, __LINE__); switch (cmd) { case ADC_CMD_GET: *(unsigned int *)arg = adc_get(); break; default: return -EINVAL; } return 0; } struct file_operations fops = { .owner = THIS_MODULE, .unlocked_ioctl = adc_ioctl, }; int adc_init(void) { int ret; int major; struct device *pdevice = NULL; //printk("%s:%s:%d\n", __FILE__, __func__, __LINE__); ret = alloc_chrdev_region(&dev, minor_base, adc_count, adc_name); if (0 > ret) { printk("Can't get device number\n"); return ret; } pcdev = cdev_alloc(); if (NULL == pcdev) { printk("cdev alloc failed.\n"); ret = -ENOMEM; goto UNREG_DEV_NUM; } cdev_init(pcdev, &fops); pcdev->owner = THIS_MODULE; ret = cdev_add(pcdev, dev, adc_count); if (0 > ret) { printk("add cdev failed.\n"); goto DEL_CDEV; } pcls = class_create(pcdev->owner, adc_name); if (IS_ERR(pcls)) { printk("class create failed.\n"); ret = PTR_ERR(pcls); goto DEL_CDEV; } major = MAJOR(dev); pdevice = device_create(pcls, NULL, MKDEV(major, minor_base), NULL, "%s%d", adc_name, minor_base); if (IS_ERR(pdevice)) { printk("device %s%d create failed.\n", adc_name, minor_base); ret = PTR_ERR(pdevice); goto DESTROY_CLASS; } //printk("Body temperature module init done!\n"); if (0 != AdcInit()) { goto DESTROY_CLASS; } printk("adc init\n"); return 0; DESTROY_CLASS: class_destroy(pcls); DEL_CDEV: cdev_del(pcdev); UNREG_DEV_NUM: unregister_chrdev_region(dev, adc_count); return ret; } void adc_exit(void) { device_destroy (pcls, MKDEV(MAJOR(dev), minor_base)); class_destroy(pcls); cdev_del(pcdev); unregister_chrdev_region(dev, adc_count); printk("Good bye, adc module\n"); //printk("%s:%s:%d\n", __FILE__, __func__, __LINE__); } module_init(adc_init); module_exit(adc_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ruth Wei"); MODULE_DESCRIPTION("adc for demo"); MODULE_VERSION("1.0.1"); 2. 編譯測試 經過交叉編譯后,加載驅動,寫一個應用程序可以讀取ADC轉換后的值。 四、總結 本文從模數轉換器的技術指標和電路連接等方面進行分析,最終寫出驅動程序,可以在4412板子上進行測試。 相關資訊
發表評論
|