请教s3c2410的ADC驱动(for 2.6)对ADCDAT0寄存器的数据读取问题?

发布于 2022-09-29 16:35:05 字数 19745 浏览 8 评论 0

我对s3c2410的ADC驱动(for 2.6)进行测试的过程中发现,可以对ADCCON寄存器进行赋值并且读取数据,但从ADCDAT0寄存器中读取的数据有点问题。我在模数输入引脚4、2中分别引入电压信号,但不管输入电压值为多少,从ADCDAT0寄存器读取的值始终为0x3ff(0x3ff表示相应模数输入引脚读取的电压值为满量程3.3伏)。请大虾看看我的程序有什么问题?
1、驱动头文件1:s3c2410-adc.h
#include "s3c2410-adc-h_chip.h"
#ifndef _S3C2410_ADC_H_
#define _S3C2410_ADC_H_

#define ADC_WRITE(ch, prescale)        ((ch)<<16|(prescale))

#define ADC_WRITE_GETCH(data)        (((data)>>16)&0x7)
#define ADC_WRITE_GETPRE(data)        ((data)&0xff)

#endif /* _S3C2410_ADC_H_ */
2、驱动头文件2:s3c2410-adc-h_chip.h
#define ADC_CTL_BASE 0x58000000
#define bADC_CTL(Nb) ((Nb)+S3C2410_VA_ADC1)
#define S3C2410_VA_ADC1 S3C2410_ADDR1(0x01000000)
#define S3C2410_ADDR1(x) (0xF0000000+(x))
/*#define bADC_CTL(Nb)                __REG(ADC_CTL_BASE + (Nb))
  #define __REG(x) io_p2v(x)
  #define io_p2v(x) ((x) | 0xF1000000)
*/
/* Offset */
#define oADCCON                        0x00        /* R/W, ADC control register */
#define oADCTSC                        0x04        /* R/W, ADC touch screen ctl reg */
#define oADCDLY                        0x08        /* R/W, ADC start or interval delay reg */
#define oADCDAT0                0x0c        /* R  , ADC conversion data reg */
#define oADCDAT1                0x10        /* R  , ADC conversion data reg */
/* Registers */
#define ADCCON                        bADC_CTL(oADCCON)
#define ADCTSC                        bADC_CTL(oADCTSC)
#define ADCDLY                        bADC_CTL(oADCDLY)
#define ADCDAT0                        bADC_CTL(oADCDAT0)
#define ADCDAT1                        bADC_CTL(oADCDAT1)
/* Field */
#define fADCCON_PRSCVL                Fld(8, 6)
#define fADCCON_INPUT                Fld(3, 3)
#define fTSC_XY_PST                Fld(2, 0)
#define fADC_DELAY                Fld(6, 0)
#define fDAT_UPDOWN                Fld(1, 15)
#define fDAT_AUTO_PST                Fld(1, 14)
#define fDAT_XY_PST                Fld(2, 12)
#define fDAT_XPDATA                Fld(10, 0)
#define fDAT_YPDATA                Fld(10, 0)
/* ... */
#define ADC_IN0                 0
#define ADC_IN1                 1
#define ADC_IN2                 2
#define ADC_IN3                 3
#define ADC_IN4                 4
#define ADC_IN5                 5
#define ADC_IN6                 6
#define ADC_IN7                 7
#define ADC_BUSY                1
#define ADC_READY                0
#define NOP_MODE                0
#define X_AXIS_MODE                1
#define Y_AXIS_MODE                2
#define WAIT_INT_MODE                3
/* ... */
#define ADCCON_ECFLG                (1 << 15)
#define PRESCALE_ENDIS                (1 << 14)
#define PRESCALE_DIS                (PRESCALE_ENDIS*0)
#define PRESCALE_EN                (PRESCALE_ENDIS*1)

#define PRSCVL(x)                (x << 6)
#define ADC_INPUT(x)                (x << 3)
#define ADCCON_STDBM                (1 << 2)        /* 1: standby mode, 0: normal mode */
#define ADC_NORMAL_MODE                FClrBit(ADCCON, ADCCON_STDBM)
#define ADC_STANDBY_MODE        (ADCCON_STDBM*1)
#define ADCCON_READ_START        (1 << 1)
#define ADC_START_BY_RD_DIS        FClrBit(ADCCON, ADCCON_READ_START)
#define ADC_START_BY_RD_EN        (ADCCON_READ_START*1)
#define ADC_START                (1 << 0)

3、ADC驱动:   s3c2410-adc.c
/*s3c2410-adc.c*/
#include <asm/io.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
//#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <asm/hardware.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
#include <asm/arch/regs-adc.h>
#include "s3c2410-adc.h"
#define DEVICE_NAME "s3c2410_adc"
#define ADC_MAJOR 233
#define BASE_ADDR 0x58000000
unsigned long tmp;
MODULE_AUTHOR("Zxh");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("s3c2410_adc");
typedef struct {
        struct semaphore lock;
        wait_queue_head_t wait;
        int channel;
        int prescale;
} ADC_DEV;

static ADC_DEV adcdev;
/*
static void adcdone_int_handler(int irq, void *dev_id, struct pt_regs *reg)
{
        wake_up(&adcdev.wait);
}
*/

#define START_ADC_AIN(ch, prescale)          {*((int*)ADCCON) = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; *((int*)ADCCON) |= ADC_START;}
static int s3c2410_adc_open(struct inode *inode, struct file *filp)
{
        printk("Added by zxh,enter s3c2410_adc_open function\n");
        init_MUTEX(&adcdev.lock);
        init_waitqueue_head(&(adcdev.wait));

        adcdev.channel=0;
        adcdev.prescale=0xff;
        printk("adcdev.channel=%d,adcdev.prescale=0x%x",adcdev.channel,adcdev.prescale);
// try_module_get(&owner);
       printk( "adc opened\n");
        return 0;
}

static int s3c2410_adc_ioctl (struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg)
{
        if ((cmd <0)||(cmd >7))
        {
                printk("out range of adc !\n");
                return -EINVAL;
        }
        if ((cmd ==5)||(cmd ==7))
        {
                printk("touch green use this channel !\n");
                return -EINVAL;
        }

        adcdev.channel = cmd;
        return 0;
}

static int s3c2410_adc_release(struct inode *inode, struct file *filp)
{
//        module_put();
         printk( "adc closed\n");
        return 0;
}
static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
        
        int data;
        printk("Added by zxh,enter s3c2410_adc_writer function\n");
        if(count!=sizeof(data)){
                //error input data size
                 printk("the size of  input data must be %d\n", sizeof(data));
                return 0;
        }
  printk("before copy_from_user function:\n");
        copy_from_user(&data, buffer, count);
        printk("the value of data is %d\n",data);
        adcdev.channel=ADC_WRITE_GETCH(data);
        adcdev.prescale=ADC_WRITE_GETPRE(data);

         printk("set adc channel=%d, prescale=0x%x\n", adcdev.channel, adcdev.prescale);

        return count;
}

