忘记密码   免费注册 查看新帖 | 论坛精华区
ChinaUnix.net
  平台论坛 博客 微博 读书 人才 精华 文库 自测 | 频道操作系统 开发 数据库 存储 服务器 网络 IT新闻 Linux 下载 Power用户组
最近访问板块 发新帖
查看: 8212 | 回复: 56

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

Rank: 1

帖子
141
主题
26
精华
0
可用积分
228
专家积分
0
在线时间
119 小时
注册时间
2008-03-27
最后登录
2009-06-21
论坛徽章:
0
发表于 2008-11-17 15:54:39 |显示全部楼层
这个驱动一直看不怎么懂,去问客服,客服也不说 说什么是程序员写得 不知道 郁闷死了
这个是华恒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让他工作?????

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

Rank: 8Rank: 8

帖子
5585
主题
214
精华
38
可用积分
18873
专家积分
80
在线时间
2940 小时
注册时间
2007-05-11
最后登录
2012-02-10
论坛徽章:
0
发表于 2008-11-17 16:02:49 |显示全部楼层

回复 #1 ady2002 的帖子

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

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

Nginx源码分析交流群:120388348
微博地址:http://weibo.com/u/1847971765
言多必失

Rank: 8Rank: 8

帖子
5585
主题
214
精华
38
可用积分
18873
专家积分
80
在线时间
2940 小时
注册时间
2007-05-11
最后登录
2012-02-10
论坛徽章:
0
发表于 2008-11-17 16:10:44 |显示全部楼层
1.ssize_t adc0809_write(),这个写函数什么时候调用,运行,起什么作用的?看了测试程序没有调用,哪放在这里有什么用,仅仅是因为驱动程序框架是这样吗?
===> 如果你应用程序要写这个设备,那么就会调用到这个函数,并把你写的数据保存到adc_write_addr这个地址,实际上只写了一个字节。
Nothing is impossible!

Nginx源码分析交流群:120388348
微博地址:http://weibo.com/u/1847971765
言多必失

Rank: 8Rank: 8

帖子
5585
主题
214
精华
38
可用积分
18873
专家积分
80
在线时间
2940 小时
注册时间
2007-05-11
最后登录
2012-02-10
论坛徽章:
0
发表于 2008-11-17 16:13:24 |显示全部楼层
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 编辑 ]
Nothing is impossible!

Nginx源码分析交流群:120388348
微博地址:http://weibo.com/u/1847971765
言多必失

Rank: 8Rank: 8

帖子
5585
主题
214
精华
38
可用积分
18873
专家积分
80
在线时间
2940 小时
注册时间
2007-05-11
最后登录
2012-02-10
论坛徽章:
0
发表于 2008-11-17 16:16:25 |显示全部楼层
最后一个问题:
“//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它了。
Nothing is impossible!

Nginx源码分析交流群:120388348
微博地址:http://weibo.com/u/1847971765
To be 千里马!

Rank: 8Rank: 8

帖子
14516
主题
366
精华
21
可用积分
58752
专家积分
79
在线时间
5761 小时
注册时间
2007-03-09
最后登录
2012-02-09
论坛徽章:
0
发表于 2008-11-17 16:23:35 |显示全部楼层
ADC0809基本上是教学中最常用的ADC,单片机中举例有就是用的这个芯片。这个芯片的操作比较简单,建议LZ看一下芯片手册,了解这个芯片的工作方法,然后再对照着驱动看,应该会比较快的理解
----------
欢迎光临Godbach的博客交流技术问题:
Godbach's Blog
---------
明犯我强汉天威者,穷搜天下,万里追杀,覆其巢,断其苗裔,戮其身,追其魂,屠其魄,虽远必诛!

Rank: 1

帖子
141
主题
26
精华
0
可用积分
228
专家积分
0
在线时间
119 小时
注册时间
2008-03-27
最后登录
2009-06-21
论坛徽章:
0
发表于 2008-11-17 16:35:12 |显示全部楼层
原帖由 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 编辑 ]

Rank: 1

帖子
141
主题
26
精华
0
可用积分
228
专家积分
0
在线时间
119 小时
注册时间
2008-03-27
最后登录
2009-06-21
论坛徽章:
0
发表于 2008-11-17 16:36:43 |显示全部楼层
原帖由 Godbach 于 2008-11-17 16:23 发表
ADC0809基本上是教学中最常用的ADC,单片机中举例有就是用的这个芯片。这个芯片的操作比较简单,建议LZ看一下芯片手册,了解这个芯片的工作方法,然后再对照着驱动看,应该会比较快的理解

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

Rank: 1

帖子
141
主题
26
精华
0
可用积分
228
专家积分
0
在线时间
119 小时
注册时间
2008-03-27
最后登录
2009-06-21
论坛徽章:
0
发表于 2008-11-17 16:39:36 |显示全部楼层
原帖由 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的相应管脚
这一点 程序里看不见哦
To be 千里马!

Rank: 8Rank: 8

帖子
14516
主题
366
精华
21
可用积分
58752
专家积分
79
在线时间
5761 小时
注册时间
2007-03-09
最后登录
2012-02-09
论坛徽章:
0
发表于 2008-11-17 16:39:49 |显示全部楼层
read对应ADC0809的读函数在哪里啊?
----------
欢迎光临Godbach的博客交流技术问题:
Godbach's Blog
---------
明犯我强汉天威者,穷搜天下,万里追杀,覆其巢,断其苗裔,戮其身,追其魂,屠其魄,虽远必诛!
您需要登录后才可以回帖 登录 | 注册

北京皓辰网域网络信息技术有限公司. 版权所有 京ICP证:060528号 北京市公安局海淀分局网监中心备案编号:1101082001
广播电视节目制作经营许可证(京) 字第1234号 中国互联网协会会员  联系我们:
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP