您的位置:首页 > 运维架构 > Linux

ARM-Linux--ADC 驱动(查询方式)

2015-06-15 09:05 471 查看
主机系统:Ubuntu 11.04

内核版本:Linux Kernel 2.6.39

硬件平台:FL2440

开发板系统:Linux Kernel 2.6.28

下面是用CPU轮寻的方式来判断AD转换完成的

#include <linux/kernel.h>
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/device.h> /*创建设备节点*/
#include <linux/clk.h>
#include <linux/delay.h>/*延时函数*/

#include <asm/io.h>
#include <asm/uaccess.h>

#include <plat/regs-adc.h>
#include <mach/regs-clock.h>

#define ADC_MAJOR 102
#define ADC_NAME "my_adc"
#define SUCCESS 0

static int adc_open(struct inode *,struct file *);
static int adc_release(struct inode *,struct file *);
static int __init adc_init(void);
static int __exit adc_exit(void);
static ssize_t adc_read(struct file *,char *,size_t,loff_t *);

volatile unsigned long adc_con;
unsigned long adc_dat0;
//#define adc_con		(unsigned long)ioremap(0x58000000,4)
//#define adc_dat0		(volatile unsigned long)ioremap(0x5800000c,4)
struct clk *adc_clk;

struct file_operations  adc_ops =
{
.owner	=	THIS_MODULE,
.read	    =   adc_read,
.open	=   adc_open,
.release	=	adc_release,
};

static int __init adc_init(void)
{
int ret;
adc_clk = clk_get(NULL,"adc");//获取时钟
clk_enable(adc_clk);//使能时钟
ret=register_chrdev(ADC_MAJOR,ADC_NAME,&adc_ops); //注册设备
if(ret<0)
{
printk("register device fail/n");
return ret;
}
adc_con=(unsigned long)ioremap(0x58000000,4);
adc_dat0=(volatile unsigned long)ioremap(0x58000000+S3C2410_ADCDAT0,4);
if(adc_con&adc_dat0==0)
{
printk("Failed to ioremap/n");
goto handle;
}
printk("Initialized.../n");
return SUCCESS;
handle:
unregister_chrdev(ADC_MAJOR,ADC_NAME);
return -1;
}

static int adc_open(struct inode * inode,struct file * file) //打开设备函数
{

return SUCCESS;
}

static int adc_release(struct inode * inode,struct file * file) //关闭设备函数
{
return SUCCESS;
}

static ssize_t adc_read(struct file *file,
char * buffer,
size_t length,
loff_t * offset)//设备读取函数
{
unsigned int buf;
int tmp;
int i;
writew((1<<14)|(0x31<<6),adc_con);       //设置ADCCON
writew((readw(adc_con) | 0x1),adc_con);  //启动AD转换
while(readw(adc_con) & 0x1) ;              //启动转换后,等待启动位清零
while(!(readw(adc_con) & 0x8000)) ;            //等待转换是否完毕
//for(i=0;i<200000;i++) ;
mdelay(100);
buf=(readw(adc_dat0) & 0x3ff );                 //取出转换后得到的有效数据

copy_to_user(buffer, (char *)&buf, sizeof(buf));
//printk("The value is %x/n",buf);
return 2;

}

static int __exit adc_exit(void) //驱动卸载函数
{
iounmap(adc_con);
iounmap(adc_dat0);
unregister_chrdev(ADC_MAJOR,ADC_NAME);
clk_disable(adc_clk);
clk_put(adc_clk);
printk("The adc is unintialized/n");
return SUCCESS;
}

module_init(adc_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");


其中控制寄存器的第15未标明AD转换是否完成,当AD完成转换时,控制寄存器自动置一,但是由于数据存在延迟,当第15位置一的时候读出的数据并不稳定,需要在其后加个延迟的函数,在内核态使用的延迟函数包含头文件./linux/delay.h

mdelay(int x);延时x毫秒

udelay(int x);延时x微秒

ndelay(int x);延时x纳秒

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

#define ADC_DEVICE	"/dev/my_adc"

int main()
{
int ret;
unsigned int data;
ret=open(ADC_DEVICE,0);
if(ret<0)
{
printf("Open adc fail/n");
return ret;
}
for(;;)
{
//printf("cnt=%d/n",cnt);
read(ret,&data,sizeof(data));
printf("The value is 0x%x/n",data);
}
close(ret);
return 0;
}


测试结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: