原创 S3C2410的两种ADC驱动,查询式和中断式

2008-11-28 20:52 4448 4 4 分类: MCU/ 嵌入式

1.查寻式的

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/device.h>
#include <asm/irq.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <asm/arch/map.h>
#include <asm/uaccess.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch-s3c2410/regs-adc.h>
#include <asm/arch-s3c2410/regs-clock.h>

#include "adc.h"

#define DEVICE_NAME "adc"
static int adc_major = 0;

static ssize_t adc_read(struct file *file, char  *buf, size_t count, loff_t *ppos)
{
 int data="0";
 unsigned long tmp;
 //printk("1.........\n");
 //start ADC
 tmp = readl(S3C2410_ADCCON) | 0x01; //start AD convert
 writel( tmp, S3C2410_ADCCON);
       //    printk("2.........\n"); 
 do{
  tmp = readl(S3C2410_ADCCON);
 }while(((unsigned int)tmp) & 0x01); //check if Enable_start is low
 //printk("3.........\n");
 //state
 do{
  tmp = readl(S3C2410_ADCCON);
 }while(!(((unsigned int)tmp)&0x8000));
 //read data
// printk("4.........\n");
 data = readl(S3C2410_ADCDAT0) & 0x3ff;
 // printk("5.........\n");
 //printk("data=%d\n", data);
 
 if(copy_to_user(buf, &data, sizeof(data)))
   return -EFAULT;
 
 return (sizeof(int));
}


static ssize_t adc_write(struct file * file, const char  * buf, size_t count, loff_t * off)
{
 unsigned long tmp;
 struct ADC_DEV adcdev;
 
 copy_from_user(&adcdev, (struct ADC_DEV *)buf, count);

 writel((readl(S3C2410_CLKCON) | S3C2410_CLKCON_ADC),S3C2410_CLKCON);   //S3C2410_ADCTSC//使能ADC_CLK

 tmp = readl(S3C2410_ADCTSC);
 tmp &= (~S3C2410_ADCTSC_AUTO_PST) | S3C2410_ADCTSC_XY_PST(S3C2410_NOP_MODE);
 writel(tmp , S3C2410_ADCTSC);
 
 //S3C2410_ADCCON----set chanel and prescaler
 tmp = readl(S3C2410_ADCCON);
 tmp = S3C2410_ADCCON_PRSCEN | PRSCVL(adcdev.prescale) | ADC_INPUT(adcdev.channel);
 writel( tmp, S3C2410_ADCCON);

 return sizeof(struct ADC_DEV);
}

static int adc_open(struct inode * inode, struct file * filp)
{

 printk("ad convert opened!\n");
 
 return 0;
}

static int adc_release(struct inode * inode, struct file * filp)
{
 
 printk("ad convert closed!\n");
 
 return 0;
}


static void adc_setup_cdev(struct cdev *dev, int minor,
  struct file_operations *fops)
{
 int err, devno = MKDEV(adc_major, minor);
   
 cdev_init(dev, fops);
 dev->owner = THIS_MODULE;
 dev->ops = fops;
 err = cdev_add (dev, devno, 1);
 /* Fail gracefully if need be */
 if (err)
  printk (KERN_NOTICE "Error %d adding adc %d", err, minor);
}

static struct cdev AdcDevs;

static struct file_operations adc_remap_ops = {
 .owner = THIS_MODULE,
 .open = adc_open,
 .read = adc_read, 
 .write = adc_write,
 .release = adc_release,
};


int __init adc_init(void)
{
 /* normal ADC */
 int result;
 dev_t dev = MKDEV(adc_major, 0);

 /* Figure out our device number. */
 if (adc_major)
  result = register_chrdev_region(dev, 1, "adc");
 else {
  result = alloc_chrdev_region(&dev, 0, 1, "adc");
  adc_major = MAJOR(dev);
 }
 if (result < 0) {
  printk(KERN_WARNING "adc: unable to get major %d\n", adc_major);
  return result;
 }
 if (adc_major == 0)                         
  adc_major = result;
 adc_setup_cdev(&AdcDevs, 0, &adc_remap_ops);
 printk("adc device installed, with major %d\n", adc_major);
 return 0;
}

static void adc_cleanup(void)
{
 cdev_del(&AdcDevs);
 unregister_chrdev_region(MKDEV(adc_major, 0), 1);
 printk("adc device uninstalled\n");
}


module_init(adc_init);
module_exit(adc_cleanup);
MODULE_AUTHOR("Machuanlong");
MODULE_LICENSE("Dual BSD/GPL");
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

adc.h

#ifndef __ADC_H__
#define __ADC_H__

       
struct ADC_DEV
{
 int channel;
 int prescale;
};

