Linux.ChinaUnix.net
ChinaUnix | Linux首页 | 新闻 | 博客 | 文章 | 专栏 | 新手 | 方案 | 图书 | 下载 | 人才 | 手册 | wiki | 搜索     
Linux论坛
  会员: 密码: 免费注册 | 忘记密码 | 会员登录 | 搜索



请教一个ADC0809驱动的问题,高人进
首页 » CU论坛 » Linux » 汇总贴列表 » 驱动开发 »  
[打印] [订阅] [收藏] [本帖文本页] [推荐此主题给朋友,立即获积分]
ady2002
精灵



CU编号: 682681
注册:2008-3-27
最后登录: 2009-06-21
帖子:153
精华:0

可用积分:228 (白手起家)
信誉积分:0
专家积分:0 (本版:0)
空间积分:0
推广积分:0

状态:...离线...

[个人空间] [短信] [博客]


1楼 发表于 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让他工作?????

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



您对本贴的看法:鲜花[0] 臭蛋[0]
版主 dreamice
广告杀手-精灵使
言多必失



CU编号: 562632
注册:2007-5-11
最后登录: 2009-07-02
帖子:3895
精华:37

可用积分:6236 (富足长乐)
信誉积分:110
专家积分:70 (本版:0)
空间积分:0
推广积分:31

状态:...离线...

[个人空间] [短信] [博客]


2楼 发表于 2008-11-17 16:02 
回复 #1 ady2002 的帖子

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

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



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

Nothing is impossible!
版主 dreamice
广告杀手-精灵使
言多必失



CU编号: 562632
注册:2007-5-11
最后登录: 2009-07-02
帖子:3895
精华:37

可用积分:6236 (富足长乐)
信誉积分:110
专家积分:70 (本版:0)
空间积分:0
推广积分:31

状态:...离线...

[个人空间] [短信] [博客]


3楼 发表于 2008-11-17 16:10 
1.ssize_t adc0809_write(),这个写函数什么时候调用,运行,起什么作用的?看了测试程序没有调用,哪放在这里有什么用,仅仅是因为驱动程序框架是这样吗?
===> 如果你应用程序要写这个设备,那么就会调用到这个函数,并把你写的数据保存到adc_write_addr这个地址,实际上只写了一个字节。



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

Nothing is impossible!
版主 dreamice
广告杀手-精灵使
言多必失



CU编号: 562632
注册:2007-5-11
最后登录: 2009-07-02
帖子:3895
精华:37

可用积分:6236 (富足长乐)
信誉积分:110
专家积分:70 (本版:0)
空间积分:0
推广积分:31

状态:...离线...

[个人空间] [短信] [博客]


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 编辑 ]



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

Nothing is impossible!
版主 dreamice
广告杀手-精灵使
言多必失



CU编号: 562632
注册:2007-5-11
最后登录: 2009-07-02
帖子:3895
精华:37

可用积分:6236 (富足长乐)
信誉积分:110
专家积分:70 (本版:0)
空间积分:0
推广积分:31

状态:...离线...

[个人空间] [短信] [博客]


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它了。



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

Nothing is impossible!
版主 Godbach (To be 千里马!)
版主-大法师


CU奥运火炬传递手2008
CU编号: 534931
注册:2007-3-9
最后登录: 2009-07-04
帖子:8560
精华:12

可用积分:22755 (巨富豪门)
信誉积分:112
专家积分:114 (本版:10)
空间积分:2
推广积分:17

状态:...保密...

[个人空间] [短信] [博客]


6楼 发表于 2008-11-17 16:23 
ADC0809基本上是教学中最常用的ADC,单片机中举例有就是用的这个芯片。这个芯片的操作比较简单,建议LZ看一下芯片手册,了解这个芯片的工作方法,然后再对照着驱动看,应该会比较快的理解



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

明犯我强汉天威者,穷搜天下,万里追杀,覆其巢,断其苗裔,戮其身,追其魂,屠其魄,虽远必诛!
----------------------------------
一尺之槌,日取其半,万世不竭!
----------------------------------
欢迎光临Godbach的博客交流技术问题:
http://blog.chinaunix.net/u/33048/
----------------------------------
ady2002
精灵



