免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 17684 | 回复: 56
打印 上一主题 下一主题

请教一个ADC0809驱动的问题,高人进 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-17 15:54 |只看该作者 |倒序浏览
这个驱动一直看不怎么懂,去问客服,客服也不说 说什么是程序员写得 不知道 郁闷死了
这个是华恒ARM9-S3C2410的试验箱的一个  ad0809模块的驱动程序
/* driver/char/adc0809.c
*  this is a adc0809 char device driver.
* Any problem pls contact support@hhcn.com
*/
#include <module.h>
#include <linux/fs.h>
#include <linux/iobuf.h>
#include <linux/major.h>
#include <linux/blkdev.h>
#include <linux/capability.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/hardware.h>
#include <asm/arch/cpu_s3c2410.h>
#include <asm/io.h>
#include <linux/vmalloc.h>

#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <asm/arch/hardware.h>
#include <asm/arch/irqs.h>

#include "adc0809_ioctl.h"

#define ADC0809_MAJOR 231
/*define the adc0809 major node is 231*/


#define adc0809_sle (*(volatile unsigned long *)ADC_GPACON)
#define adc0809_sle_data (*(volatile unsigned long *)ADC_GPADATA)

unsigned long ADC_GPACON, ADC_GPADATA;
unsigned long ADC_0, ADC_1, ADC_2, ADC_3, ADC_4, ADC_5, ADC_6, ADC_7;
unsigned long ADC_DATA;

unsigned long adc_write_addr;
unsigned long adc_read_addr;


devfs_handle_t devfs_adc;

void adc0809_interrupt(int,void *,struct pt_regs *);

int  adc0809_open(struct inode *, struct file *);
int  adc0809_release(struct inode *, struct file *);
int  adc0809_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
ssize_t adc0809_read(struct file *, char * , size_t , loff_t *);
ssize_t adc0809_write(struct file *, const char *, size_t , loff_t *);

static struct file_operations adc0809_fops = {
       ioctl:          adc0809_ioctl,
       open:           adc0809_open,
       read:           adc0809_read,
       write:          adc0809_write,
       release:        adc0809_release,
};

unsigned long data;
unsigned long addr;

void adc0809_interrupt(int irq,void *d,struct pt_regs *regs)
{
/*clear interrupt register for INT 2*/
printk("********************** adc0809_interrupt *********************\n");
SRCPND &= (~0x00000004);    //clear interrupt (bit2)
INTPND = INTPND;
//  EINTPEND &= (~0x00000004);  //bit2

printk("interrupt process!\n");

//udelay(100000);
adc_read_addr = ioremap(0x10000020,4);

/* read ad converter's result */
data = (*(volatile unsigned long *) adc_read_addr);

}

/*
* Open/close code for raw IO.
*/
int adc0809_open(struct inode *inode, struct file *filp)
{
adc_read_addr = ADC_DATA;

printk("open ok\n");
return 0;
}

ssize_t adc0809_read(struct file *filp, char * buf,
                size_t size, loff_t *offp)
{
char key;
key = data;
data = 0;
if(key == 0){
//printk("adc0809_read:have no data to read\n");
return 0;
}
put_user(key,buf);

return 1;
}

ssize_t adc0809_write(struct file *filp, const char *buf,
                 size_t size, loff_t *offp)
这个写函数什么时候调用,运行,起什么作用的?看了测试程序没有调用,哪放在这里有什么用,仅仅是因为
驱动程序框架是这样吗?
{
  char key;
  if (get_user(key, buf))
      return -EFAULT;
  printk("adc0809_write:adc_write_addr=0x%x; key = %c\n",adc_write_addr,key);

(*(volatile unsigned char *) adc_write_addr) = key;
  //put_user(key,buf);
  return 1;
}

//__ioremap
int adc0809_release(struct inode *inode, struct file *filp)
{
       printk("release ok\n");
       return 0;
}

/*
* Deal with ioctls against the raw-device control interface, to bind
* and unbind other raw devices.
*/
int adc0809_ioctl(struct inode *inode,
                 struct file *flip,
                 unsigned int command,
                 unsigned long arg)
{
     int err = 0;
     switch (command) {
case IOCTRL_ADC_0:
adc_write_addr = ADC_0;
//printk("adc0809_ioctl: adc addr: %x\n",adc_write_addr);
/* start collect and convert */
(*(volatile unsigned char *) adc_write_addr) = (char) arg;
return 0;
case IOCTRL_ADC_1:
adc_write_addr = ADC_1;
(*(volatile unsigned char *) adc_write_addr) = (char) arg;
return 0;
case IOCTRL_ADC_2:
adc_write_addr = ADC_2;
(*(volatile unsigned char *) adc_write_addr) = (char) arg;
给2通道地址所指向的空间赋值(char) arg,是启动转换的意思吗?赋任意值都可以吗?这里赋select只是为了方便吗?
上面这条语句和write()函数有什么联系,除了赋值之外,会调用write()函数吗?
return 0;
case IOCTRL_ADC_3:
adc_write_addr = ADC_3;
(*(volatile unsigned char *) adc_write_addr) = (char) arg;
return 0;
case IOCTRL_ADC_4:
adc_write_addr = ADC_4;
(*(volatile unsigned char *) adc_write_addr) = (char) arg;
return 0;
case IOCTRL_ADC_5:
adc_write_addr = ADC_5;
(*(volatile unsigned char *) adc_write_addr) = (char) arg;
return 0;
case IOCTRL_ADC_6:
adc_write_addr = ADC_6;
(*(volatile unsigned char *) adc_write_addr) = (char) arg;
return 0;
case IOCTRL_ADC_7:
adc_write_addr = ADC_7;
(*(volatile unsigned char *) adc_write_addr) = (char) arg;
return 0;
default:
err = -EINVAL;
     }
     // adc_read_addr = ADC_DATA;
     adc_write_addr = ADC_2;
(*(volatile unsigned char *) adc_write_addr) = (char) arg;
   
     return err;
}

int __init adc0809_init(void)
{
static int result;
unsigned long gpfup;
volatile unsigned int bankcon2;

printk("*********************adc0809_init**************\n");

ADC_GPACON = (unsigned int)ioremap(0x56000000,4);
ADC_GPADATA = ioremap(0x56000004,4);

ADC_0 = ioremap(0x10000010,4);
ADC_1 = ioremap(0x10002010,4);
ADC_2 = ioremap(0x10004010,4);
ADC_3 = ioremap(0x10006010,4);
ADC_4 = ioremap(0x10008010,4);
ADC_5 = ioremap(0x1000a010,4);
ADC_6 = ioremap(0x1000c010,4);
ADC_7 = ioremap(0x1000e010,4);

ADC_DATA = ioremap(0x10000020,4);
这是对读数据进行地址映射,这个地址和CPLD的逻辑关系有关对吗?
如果我自己要外接一个0809,如果我片选信号用GPB0,那么这个读寄存器的地址是否可以设置为0x56000014
或者任意一个地址都可以吗,我想应该不可以吧,因为我自己外接0809并没有用CPLD设置好的逻辑。

bankcon2=(volatile unsigned int)ioremap(0x4800000c,4);
*(volatile unsigned int*)bankcon2 |= 3<<13;
/* select NGCS2 */
adc0809_sle |= 0x2000;
adc0809_sle_data &= (~0x2000);改语句是将13位清0,上一条已经将13位设置第二功能片选,那么按照2410手册
数据控制寄存器应该是读到不确定的值,将13为清0又是什么意思?
  上面是片选选中NGCS2,其中的逻辑关系是否已经由CPLD设置好了?

adc_read_addr = ADC_DATA;

/* set external irq rising edge */
set_external_irq(IRQ_EINT2, EXT_RISING_EDGE, GPIO_PULLUP_DIS);

/* set EINT2 pull up */
gpfup = ioremap(0x56000058,4);
(*(volatile unsigned long *)gpfup) = 0;

printk("adc0809_irq : EXTERNAL_IRQ = %d\n",IRQ_EINT2);

disable_irq(IRQ_EINT2);
enable_irq(IRQ_EINT2);

/* request irq */
result=request_irq(IRQ_EINT2,&adc0809_interrupt,SA_INTERRUPT/*|SA_SHIRQ\*/,"adc0809",NULL);
if (result)
   {
     printk("Can't get assigned irq %d,result=%d\n",IRQ_EINT2,result);
    //              return result;
    }

/* register char device */
devfs_adc =
       devfs_register(NULL,"adc0809",DEVFS_FL_DEFAULT,
      ADC0809_MAJOR, 0,
            S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
      &adc0809_fops,NULL);
       return 0;
}

