+ -
当前位置:首页 → 问答吧 → adc驱动问题,高手救命

adc驱动问题,高手救命

时间:2007-08-08

来源:互联网

我使用优龙的YL2440的开发板,
我自己写了一个驱动程序:
文件名:adc.c
#ifndef __KERNEL__
    #define __KERNEL__
#endif
#ifndef MODULE
    #define MODULE
#endif
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>         /* kmalloc() */
#include <linux/fs.h>           /* everything... */
#include <linux/errno.h>        /* error codes */
#include <linux/proc_fs.h>
#include <linux/fcntl.h>        /* O_ACCMODE */
#include <asm-arm/io.h>
#include <asm/arch/regs-gpio.h>  
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-adc.h>
#include <linux/delay.h>         
#include <linux/ioport.h>
#include <asm/system.h>         /* cli(), *_flags */
#include <asm/uaccess.h>

#include <asm/arch/irqs.h>
#include <asm/arch/hardware.h>
#include <asm/io.h>
#include "adc.h"
//预分频倍数
#define PRESCALER 19
#define ADCCON (0x58000000)
#define ADCTSC (0x58000004)
#define ADCDLY (0x58000008)
#define ADCDAT0 (0x580000c)
#define ADCDAT1 (0x58000010)
#define ADCUPDN (0x58000014)

MODULE_LICENSE("Dual BSD/GPL");
//static int channel = -1;
static unsigned long *adccon, *adctsc, *adcdly, *adcdat0, *adcdat1, *adcupdn;
static unsigned int adc_usage[MAX_ADC];
static ssize_t adc_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
static int adc_open(struct inode *inode, struct file *filp);
static int adc_release(struct inode *inode, struct file *filp);
int  adc_init(void);
void adc_cleanup(void);

module_init(adc_init);
module_exit(adc_cleanup);

static struct file_operations adc_fops =        /* driver info  */
{
    .owner =    THIS_MODULE,
    .open =  adc_open,
    .release =    adc_release,
    .read =   adc_read,
};

static ssize_t adc_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
    unsigned long flags;
    u32 temp0, temp;
    unsigned short temp2;
    int i = 0, j = 0;
   
    if (count > 8)
    {
        return -EFBIG;
    }
    if (!access_ok(VERIFY_WRITE, (void *)buf, count))
    {
        return -EFAULT;
    }
    //temp1 = (int)filp->private_data;
    local_irq_save(flags);
    //outl(AdcrSave | (1u <_u32 ?temp) | (1u << 24), ADCCON);
    //使能设置预分频,采用AIN0   
    writel((0x1<<14)|(PRESCALER<<6)|(0<<3), adccon);
    //等待通道切换
    for(j = 0; j < 20000; j++)
     i++;
    temp0 = readl(adccon);
    //开始AD转换
    writel(temp0|0x01, adccon);
    //等待AD转换完成
    while((readl(adccon) & 0x01) != 0);
    //等待AD数据写入ADCDAT0
while((readl(adccon) & (0x1 _u60 ? 15)) == 0);
    printk("adccon = %d, adctsc = %d, adcdly = %d, adcdat0 = %d, adcdat1= %d, adcupdn = %d\n", readl(adccon), readl(adctsc), readl(adcdly), readl(adcdat0), readl(adcdat1), readl(adcupdn));
    temp = readl(adcdat0);
    temp2 = temp&0x3fff;
    copy_to_user(buf, &temp2, 2);
    printk("temp2 = %d\n", temp2);
    local_irq_restore(flags);
    return 1;
}

static int adc_open(struct inode *inode, struct file *filp)
{
    int num;
    num = MINOR(inode->i_rdev);
    if (num >= MAX_ADC)
    {
        return -ENODEV;
    }
    adc_usage[num]++;
    //MOD_INC_USE_COUNT;
    try_module_get(THIS_MODULE);
    return 0;          /* success */
}

static int adc_release(struct inode *inode, struct file *filp)
{
    int num;
    num = MINOR(inode->i_rdev);
    if (num >= MAX_ADC)
    {
        return -ENODEV;
    }
    module_put(THIS_MODULE);
    adc_usage[num]--;
    return(0);
}

