ADC的基本原理及编写基于ARM的裸机程序的方案解析

一口Linux
关注

结构体s3c_device_adc定义在以下文件:

rchrmplat-samsungDevs.c
#ifdef CONFIG_PLAT_S3C24XX
static struct resource s3c_adc_resource[] = {
 [0] = DEFINE_RES_MEM(S3C24XX_PA_ADC, S3C24XX_SZ_ADC),
 [1] = DEFINE_RES_IRQ(IRQ_TC),
 [2] = DEFINE_RES_IRQ(IRQ_ADC),
};
struct platform_device s3c_device_adc = {
 .name    = "s3c24xx-adc",
 .id    = -1,
 .num_resources  = ARRAY_SIZE(s3c_adc_resource),
 .resource  = s3c_adc_resource,
};
#endif  CONFIG_PLAT_S3C24XX
#if defined(CONFIG_SAMSUNG_DEV_ADC)
static struct resource s3c_adc_resource[] = {
 [0] = DEFINE_RES_MEM(SAMSUNG_PA_ADC, SZ_256),
 [1] = DEFINE_RES_IRQ(IRQ_TC),
 [2] = DEFINE_RES_IRQ(IRQ_ADC),
};
struct platform_device s3c_device_adc = {
 .name    = "samsung-adc",
 .id    = -1,
 .num_resources  = ARRAY_SIZE(s3c_adc_resource),
 .resource  = s3c_adc_resource,
};
#endif  CONFIG_SAMSUNG_DEV_ADC

由代码可知,平台驱动对应的platform_device具体内容由宏CONFIG_PLAT_S3C24XX、CONFIG_SAMSUNG_DEV_ADC来控制。驱动编写架构和流程如下

read()

      1、向adc设备发送要读取的命令
         ADCCON    1<<0 | 1<<14 | 0X1<<16 | 0XFF<<6
      2、读取不到数据就休眠
           wait_event_interruptible();
      3、等待被唤醒读数据
         havedata = 0;

adc_handler()

      1、清中断 ADC使用中断来通知转换数据完毕的
      2、状态位置位;
           havedata=1;
      3、唤醒阻塞进程
           wake_up()

probe()

     1、读取中断号,注册中断处理函数
     2、读取寄存器的地址,ioremap
     3、字符设备的操作

驱动需要首先捕获中断信号后再去寄存器读取相应的数据,在ADC控制器没有准备好数据之前,应用层需要阻塞读取数据,所以在读取数据的函数中,需要借助等待队列来实现驱动对应用进程的阻塞。驱动程序

驱动程序对寄存器的操作参考裸机程序,只是基地址需要通过ioremap()做映射,对寄存器的读写操作需要用readl、writel。

driver.c

#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/io.h>
static int major = 250;


static wait_queue_head_t wq;
static int have_data = 0;
static int adc;
static struct resource *res1;
static struct resource *res2;
static void *adc_base;

#define ADCCON 0x0000
#define ADCDLY 0x0008
#define ADCDAT 0x000C
#define CLRINTADC 0x0018
#define ADCMUX 0x001C


static  irqreturn_t adc_handler(int irqno, void *dev)

 have_data = 1;

 printk("11111");
 清中断
 writel(0x12,adc_base + CLRINTADC);
 wake_up_interruptible(&wq);
 return IRQ_HANDLED;

static int adc_open (struct inode *inod, struct file *filep)


 return 0;

static ssize_t adc_read(struct file *filep, char __user *buf, size_t len, loff_t *pos)

   writel(0x3,adc_base + ADCMUX);
 writel(1<<0 | 1<<14 | 0X1<<16 | 0XFF<<6 ,adc_base +ADCCON );

 wait_event_interruptible(wq, have_data==1);

 read data
 adc = readl(adc_base+ADCDAT)&0xfff;
 
 if(copy_to_user(buf,&adc,sizeof(int)))
 {
   return -EFAULT;
 }
 have_data = 0;
 return len;

static  int adc_release(struct inode *inode, struct file *filep)

 return 0;

static struct file_operations  adc_ops =

 .open = adc_open,
 .release = adc_release,
 .read = adc_read,
};


static int hello_probe(struct platform_device *pdev)

 int ret;
 printk("match 0k ");

 res1 = platform_get_resource(pdev,IORESOURCE_IRQ, 0);
   res2 = platform_get_resource(pdev,IORESOURCE_MEM, 0);
   
 ret = request_irq(res1->start,adc_handler,IRQF_DISABLED,"adc1",NULL);
     adc_base = ioremap(res2->start,res2->end-res2->start);

 register_chrdev( major, "adc", &adc_ops);
 init_waitqueue_head(&wq);
 
 return 0;

static int hello_remove(struct platform_device *pdev)

 free_irq(res1->start,NULL);
 free_irq(res2->start,NULL);  
 unregister_chrdev( major, "adc");
 return 0;


static struct of_device_id adc_id[]=

 {.compatible = "fs4412,adc" },
};

static struct platform_driver hello_driver=

 
 .probe = hello_probe,
 .remove = hello_remove,
 .driver ={
   .name = "bigbang",
   .of_match_table = adc_id,
 },
};

static int hello_init(void)

 printk("hello_init");
 return platform_driver_register(&hello_driver);

static void hello_exit(void)

 platform_driver_unregister(&hello_driver);
 printk("hello_exit ");
 return;

MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);

测试程序

test.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

main()

 int fd,len;
 int adc;
 fd = open("/dev/hello",O_RDWR);
 if(fd<0)
 {
   perror("open fail ");
   return ;
 }

 while(1)
 {
   read(fd,&adc,4);
   printf("adc%0.2f V ",(1.8*adc)/4096);
 }

 close(fd);


声明: 本文由入驻OFweek维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。
侵权投诉

下载OFweek,一手掌握高科技全行业资讯

还不是OFweek会员,马上注册
打开app,查看更多精彩资讯 >
  • 长按识别二维码
  • 进入OFweek阅读全文
长按图片进行保存