一,ADC原理
ADC,模數轉換器,将模拟量轉換成數字量,采樣,保持電路與AD轉換器內建在一起。AD轉換器模拟輸入信号是直流電壓信号,0~3.3V之間。S3C2440有8路模拟輸入信号,AD轉換器内部有一個模拟多路選擇器,某一時刻隻能将一路模拟輸入信号,通過模拟多路選擇器接通進行AD轉換,而其他路模拟輸入信号被斷開。
片内ADC電路
ADC轉換電路
子產品圖
XP,XM,YP,YM占用了四個AD通道,用于觸摸屏操作
功能描述
1.AD轉換時間(轉換速率)
2.正常轉換模式
二,寄存器操作
ADC控制寄存器
ADC資料轉換寄存器0([9~0]保留AD轉換之後的資料)
三,ADC驅動源代碼
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/clk.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/kernel.h>//printk()
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>//包含很多驅動使用的核心API的定義。睡眠函數,變量聲明
#include <asm/io.h>//定義IO映射
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h>
#include <plat/regs-adc.h>//ADC寄存器的定義
#include <mach/regs-gpio.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#define DEVICE_NAME "my2440_adc"
static DECLARE_WAIT_QUEUE_HEAD(adc_waitq);
static volatile int ev_adc = 0;
static int adc_data;
static void __iomem *adc_base;
static struct clk *adc_clk;
//DECLARE_MUTEX(ADC_LOCK);
extern struct semaphore ADC_LOCK;
static irqreturn_t adc_irq(int irq, void *dev_id)
{
if(!ev_adc)
{
adc_data = readl(adc_base + S3C2410_ADCDAT0) & 0x3ff;
ev_adc = 1;
wake_up_interruptible(&adc_waitq);
}
return IRQ_HANDLED;
}
static void start_adc(void)
{
unsigned int tmp;
tmp = (1 << 14) | (255 << 6) | (0 << 3);
writel(tmp, adc_base + S3C2410_ADCCON);
tmp = readl(adc_base + S3C2410_ADCCON);
tmp = tmp | (1 << 0);
writel(tmp, adc_base + S3C2410_ADCCON);
}
static ssize_t adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
if (down_trylock(&ADC_LOCK))
{
return -EBUSY;
}
if(!ev_adc)
{
if(filp->f_flags & O_NONBLOCK)
{
return -EAGAIN;
}
else
{
start_adc();
wait_event_interruptible(adc_waitq, ev_adc);
}
}
ev_adc = 0;
copy_to_user(buffer, (char *)&adc_data, sizeof(adc_data));
up(&ADC_LOCK);
return sizeof(adc_data);
}
static int adc_open(struct inode *inode, struct file *file)
{
int ret;
ret = request_irq(IRQ_ADC, adc_irq, IRQF_SHARED, DEVICE_NAME, 1);
if (ret)
{
printk(KERN_ERR "IRQ%d error %d\n", IRQ_ADC, ret);
return -EINVAL;
}
return 0;
}
static int adc_release(struct inode *inode, struct file *filp)
{
return 0;
}
static struct file_operations adc_fops =
{
.owner = THIS_MODULE,
.open = adc_open,
.read = adc_read,
.release = adc_release,
};
static struct miscdevice adc_miscdev =
{
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &adc_fops,
};
static int __init adc_init(void)
{
int ret;
adc_clk = clk_get(NULL, "adc");
if (!adc_clk)
{
printk(KERN_ERR "failed to find adc clock source\n");
return -ENOENT;
}
clk_enable(adc_clk);
adc_base = ioremap(S3C2410_PA_ADC, 0x20);
if (adc_base == NULL)
{
printk(KERN_ERR "Failed to remap register block\n");
ret = -EINVAL;
goto err_noclk;
}
ret = misc_register(&adc_miscdev);
if (ret)
{
printk(KERN_ERR "cannot register miscdev on minor=%d (%d)\n", MISC_DYNAMIC_MINOR, ret);
goto err_nomap;
}
printk(DEVICE_NAME " initialized!\n");
return 0;
//以下是上面錯誤處理的跳轉點
err_noclk:
clk_disable(adc_clk);
clk_put(adc_clk);
err_nomap:
iounmap(adc_base);
return ret;
}
static void __exit adc_exit(void)
{
free_irq(IRQ_ADC, 1);
iounmap(adc_base);
if (adc_clk)
{
clk_disable(adc_clk);
clk_put(adc_clk);
adc_clk = NULL;
}
misc_deregister(&adc_miscdev);
}
//EXPORT_SYMBOL(ADC_LOCK);
module_init(adc_init);
module_exit(adc_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("apple");
MODULE_DESCRIPTION("My2440 ADC Driver");
測試程式:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(int argc, char **argv)
{
int fd;
//以阻塞方式打開裝置檔案,非阻塞時flags=O_NONBLOCK
fd = open("/dev/my2440_adc", 0);
if(fd < 0)
{
printf("Open ADC Device Faild!\n");
exit(1);
}
while(1)
{
int ret;
int data;
ret = read(fd, &data, sizeof(data)); //讀裝置
if(ret != sizeof(data))
{
if(errno != EAGAIN)
{
printf("Read ADC Device Faild!\n");
}
continue;
}
else
{
printf("Read ADC value is: %d\n", data);
}
}
close(fd);
return 0;
}