int adc_init(void)
{
    int  result;
    result = register_chrdev(ADC_MAJOR_NR,  DEVICE_NAME,  &adc_fops);
    if (result < 0)
    {
        printk(KERN_ERR DEVICE_NAME ": Unable to get major %d\n", ADC_MAJOR_NR );
        return(result);
    }
/*****************
    if (ADC_MAJOR_NR == 0)
    {
        ADC_MAJOR_NR = result;
    }   
    ******************/
adccon = ioremap(ADCCON,0x00000004);
adctsc = ioremap(ADCTSC,0x00000004);
adcdly = ioremap(ADCDLY,0x00000004);
adcdat0 = ioremap(ADCDAT0,0x00000004);
adcdat1 = ioremap(ADCDAT1,0x00000004);
adcupdn = ioremap(ADCUPDN,0x00000004);
writel(0x58, adctsc);
writel(0, adcupdn);
printk("adcdat0 = %d\n", readl(adcdat0));
    printk(KERN_INFO DEVICE_NAME ": init OK\n");
    return(0);
}

void adc_cleanup(void)
{
iounmap(adccon);
iounmap(adctsc);
iounmap(adcdly);
iounmap(adcdat0);
iounmap(adcdat1);
iounmap(adcupdn);
    unregister_chrdev(ADC_MAJOR_NR, DEVICE_NAME);
}

Makefile文件内容:
obj-m += adc.o
执行命令:
make -C /usr/src/linux-2.6.12/ SUBDIRS=/root/driver/adc/ modules
进行编译。(说明:“/usr/src/linux-2.6.12/”为内核源文件的目录,“/root/driver/adc/“ 为存放驱动程序的目录)
测试程序:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

int main()
{
int fp;
unsigned short data = 0;
fp = open("/dev/adc", O_RDONLY);
if(fp == -1)
{
  perror("open");
  return errno;
}
while(1)
{
  read(fp, &data, 2);
  printf("adc = %d\n", data);
  sleep(1);
}
return -1;
}
测试程序的Makefile:
EXEC =adctest
OBJS =adctest.o
SRC =adc_test.cpp
CC =arm-linux-gcc
BASEPATH =/usr/src/
LIBPATH =$(BASEPATH)/lib
INCLUDEPATH =$(BASEPATH)/linux-2.6.12/include
LDFLAGS =-Os -g -Dlinux -D__linux__ -Dunix -D__uClinux__ -DEMBED

LDLIBS_OBJS =-c
all: $(EXEC)
$(EXEC): $(OBJS)
$(CC) $(LDFLAGS)  -o $@ $(OBJS)
%.o:%.c
$(CC) $(LDFLAGS) -c $< -o $@
clean:
-rm -f $(EXEC)  *.o
但是运行的结果树出为:
adccon = 50368, adctsc = 88, adcdly = 255, adcdat0 = 0, adcdat1= 32768, adcupdn
= 0
temp2 = 0
adc = 0
adccon = 50368, adctsc = 88, adcdly = 255, adcdat0 = 0, adcdat1= 32768, adcupdn
= 0
temp2 = 0
adc = 0
adccon = 50368, adctsc = 88, adcdly = 255, adcdat0 = 0, adcdat1= 32768, adcupdn
= 0
temp2 = 0
adc = 0
adccon = 50368, adctsc = 88, adcdly = 255, adcdat0 = 0, adcdat1= 32768, adcupdn
= 0
temp2 = 0
adc = 0
adccon = 50368, adctsc = 88, adcdly = 255, adcdat0 = 0, adcdat1= 32768, adcupdn
= 0
temp2 = 0
adc = 0

我觉得所有的设置都是对的,为什么就是AD转换的结果始终为0。
高手救命!!!!!!!!!!      

作者: wujidong   发布时间: 2007-08-08

如果AD的输入量就是0呢?      

作者: 风雪狂客   发布时间: 2007-08-08

输入肯定不为零,在ADS下可以得到正确的AD转换的值!      

作者: wujidong   发布时间: 2007-08-13