int __init adc0809_exit(void)
{
free_irq(IRQ_EINT2, adc0809_interrupt);
devfs_unregister(devfs_adc);
return 0;
}

/*
__initcall(adc0809_init);
*/
module_init(adc0809_init);
module_exit(adc0809_exit);

-------------------------------------------
总结一下,就是:
1.ssize_t adc0809_write(),这个写函数什么时候调用,运行,起什么作用的?看了测试程序没有调用,哪放在这里有什么用,仅仅是因为驱动程序框架是这样吗?
2.case IOCTRL_ADC_0:
adc_write_addr = ADC_0;  //为什么要不地址赋给adc_write_addr ,整个驱动的获取数据的过程都没有看到有用        
                         //adc_write_addr,这个adc_write_addr 在整个驱动中到底是干嘛用的???   
(*(volatile unsigned char *) adc_write_addr) = (char) arg;
return 0;
给0通道地址所指向的空间赋值(char) arg,是启动转换的意思吗?赋任意值都可以吗?这里赋select只是为了方便吗?上面这条语句和write()函数有什么联系,除了赋值之外,会调用write()函数吗?
3.中断的作用是干嘛?难道是用来启动ADC0809让他工作?????

希望有好心人能解答~~~~感激不尽~~~~
在线等~~~~~~~~~~~~~~~~~~~~~~~

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
2 [报告]
发表于 2008-11-17 16:02 |只看该作者

回复 #1 ady2002 的帖子

贴代码的时候,最好用【code】+【/code】把它组织一下,这样看起来舒服一点

[ 本帖最后由 dreamice 于 2008-11-17 16:04 编辑 ]

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
3 [报告]
发表于 2008-11-17 16:10 |只看该作者
1.ssize_t adc0809_write(),这个写函数什么时候调用,运行,起什么作用的?看了测试程序没有调用,哪放在这里有什么用,仅仅是因为驱动程序框架是这样吗?
===> 如果你应用程序要写这个设备,那么就会调用到这个函数,并把你写的数据保存到adc_write_addr这个地址,实际上只写了一个字节。

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
4 [报告]
发表于 2008-11-17 16:13 |只看该作者
2.case IOCTRL_ADC_0:
adc_write_addr = ADC_0;  //为什么要不地址赋给adc_write_addr ,整个驱动的获取数据的过程都没有看到有用        
                         //adc_write_addr,这个adc_write_addr 在整个驱动中到底是干嘛用的???   
(*(volatile unsigned char *) adc_write_addr) = (char) arg;
return 0;
给0通道地址所指向的空间赋值(char) arg,是启动转换的意思吗?赋任意值都可以吗?这里赋select只是为了方便吗?上面这条语句和write()函数有什么联系,除了赋值之外,会调用write()函数吗?
==>我想这个只是一个测试程序,这个地址是你用户空间程序写下来的数据,最终写到的那个地址。这个case,也就是把ADC_0写到这个地址去,用ioctl来实现操作,而省去了用户程序的写传递。

[ 本帖最后由 dreamice 于 2008-11-17 16:26 编辑 ]

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
5 [报告]
发表于 2008-11-17 16:16 |只看该作者
最后一个问题:
“//udelay(100000);
adc_read_addr = ioremap(0x10000020,4);

/* read ad converter's result */
data = (*(volatile unsigned long *) adc_read_addr);

看清楚这段程序。中断的作用就是告诉你,设备接收到数据了。然后把数据映射到一个地址(adc_read_addr = ioremap(0x10000020,4);),最后把值传递给data这个全局变量,你的用户空间的程序就可以read它了。

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
6 [报告]
发表于 2008-11-17 16:23 |只看该作者
ADC0809基本上是教学中最常用的ADC,单片机中举例有就是用的这个芯片。这个芯片的操作比较简单,建议LZ看一下芯片手册,了解这个芯片的工作方法,然后再对照着驱动看,应该会比较快的理解

