Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1316858
  • 博文数量: 177
  • 博客积分: 3640
  • 博客等级: 中校
  • 技术积分: 1778
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-27 16:51
文章分类

全部博文(177)

文章存档

2014年(1)

2013年(10)

2012年(3)

2011年(163)

分类: LINUX

2011-10-01 10:40:05

/*
* s3c2410-adc.c
*
* S3C2410 ADC
* exclusive with s3c2410-ts.c
*/
#include
//linux 的配置文件 
#include
//模块化源文件必须带的头文件
#include
//包含printk函数
#include
//包含module_init(init_function)和module_exit(exit_function)
#include
//包含驱动程序需要的大量API函数,包括睡眠函数以及各种变量声明
#include
#include
#include
#include
//信号量
#include
#include

#define CONFIG_DEVFS_FS 1       //可选项,要是不选insmod之前必须先mknod /dev/s3c2410 c 220 1
#define USE_IRQ_WAITQUEUE 0     //可选项,AD转换要一段时间,启动之后可以让进程休眠,让CPU去做其他事情
                                                                                     //我的板子不知道为什么申请不到这个中断号所以现不用这,反正是测试,对速度没要求)
#define DEVICE_NAME "s3c2410-adc"
#define ADCRAW_MINOR 1          //此设备号
#define ADC_WRITE(ch, prescale)((ch)<<16|(prescale))    //驱动里没用到,应用程序中,把ch,prescale合成一个数据传送到驱动程序
#define ADC_WRITE_GETCH(data)(((data)>>16)&0x7)   //得到通道号
#define ADC_WRITE_GETPRE(data)((data)&0xff)      //得到转换的比例因子

static int adcMajor = 220;    //主设备号

typedef struct {
struct semaphore lock;      //互斥锁。 作用:一个应用程序A要用此驱动,先拿到锁,把驱动锁上,
                                                                           //   另一个应用程序想用此驱动,先看是否被锁,锁了就等待或返回信息。
#ifdef USE_IRQ_WAITQUEUE
wait_queue_head_t wait;      //等待队列的定义。驱动做某件事情需要些时间,但又不想while(finish)下去,
                                                                             //因为驱动的while不能被进程调度,可能导致系统当掉
#endif
int channel;                 //通道号
int prescale;                //比例因子
}ADC_DEV;                 

static ADC_DEV adcdev;

#define START_ADC_AIN(ch, prescale) \
do{ \
ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \
ADCCON |= ADC_START; \
}while(0)                        //此函数就是向ADCCON里先写初始化位,再让其开始转换

#ifdef USE_IRQ_WAITQUEUE
static void adcdone_int_handler(int irq, void *dev_id, struct pt_regs *reg)
{
wake_up(&adcdev.wait);                //AD转换完成产生的中断信号调用此函数,唤醒等待队列
}
#endif

static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
int data;                 //用来保存应用程序传来的数据
if(count!=sizeof(data)){
printk("the size of input data must be %d\n", sizeof(data));     //应用程序传来的数据和data长度不同,报错
return 0;
}
copy_from_user(&data, buffer, count);                 //从应用程序传来数据 放到data
adcdev.channel=ADC_WRITE_GETCH(data);          
adcdev.prescale=ADC_WRITE_GETPRE(data);
printk("set adc channel=%d, prescale=0x%x\n", adcdev.channel, adcdev.prescale);
return count;
}

static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
int ret = 0;
if (down_interruptible(&adcdev.lock))    //先获得互斥锁
return -ERESTARTSYS;
START_ADC_AIN(adcdev.channel, adcdev.prescale);   //开始转换
#ifdef USE_IRQ_WAITQUEUE
interruptible_sleep_on(&adcdev.wait);            //休眠进程,让CPU做其他的事情
#endif
printk("in read channel=%d\n",adcdev.channel);
printk("ADCDAT0=%x\n",ADCDAT0);
while(!(ADCCON & 0x8000))                        //查看AD是否转换完成
udelay(100);
ret = ADCDAT0;
ret &= 0x3ff;                                   //10位AD转换,所以取低十位
copy_to_user(buffer, (char *)&ret, sizeof(ret));   //把得到的值传回应用程序
up(&adcdev.lock);                                  //释放信号量
return sizeof(ret);
}

static int s3c2410_adc_open(struct inode *inode, struct file *filp)
{
init_MUTEX(&adcdev.lock);                        //初始化一个互斥锁
#ifdef USE_IRQ_WAITQUEUE
init_waitqueue_head(&(adcdev.wait));              //初始化一个休眠队列
#endif
adcdev.channel=4;
adcdev.prescale=0xff;

MOD_INC_USE_COUNT;                                //原子操作 ,计数现在有多少应用程序在使用此去驱动
printk("adc opened!\n");
return 0;
}

static int s3c2410_adc_release(struct inode *inode, struct file *filp)
{
MOD_DEC_USE_COUNT;                       //某个应用程序不用此驱动了,驱动程序相应记录一下
printk( "adc closed\n");
return 0;
}


static struct file_operations s3c2410_fops = {
owner:THIS_MODULE,
open:s3c2410_adc_open,
read:s3c2410_adc_read,
write:s3c2410_adc_write,
release:s3c2410_adc_release,
};

#ifdef CONFIG_DEVFS_FS
static devfs_handle_t devfs_adc_dir, devfs_adcraw;
#endif

int __init s3c2410_adc_init(void)
{
int ret;
printk("s3c2410_adc_init\n");
/* normal ADC */
#ifdef USE_IRQ_WAITQUEUE     
ADCTSC = 0;
printk("IRQ_ADC_DONE is %d\n",IRQ_ADC_DONE);    //输出要申请的中断号
ret = request_irq(IRQ_ADC_DONE, adcdone_int_handler, SA_INTERRUPT, DEVICE_NAME, NULL); //申请中断的函数
if (ret) {
return ret;          //看是否申请到中断,没申请到的话返回错误编号给内核
}
#endif
ret = register_chrdev(220, DEVICE_NAME, &s3c2410_fops);   //注册设备的函数
if (ret < 0) {
printk(DEVICE_NAME " can't get major number\n");            
return ret;
}
adcMajor=220;

#ifdef CONFIG_DEVFS_FS
//devfs_adc_dir = devfs_mk_dir(NULL, "adc", NULL);
devfs_adcraw = devfs_register(devfs_adc_dir, "0raw", DEVFS_FL_DEFAULT,
adcMajor, ADCRAW_MINOR, S_IFCHR | S_IRUSR | S_IWUSR, &s3c2410_fops, NULL);   //创建设备节点的函数
#endif
printk (DEVICE_NAME"\tinitialized\n");
printk ("initialized\n");

printk("inilized ADCDAT0=%x\n",ADCDAT0);
printk("inilized ADCCON=%x\n",ADCCON);
return 0;
}

module_init(s3c2410_adc_init);   //设置初始化函数

#ifdef MODULE
void __exit s3c2410_adc_exit(void)
{
#ifdef CONFIG_DEVFS_FS
devfs_unregister(devfs_adcraw);          
//devfs_unregister(devfs_adc_dir);
#endif
unregister_chrdev(adcMajor, DEVICE_NAME);   //注销设备
#ifdef USE_IRQ_WAITQUEUE
free_irq(IRQ_ADC_DONE, NULL);     //释放中断号
}
#endif
module_exit(s3c2410_adc_exit);    //设置注销函数
MODULE_LICENSE("GPL");
#endif

应用程序

#include
#include
#include
#include
#include
#include

#define ADC_DEV "/dev/0raw"             //设备驱动程度的位置
#define ADC_WRITE(ch, prescale)((ch)<<16|(prescale))
#define ADC_WRITE_GETCH(data)(((data)>>16)&0x7)   //得到通道号
#define ADC_WRITE_GETPRE(data)((data)&0xff)      //得到转换的比例因子
int fd;

static int get(int channel)
{
int PRESCALE=0XFF;
int data=ADC_WRITE(channel, PRESCALE);    //把channel和 prescale组合成data
write(fd, &data, sizeof(data));      //调用驱动程序中的write()函数
read(fd, &data, sizeof(data));         //调用驱动程序中的read()函数
return data;
}

main()
{
int i;
int val=-1 ;

float d;
void * retval;

if((fd=open(ADC_DEV, O_RDWR))<0)            //打开设备
{
printf("Error opening %s adc device\n", ADC_DEV);
return -1;
}
/*for(i=0; i<=7; i++)
{
d=((float)get(i)*3.3)/1024.0;
printf("a[%d]=%8.4f\n",i,d);
}*/

while(1){
printf("1:get AD4 2:get AD6 3:EXIT \n");   //输入数字选择功能。
scanf("%d",&val);
if(val==1){
d=((float)get(4)*3.3)/1024.0;
printf("AD4=%8.4f\n",d);
}
else if(val==2){
d=((float)get(6)*3.3)/1024.0;
printf("AD6=%8.4f\n",d);
}
else if(val==3){
close(fd);
return 0;
}
else{
printf("val is %d\n",val);
continue;
}
}
}


阅读(1878) | 评论(0) | 转发(0) |
0

上一篇:遍历linux目录

下一篇:mknod指令

给主人留下些什么吧!~~