CU编号: 682681
注册:2008-3-27
最后登录: 2009-06-21
帖子:153
精华:0

可用积分:228 (白手起家)
信誉积分:0
专家积分:0 (本版:0)
空间积分:0
推广积分:0

状态:...离线...

[个人空间] [短信] [博客]


7楼 发表于 2008-11-17 16:35 


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

多谢 版主的热心讲解~~~~
情况是这样的,这个驱动是用来数模转换的,而测试程序只是用来读取转换后的数字,也就是说根本没有用到adc0809_write这个函数
我把测试程序代码贴出来 相信大家能看的更清楚点哦呵呵

/* adc0809_test.c
*  this is a adc0809 char device driver test program.
* Any problem pls contact [email]support@hhcn.com[/email]
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <syslog.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <syslog.h>
#include <signal.h>

#include "adc0809_ioctl.h"

int main()
{
        int adc_fd,count;
        int select = 0;       
        int i = 0;
        adc_fd = open("/dev/adc0809",O_RDWR);
        if (adc_fd <= 0){
                printf("open adc0809 device error\n");
                return 0;
        }

        printf("please input which input do u want:\n");
        scanf("%d",&select);
        //ioctl(adc_fd,select,select);//start collect and convert
        while(1)
        {       
                char ret[2];
                ioctl(adc_fd,select,select);
                count = read(adc_fd,ret,1);//read ad converter's result
                if (count != 0){
                  printf("key = %d\n", ret[0]);
                }
                sleep(3);
        }       
        close(adc_fd);
        return 0;
}

这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] 臭蛋[0]
ady2002
精灵



CU编号: 682681
注册:2008-3-27
最后登录: 2009-06-21
帖子:153
精华:0

可用积分:228 (白手起家)
信誉积分:0
专家积分:0 (本版:0)
空间积分:0
推广积分:0

状态:...离线...

[个人空间] [短信] [博客]


8楼 发表于 2008-11-17 16:36 


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

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



您对本贴的看法:鲜花[0] 臭蛋[0]
ady2002
精灵



CU编号: 682681
注册:2008-3-27
最后登录: 2009-06-21
帖子:153
精华:0

可用积分:228 (白手起家)
信誉积分:0
专家积分:0 (本版:0)
空间积分:0
推广积分:0

状态:...离线...

[个人空间] [短信] [博客]


9楼 发表于 2008-11-17 16:39 


QUOTE:
原帖由 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的相应管脚
这一点 程序里看不见哦



您对本贴的看法:鲜花[0] 臭蛋[0]
版主 Godbach (To be 千里马!)
版主-大法师


CU奥运火炬传递手2008
CU编号: 534931
注册:2007-3-9
最后登录: 2009-07-04
帖子:8560
精华:12

可用积分:22755 (巨富豪门)
信誉积分:112
专家积分:114 (本版:10)
空间积分:2
推广积分:17

状态:...保密...

[个人空间] [短信] [博客]


10楼 发表于 2008-11-17 16:39 
read对应ADC0809的读函数在哪里啊?



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

明犯我强汉天威者,穷搜天下,万里追杀,覆其巢,断其苗裔,戮其身,追其魂,屠其魄,虽远必诛!
----------------------------------
一尺之槌,日取其半,万世不竭!
----------------------------------
欢迎光临Godbach的博客交流技术问题:
http://blog.chinaunix.net/u/33048/
----------------------------------

首页 » CU论坛 » Linux » 汇总贴列表 » 驱动开发 »

 


Copyright © 2001-2008 ChinaUnix.net All Rights Reserved     联系我们:

感谢所有关心和支持过ChinaUnix的朋友们    转载本站内容请注明原作者名及出处

京ICP证041476号


清除 Cookies - Linux时代 - Archiver - WAP - TOP

Processed in 0.099707 second(s), 5 queries , Gzip enabled