论坛徽章:
0
7 [报告]
发表于 2008-11-17 16:35 |只看该作者
原帖由 dreamice 于 2008-11-17 16:10 发表
1.ssize_t adc0809_write(),这个写函数什么时候调用,运行,起什么作用的?看了测试程序没有调用,哪放在这里有什么用,仅仅是因为驱动程序框架是这样吗?
===> 如果你应用程序要写这个设备,那么就会调用到 ...

多谢 版主的热心讲解~~~~
情况是这样的,这个驱动是用来数模转换的,而测试程序只是用来读取转换后的数字,也就是说根本没有用到adc0809_write这个函数
我把测试程序代码贴出来 相信大家能看的更清楚点哦呵呵
  1. /* adc0809_test.c
  2. *  this is a adc0809 char device driver test program.
  3. * Any problem pls contact [email]support@hhcn.com[/email]
  4. */
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #include <sys/socket.h>
  9. #include <syslog.h>
  10. #include <signal.h>
  11. #include <errno.h>
  12. #include <unistd.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <sys/socket.h>
  16. #include <syslog.h>
  17. #include <signal.h>

  18. #include "adc0809_ioctl.h"

  19. int main()
  20. {
  21.         int adc_fd,count;
  22.         int select = 0;       
  23.         int i = 0;
  24.         adc_fd = open("/dev/adc0809",O_RDWR);
  25.         if (adc_fd <= 0){
  26.                 printf("open adc0809 device error\n");
  27.                 return 0;
  28.         }

  29.         printf("please input which input do u want:\n");
  30.         scanf("%d",&select);
  31.         //ioctl(adc_fd,select,select);//start collect and convert
  32.         while(1)
  33.         {       
  34.                 char ret[2];
  35.                 ioctl(adc_fd,select,select);
  36.                 count = read(adc_fd,ret,1);//read ad converter's result
  37.                 if (count != 0){
  38.                   printf("key = %d\n", ret[0]);
  39.                 }
  40.                 sleep(3);
  41.         }       
  42.         close(adc_fd);
  43.         return 0;
  44. }

复制代码


这while这个循环里,如果ioctl函数在while循环之外,一直read的数据是一样的,只有循环的ioctl才能获取新的数据
所以我猜想 ioctl这个函数是不是使能ADC0809芯片让他工作,以触发中断,但是在驱动中又看不懂到底是怎么触发中断的
很是不解啊。case IOCTRL_ADC_0: adc_write_addr = ADC_0;这两句其实是选着相应的ADC0809的管脚,也就是所
读取相应0809的管脚的转换后的数据。希望版主能帮我仔细看看怎么回事 已经苦恼一个月了~~~感激不尽啊

[ 本帖最后由 dreamice 于 2008-11-17 16:40 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2008-11-17 16:36 |只看该作者
原帖由 Godbach 于 2008-11-17 16:23 发表
ADC0809基本上是教学中最常用的ADC,单片机中举例有就是用的这个芯片。这个芯片的操作比较简单,建议LZ看一下芯片手册,了解这个芯片的工作方法,然后再对照着驱动看,应该会比较快的理解

这个我已经看过了 也知道是怎么工作的哦  但是板子的ADC是连接在cpld上的 所以具体管脚怎么接的不是很不清楚

论坛徽章:
0
9 [报告]
发表于 2008-11-17 16:39 |只看该作者
原帖由 dreamice 于 2008-11-17 16:16 发表
最后一个问题:
“//udelay(100000);
adc_read_addr = ioremap(0x10000020,4);

/* read ad converter's result */
data = (*(volatile unsigned long *) adc_read_addr);

看清楚这段程序。中断的作用 ...

恩 这个中断内的函数我是看的懂的

我是想知道  驱动是通过什么方式来触发这个中断的,中断触发后 是不是会去配置一下ADC0809的相应管脚
这一点 程序里看不见哦

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
10 [报告]
发表于 2008-11-17 16:39 |只看该作者
read对应ADC0809的读函数在哪里啊?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP