一,ADC原理
ADC,模数转换器,将模拟量转换成数字量,采样,保持电路与AD转换器集成在一起。AD转换器模拟输入信号是直流电压信号,0~3.3V之间。S3C2440有8路模拟输入信号,AD转换器内部有一个模拟多路选择器,某一时刻只能将一路模拟输入信号,通过模拟多路选择器接通进行AD转换,而其他路模拟输入信号被断开。
片内ADC电路
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyczM581NxETOyczN1MTMvwVOw8CXxAzMxAjMvw1ckF2bsBXdvwFdl5mLuR2cj5Set1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
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;
}