Chinaunix首页 | 论坛 | 博客
  • 博客访问: 120039
  • 博文数量: 24
  • 博客积分: 616
  • 博客等级: 中士
  • 技术积分: 375
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-01 10:54
文章分类
文章存档

2012年(24)

我的朋友

分类: LINUX

2012-07-24 10:26:42

平台:micro2440
系统:ubuntu10.04
内核:2.6.32.2
使用ADC通道为channel0
 
 
底层驱动程序如下:
 
 

/*********************************
**        adc 驱动程序          **
*********************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
 
#include
#include
#include
#include
#include "s3c24xx-adc.h"
static void __iomem *base_addr;
#define ADCCON      (*(volatile unsigned long *)(base_addr + 0)) //ADC control
#define ADCTSC      (*(volatile unsigned long *)(base_addr + 0x04)) //ADC touch screen control
#define ADCDLY      (*(volatile unsigned long *)(base_addr + 0x08)) //ADC start or Interval Delay
#define ADCDAT0     (*(volatile unsigned long *)(base_addr + 0x0c)) //ADC conversion data 0
#define ADCDAT1     (*(volatile unsigned long *)(base_addr + 0x10)) //ADC conversion data 1
#define ADCUPDN     (*(volatile unsigned long *)(base_addr + 0x14)) //Stylus Up/Down interrupt status
#define DEVICE_NAME "adc_micro2440_drv"
static struct semaphore lock;
typedef struct {
 wait_queue_head_t wait;
 int channel;
 int prescale;
}ADC_DEV;
static struct clk *adc_clock;

static int OwnADC = 0;
static ADC_DEV adcdev;
static volatile int ev_adc = 0;
static int adc_data;
static int biaozhi_adc_start = 0;
 

#define PRESCALE_DIS        (0 << 14)
#define PRESCALE_EN         (1 << 14)
#define PRSCVL(x)           ((x) << 6)
#define ADC_INPUT(x)        ((x) << 3)
#define ADC_START           (1 << 0)
#define ADC_ENDCVT          (1 << 15)

void adc_start(int ch,int prescale)
{
 ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ;
 ADCCON |= ADC_START;
}
static irqreturn_t adc_interupt_handler(int irq, void *dev_id)
{
   if(biaozhi_adc_start>0)
   {
      adc_data = ADCDAT0 & 0x3ff;//获取AD数值
      ev_adc = 1;
      wake_up_interruptible(&adcdev.wait);
   }
 return IRQ_HANDLED;
}
static ssize_t adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
 char str[20];
 int value;
 size_t len;
  biaozhi_adc_start = 1;
  adc_start(adcdev.channel, adcdev.prescale);
  wait_event_interruptible(adcdev.wait, ev_adc);
  ev_adc = 0;
  //DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0);
  value = adc_data;
  biaozhi_adc_start = 0;
  up(&lock);
 
 len = sprintf(str, "%d\n", value);//将value打印成一个字符串保存在str中
 if (count >= len) {
  int r = copy_to_user(buffer, str, len);
  return r ? r : len;
 } else {
  return -EINVAL;
 }
}
static int adc_open(struct inode *inode,struct file *file)
{
      //尝试打开互斥锁
       int ret;
       ret=down_trylock(&lock);
       if(ret!=0)
        return -EBUSY;
      //将中断加入等待队列
      init_waitqueue_head(&(adcdev.wait));
      //初始化adc采样通道及预分频参数
      adcdev.channel=0;
      adcdev.prescale=0xff;
      return 0;
     
 } 
static int adc_close(struct inode *inodep,struct file *file)
{
     //pwm_micro2440_stop();
      //up(&lock);//释放互斥锁
     return 0;
}
static struct file_operations dev_fops={
 .owner=THIS_MODULE,
 .open=adc_open,
 .release=adc_close,
 //.ioctl=pwm_ioctl,
 .read=adc_read,
 //.write=lc04_write,
};
static struct miscdevice misc={
 .name=DEVICE_NAME,
 .minor=MISC_DYNAMIC_MINOR,
 .fops=&dev_fops,
};
static int __init adc_micro2440_init(void)
{
     int ret;
     //初始化锁
     init_MUTEX(&lock);
     //IO映射
     base_addr=ioremap(0x58000000,0x20);//0x58000000为ADC的首地址总共映射了6个寄存器
     //获取ADC时钟
     adc_clock=clk_get(NULL,"adc");
     clk_enable(adc_clock);
     //注册中断
     ret=request_irq(IRQ_ADC,adc_interupt_handler,IRQF_SHARED,DEVICE_NAME,&adcdev);
     //选择ADC为普通模式
     ADCTSC=0;
     //注册混杂设备
     ret=misc_register(&misc); 
     return ret;
}
void __exit adc_micro2440_exit(void)
{
    //1.注销中断
    free_irq(IRQ_ADC,&adcdev);
    //2.取消寄存器映射
    iounmap(base_addr);
    //3.停止ADC时钟
    clk_disable(adc_clock);
    clk_put(adc_clock);
    adc_clock=NULL;
    //4.注销混杂设备
    misc_deregister(&misc);//注销混杂设备 
}
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("xubin");
module_init(adc_micro2440_init);
module_exit(adc_micro2440_exit);
 
 
应用程序:
 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
 fprintf(stderr, "press Ctrl-C to stop\n");
 int fd = open("/dev/adc_micro2440_drv", 0);
 if (fd < 0) {
  perror("open ADC device:");
  return 1;
 }
 for(;;) {
  char buffer[30];
  int len = read(fd, buffer, sizeof buffer -1);
  if (len > 0) {
   buffer[len] = '\0';
   int value = -1;
   sscanf(buffer, "%d", &value);//将字符串buffer按照整数的形式存在value中
   printf("ADC Value: %d\n", value);
  } else {
   perror("read ADC device:");
   return 1;
  }
  usleep(500* 1000);
 }
 
 close(fd);
}
阅读(1711) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~