#define S3C2410_ADCTSC_AUTO_PST   (1<<2)
#define S3C2410_NOP_MODE    3
#define S3C2410_ADCTSC_XY_PST(x)  (((x)&0x3)<<0)
#define ADC_INPUT(x)  (x<<3)     //选取通道
#define PRSCVL(x)  (x<<6)        //设分频值
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

Makefile:

///////////////////////////////////////////////////////////////////////////////////

ifeq ($(KERNELRELEASE),)

#KERNELDIR ?= /your/target/source/directory/
#KERNELDIR ?= /source/kernel/linux-2.6.8.1-farsight
#KERNELDIR ?= /disk3/linux-2.6.13-mcl+lcd+yaffs2+nand+cs8900
KERNELDIR ?= /disk2/linux-2.6.14


PWD := $(shell pwd)

modules:
 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
 rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

.PHONY: modules modules_install clean

else
    obj-m := s3c2410-adc.o
endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

测试程序:

/**********************************************
* *AD convert driver test function
*  *date : created at 2008-01-03 by baijb
**********************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>

#define PATH  "/dev/adc"  //device file

static struct ADC_DEV
{
 int channel;
 int prescale;
}adc_infor;

int main(void)
{
 int fd;
 int result, data;
 int val;
 float d;
 //int times = 0;

 fd = open(PATH, O_RDWR);
 if (fd < 0) {
  printf("Failed to open ad_driver\n");
  exit(1);
 }
 
 printf("Please select which chanel to read....\n");
      printf("0 : chanel--0\n");
 printf("1 : chanel--1\n");
      scanf("%d", &val);

 if((val !=0) && (val !=1))
  val = 0;      //by default the chanel is 0

 adc_infor.channel = val;   //chanel 0 or 1
 adc_infor.prescale = 255;   
 
 do {
  result = write(fd, (void *)&adc_infor, sizeof(adc_infor)) == sizeof(struct ADC_DEV); 
  if (!result) {
   printf("wrong when writing!\n");
   goto failed; 
  }
  
  result = read(fd, &data, sizeof(data)) == sizeof(data);
  if (!result) {
   printf("Wrong size!\n");
   goto failed; 
  }

  //printf("chanel %d --ad result=%d\n", val, data);
   printf("fuck1....................");
  d=((float)data*3.3)/1024.0;
   printf("%8.4f\t",d);
   printf("\n");
  sleep(1);
 }while(1);
 
failed:
 close(fd);
 
 return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

挂载方法

insmod s3c2410-adc.ko

mknod /dev/adc c 253 0

./adc_test

 




文章评论1条评论)

登录后参与讨论

用户24289 2008-12-23 11:43

我的错误是unable to handle kernel paging request at virtual address 58000000,pgd=c268c000,[58000000]*pgd=000000,internal error:0ops:805[#1]
相关推荐阅读
用户6646 2010-06-09 16:44
Linux C中令人讨厌的段错误
作者:孙晓明,华清远见嵌入式学院讲师同学们在做练习的时候,编译完程序,执行的时候,有时会莫名的出现 “Segment fault”,即段错误,段错误是让许多C程序员都头疼的提示,因为对于这种模糊的提示...
用户6646 2010-06-09 13:06
VC6 显示行号 (无限制注册版)
make编译时出现错误, 会提示哪一行。可惜vc中不能显示行号,很是郁闷。这个插件可以显示行号,呵呵,很有用。VC显示行号插件说明-----------------------------------...
用户6646 2010-05-22 10:07
删除 nero search 的有效方法
不知道从什么时候开始,Nero多出来一个绑定的Nero Search,虽然可以不然它显示,可是他仍然会在后台占用资源。可以用以下方法解决:开始->运行,依次输入下列文字回车、确定即可(每次输一行...
用户6646 2010-04-03 08:46
2007年5月22日完成的全电控小电视(版本V2.0)
基础功能部分写了4000多行汇编,加上遥控红外部分达到了6000多行,大体介绍如下:1. 内置开关电源转换,11-37V供电;2. 全轻触操作,无机械可调器件,PWM调节亮度/色彩/背光;3.按钮有:...
用户6646 2010-03-17 09:41
三极管HFE与β的关系
hfe是三极管H参数,全称“共发射极低频小信号输出交流短路电流放大系数”,在等效四端网络中又叫“h21”。β是Ic与Ib函数关系的普遍表达式,尤其特指在晶体管基区中电流的分配关系。无论在教科书还是在应...
用户6646 2010-03-17 09:35
三极管饱和(2)
from:http://blog.ednchina.com/xcbao/10816/category.aspx本图片来自于<模拟集成电路的分析与设计>,用来表现三极管饱和时的carriers的分布。但...
我要评论
1
4
关闭 站长推荐上一条 /2 下一条