static ssize_t s3c2410_adc_read(struct file *filp,char *buffer,size_t count,loff_t *ppos){
            
            unsigned int ret=0;
            printk("Added by zxh,enter s3c2410_adc_read function\n");
            if (down_interruptible(&adcdev.lock))
                     return -ERESTARTSYS;
            printk("Before START_ADC_AIN:\n");
            START_ADC_AIN(adcdev.channel,adcdev.prescale);
            printk("adcdev.channel=%d,adcdev.prescale=%d\n",adcdev.channel,adcdev.prescale);
            printk("the value of ADCCON is:0x%x",*((int*)ADCCON));
            printk("After START_ADC_AIN:\n");
            //interruptible_sleep_on(&adcdev.wait);
            ret=readl(ADCDAT0);
            //ret = *((int *)ADCDAT0);
            printk("the value of ret is 0x%x\n",ret);
            ret &= 0x3ff;
            printk("AIN[%d] = 0x%04x, %d\n", adcdev.channel, ret, *((int *)ADCCON) & 0x80 ? 1:0);
            copy_to_user(buffer, (char *)&ret, sizeof(ret));
      up(&adcdev.lock);
      return sizeof(ret);
}
static struct file_operations s3c2410_adc_fops = {
               .owner = THIS_MODULE,
               .read  = s3c2410_adc_read,
               .write = s3c2410_adc_write,
               .open = s3c2410_adc_open,
               .release = s3c2410_adc_release,
               .ioctl = s3c2410_adc_ioctl,
               
};
static struct class *adc_class;
static int __init s3c2410_adc_init(void) {
            int err = 0;
            if(register_chrdev(ADC_MAJOR ,DEVICE_NAME ,&s3c2410_adc_fops)){
                printk(DEVICE_NAME "driver:Unable to register driver\n")        ;
                return -ENODEV;
            }
            
            adc_class = class_create(THIS_MODULE, DEVICE_NAME );
            if(IS_ERR(adc_class)){
                  err = PTR_ERR(adc_class);
                  goto out_chrdev;
             }
            class_device_create(adc_class,MKDEV(ADC_MAJOR, 0),NULL,DEVICE_NAME);
            err = devfs_mk_cdev(MKDEV(ADC_MAJOR,0), S_IFCHR | S_IRUGO | S_IWUSR, DEVICE_NAME);
           if(err)
                  goto out_class;
            printk("s3c2410_adc driver initialized\n");
            goto out;
out_class:
           class_device_destroy(adc_class,MKDEV(ADC_MAJOR, 0));
           class_destroy(adc_class);
out_chrdev:
           unregister_chrdev(ADC_MAJOR,DEVICE_NAME );
out:
           return err;
}
static void __exit s3c2410_adc_exit(void){
        class_device_destroy(adc_class,MKDEV(ADC_MAJOR,0));
        class_destroy(adc_class);
         unregister_chrdev(ADC_MAJOR,DEVICE_NAME);
        devfs_remove(DEVICE_NAME);
        printk(DEVICE_NAME "driver removed\n");
    }
module_init(s3c2410_adc_init);
module_exit(s3c2410_adc_exit);

4、测试应用程序 Testadc.c
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define ADC_DEV "/dev/s3c2410_adc"
#define ADC_WRITE(ch, prescale)((ch)<<16|(prescale))
#define ADC_WRITE_GETCH(data)(((data)>>16)&0x7)   //得到通道号
#define ADC_WRITE_GETPRE(data)((data)&0xff)      //得到转换的比例因子
/*
static int get(int channel)
{
int PRESCALE=0xFF;
int data=ADC_WRITE(channel, PRESCALE);
write(adc_fd, &data, sizeof(data));
read(adc_fd, &data, sizeof(data));
return data;
}
*/

int main(void)
{
int i;
int fd;
//float d;
unsigned long tmp;
void * retval;
fd=open(ADC_DEV,O_RDWR);   
if(fd < 0)
{
    printf("Error opening %s adc device\n", ADC_DEV);
    return -1;
}
else
    printf("device id is %d\n",fd);
sleep(1);
while(1){
        printf("Before read:\n");
        ioctl(fd,4,NULL);
        read(fd,&tmp,sizeof(unsigned long));
        printf("The 4 adc is 0x%x\n",tmp);
        sleep(1);
        //tmp=671;
        //write(fd,&tmp,4);
        //printf("write 67 to the file of description fd:\n");
        ioctl(fd,0,NULL);
        read(fd,&tmp,sizeof(unsigned long));
        printf("The 4 adc is 0x%x\n",tmp);
        getchar();
}

/*for(i=0; i<=7; i++)
{
     d=((float)get(i)*3.3)/1024.0;
     printf("a[%d]=%8.4f\n",i,d);
}
*/
close(fd);
return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文