请教s3c2410的ADC驱动(for 2.6)对ADCDAT0寄存器的数据读取问题?
我对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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论