adc与触摸屏调试记录

2440触摸屏原理

原理看了下面这张图就知道了

图中虚线表示屏被按压时x方向和y方向的电阻线会在按压的位置短接。
在操作触摸屏的寄存器测量屏幕坐标时,由触摸屏控制器自动开或关S1---S5

6410相比2440的触摸屏硬件接口没有变化,但中断系统有变化。

NOTE
When Touch Screen device is used, XM or YM is only connected to ground for Touch Screen I/F.

When Touch Screen device is not used, XM or YM is connecting Analog Input Signal for Normal ADC conversion



refer to
http://blog.chinaunix.net/uid-18921523-id-107097.html



************************************************
ok6410 linux2.6.36.2
adc 配置
Device Drivers  --->Character devices  ---><M> ADC driver for 6410
/drivers/char/adc.c

触摸屏配置
Device Drivers  --->Input device support  --->   [*]   Touchscreens  ---><*>   S3C touchscreen driver
drivers/input/touchscreen/s3c-ts.c

飞凌提供的内核,ad和触摸屏不能共同使用,甚至将adc.c编译成模块,在insmod时都会出现
[root@FORLINX6410]# insmod /mnt/adc.ko
insmod: cannot insert '/mnt/adc.ko': Device or resource busy
经过排查发现是adc.c在注册中断时报的错
    ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);
原来在s3c-ts.c已经独自的注册了这个中断,
ret = request_irq(ts_irq->start, stylus_action, IRQF_SAMPLE_RANDOM, "s3c_action", ts);
加上中断号共享标志,如下,重新编译下载即可
ret = request_irq(ts_irq->start, stylus_action, IRQF_SAMPLE_RANDOM|IRQF_SHARED, "s3c_action", ts);

还有问题是ok6410的rmmod不管用,解决方法是建立目录/lib/modules/2.6.36.2

[root@FORLINX6410]# rmmod adc
rmmod: chdir(/lib/modules): No such file or directory

此时建立modules目录
[root@FORLINX6410]# cd /lib
[root@FORLINX6410]# mkdir modules
[root@FORLINX6410]# rmmod adc
rmmod: chdir(2.6.36.2): No such file or directory

此时建立2.6.36.2,即可卸载成功。使用modprobe -r  adc卸载也可以。
[root@FORLINX6410]#  cd modules/
[root@FORLINX6410]# mkdir 2.6.36.2
[root@FORLINX6410]# rmmod adc
rmmod: module 'adc' not found


使用ok6410的8个ai通道
首先把触摸屏驱动取消掉--在feiling给的2.6.36内核,需要在板子文件mach-smdk6410.c中注释掉两处触摸屏的部分,否则如果不把触摸屏搞进内核,编译不通过。
改动adc.c文件,init中注释掉ADCTSC = 0否则ai5和ai7不正常,加入ioctl函数。其他不必变。但是我把read函数也改了一下,去掉了sscanf和20自字节的str数组,直接将value拷给用户,为调用进程省了20字节的栈空间。
//adc8_driver.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>

#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/regs-timer.h>
#include <plat/regs-adc.h>

#define DEBUG  
#ifdef DEBUG    
#define DBG(...) printk(" DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); printk(__VA_ARGS__)    
#else    
#define DBG(...)    
#endif    
#define DEVICE_NAME    "adc"

static void __iomem *base_addr;

typedef struct {
    wait_queue_head_t wait;
    int channel;
    int prescale;
} ADC_DEV;

#ifdef CONFIG_TOUCHSCREEN_X6410
extern int X6410_adc_acquire_io(void);
extern void X6410_adc_release_io(void);
#else
static inline int X6410_adc_acquire_io(void) {
    return 0;
}
static inline void X6410_adc_release_io(void) {
    /* Nothing */
}
#endif

static int __ADC_locked = 0;

static ADC_DEV adcdev;
static volatile int ev_adc = 0;
static int adc_data;

static struct clk    *adc_clock;

#define __ADCREG(name)    (*(volatile unsigned long *)(base_addr + name))
#define ADCCON            __ADCREG(S3C_ADCCON)    // ADC control
#define ADCTSC            __ADCREG(S3C_ADCTSC)    // ADC touch screen control
#define ADCDLY            __ADCREG(S3C_ADCDLY)    // ADC start or Interval Delay
#define ADCDAT0            __ADCREG(S3C_ADCDAT0)    // ADC conversion data 0
#define ADCDAT1            __ADCREG(S3C_ADCDAT1)    // ADC conversion data 1
#define ADCUPDN            __ADCREG(S3C_ADCUPDN)    // Stylus Up/Down interrupt status

#define PRESCALE_DIS        (0 << 14)
#define PRESCALE_EN            (1 << 14)
#define PRSCVL(x)            ((x) << 6)
#define ADC_INPUT(x)        ((x) << 3)
#define ADC_START            (1 << 0)
#define ADC_ENDCVT            (1 << 15)

#define START_ADC_AIN(ch, prescale) \
    do { \
        ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \
        ADCCON |= ADC_START; \
    } while (0)


static irqreturn_t adcdone_int_handler(int irq, void *dev_id)
{
    if (__ADC_locked) {
        adc_data = ADCDAT0 & 0x3ff;

        ev_adc = 1;
        wake_up_interruptible(&adcdev.wait);

        /* clear interrupt */
        __raw_writel(0x0, base_addr + S3C_ADCCLRINT);
    }

    return IRQ_HANDLED;
}

static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
    int value;
    size_t len=sizeof(value);

    if (X6410_adc_acquire_io() == 0) {
        __ADC_locked = 1;

        START_ADC_AIN(adcdev.channel, adcdev.prescale);

        wait_event_interruptible(adcdev.wait, ev_adc);
        ev_adc = 0;

        DBG("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0);

        value = adc_data;

        __ADC_locked = 0;
        X6410_adc_release_io();
    } else {
        value = -1;
    }

    if (count != len) {
    count=len;        
    };
    int r = copy_to_user(buffer, &value, len);
    DBG("len=%d,count=%d,r=%d\n",len,count,r);
    return r ? r : len;//if r=0,then return len
}

static int s3c2410_adc_open(struct inode *inode, struct file *filp)
{
    init_waitqueue_head(&(adcdev.wait));

    adcdev.channel=0;
    adcdev.prescale=0xff;

    DBG("adc opened\n");
    return 0;
}
//static int s3c2410_adc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
static long s3c2410_adc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
    DBG("\n");
    DBG("cmd=%d,arg=%lx\n", cmd, arg);
    switch (cmd)
     {
    case 0:
        adcdev.channel=arg;
        DBG("adcdev.channel= %x\n",adcdev.channel);
        break;
    defalut:
        DBG("case defalut\n");
        return -EINVAL;
        break;
    }
    return 0;
}
static int s3c2410_adc_release(struct inode *inode, struct file *filp)
{
    DBG("adc closed\n");
    return 0;
}


static struct file_operations dev_fops = {
    owner:    THIS_MODULE,
    open:    s3c2410_adc_open,
    read:    s3c2410_adc_read,
    unlocked_ioctl:  s3c2410_adc_ioctl,    
    release:    s3c2410_adc_release,
};

static struct miscdevice misc = {
    .minor    = MISC_DYNAMIC_MINOR,
    .name    = DEVICE_NAME,
    .fops    = &dev_fops,
};

static int __init dev_init(void)
{
    int ret;

    base_addr = ioremap(SAMSUNG_PA_ADC, 0x20);
    if (base_addr == NULL) {
        printk(KERN_ERR "Failed to remap register block\n");
        return -ENOMEM;
    }

    adc_clock = clk_get(NULL, "adc");
    if (!adc_clock) {
        printk(KERN_ERR "failed to get adc clock source\n");
        return -ENOENT;
    }
    clk_enable(adc_clock);
    
    /* normal ADC */
    //ADCTSC = 0;

    ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);
    if (ret) {
        iounmap(base_addr);
        return ret;
    }
    printk (DEVICE_NAME"\therr\n");

    ret = misc_register(&misc);

    printk (DEVICE_NAME"\tinitialized\n");
    return ret;
}

static void __exit dev_exit(void)
{
    free_irq(IRQ_ADC, &adcdev);
    iounmap(base_addr);

    if (adc_clock) {
        clk_disable(adc_clock);
        clk_put(adc_clock);
        adc_clock = NULL;
    }

    misc_deregister(&misc);
}

module_init(dev_init);
module_exit(dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Forlinx Inc.");



//adc_app.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <errno.h>

#define DEBUG
#ifdef DEBUG  
#define DBG(...) fprintf(stderr, " DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); fprintf(stderr, __VA_ARGS__)  
#else  
#define DBG(...)  
#endif  


int main()
{
	int fd,ret,i;
	int value[8]={0};
	int len=sizeof(value[0]);
	fd = open("/dev/adc", 0);
	if (fd < 0) {
	    exit(1);
	 }

//while(1){
//printf("\n");
	for(i=0;i<8;i++) {

		ret = ioctl(fd,0,i);//cmd,arg(channel)
		if(ret < 0) {
		perror("ioctl ADC error");
		exit(1);
		}

		int ret = read(fd, &value[i],len);
		if(ret==len)  
		{
			printf("ADC %d Value: %d,len=%d\n", i,value[i],len);
		}
	 }
//}

      return 0;

}

专业一点的话,就使用_IOW()构造设置通道的命令。类型使用0xfe,貌似在documentation/ioctl-number.c中还没被占用。驱动重写为
//adc8_driver.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>

#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/regs-timer.h>
#include <plat/regs-adc.h>

#define DEBUG  
#ifdef DEBUG    
#define DBG(...) printk(" DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); printk(__VA_ARGS__)    
#else    
#define DBG(...)    
#endif    
#define DEVICE_NAME	"adc"

#define ADC8_IOC_MAGIC 0xfe  //类型,0xfe代表adc8设备
#define ADC8_IOC_SELECT_CHANNEL _IOW(ADC8_IOC_MAGIC,0,int)  //第0个命令是选择通道

static void __iomem *base_addr;

typedef struct {
	wait_queue_head_t wait;
	int channel;
	int prescale;
} ADC_DEV;

#ifdef CONFIG_TOUCHSCREEN_X6410
extern int X6410_adc_acquire_io(void);
extern void X6410_adc_release_io(void);
#else
static inline int X6410_adc_acquire_io(void) {
	return 0;
}
static inline void X6410_adc_release_io(void) {
	/* Nothing */
}
#endif

static int __ADC_locked = 0;

static ADC_DEV adcdev;
static volatile int ev_adc = 0;
static int adc_data;

static struct clk	*adc_clock;

#define __ADCREG(name)	(*(volatile unsigned long *)(base_addr + name))
#define ADCCON			__ADCREG(S3C_ADCCON)	// ADC control
#define ADCTSC			__ADCREG(S3C_ADCTSC)	// ADC touch screen control
#define ADCDLY			__ADCREG(S3C_ADCDLY)	// ADC start or Interval Delay
#define ADCDAT0			__ADCREG(S3C_ADCDAT0)	// ADC conversion data 0
#define ADCDAT1			__ADCREG(S3C_ADCDAT1)	// ADC conversion data 1
#define ADCUPDN			__ADCREG(S3C_ADCUPDN)	// Stylus Up/Down interrupt status

#define PRESCALE_DIS		(0 << 14)
#define PRESCALE_EN			(1 << 14)
#define PRSCVL(x)			((x) << 6)
#define ADC_INPUT(x)		((x) << 3)
#define ADC_START			(1 << 0)
#define ADC_ENDCVT			(1 << 15)

#define START_ADC_AIN(ch, prescale) \
	do { \
		ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \
		ADCCON |= ADC_START; \
	} while (0)


static irqreturn_t adcdone_int_handler(int irq, void *dev_id)
{
	if (__ADC_locked) {
		adc_data = ADCDAT0 & 0x3ff;

		ev_adc = 1;
		wake_up_interruptible(&adcdev.wait);

		/* clear interrupt */
		__raw_writel(0x0, base_addr + S3C_ADCCLRINT);
	}

	return IRQ_HANDLED;
}

static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
	int value;
	size_t len=sizeof(value);

	if (X6410_adc_acquire_io() == 0) {
		__ADC_locked = 1;

		START_ADC_AIN(adcdev.channel, adcdev.prescale);

		wait_event_interruptible(adcdev.wait, ev_adc);
		ev_adc = 0;

		DBG("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0);

		value = adc_data;

		__ADC_locked = 0;
		X6410_adc_release_io();
	} else {
		value = -1;
	}

	if (count != len) {
	count=len;		
	};
	int r = copy_to_user(buffer, &value, len);
	DBG("len=%d,count=%d,r=%d\n",len,count,r);
	return r ? r : len;//if r=0,then return len
}

static int s3c2410_adc_open(struct inode *inode, struct file *filp)
{
	init_waitqueue_head(&(adcdev.wait));

	adcdev.channel=0;
	adcdev.prescale=0xff;

	DBG("adc opened\n");
	return 0;
}
//static int s3c2410_adc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
static long s3c2410_adc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
    DBG("\n");
    DBG("cmd=%d,arg=%lx\n", cmd, arg);
    DBG("ADC8_IOC_SELECT_CHANNEL=%d\n",ADC8_IOC_SELECT_CHANNEL);
    switch (cmd)
     {
	case ADC8_IOC_SELECT_CHANNEL:
		adcdev.channel=arg;
		DBG("adcdev.channel= %x\n",adcdev.channel);
		break;
	defalut:
		DBG("case defalut\n");
		return -EINVAL;
        break;
    }
    return 0;
}
static int s3c2410_adc_release(struct inode *inode, struct file *filp)
{
	DBG("adc closed\n");
	return 0;
}


static struct file_operations dev_fops = {
	owner:	THIS_MODULE,
	open:	s3c2410_adc_open,
	read:	s3c2410_adc_read,
	unlocked_ioctl:  s3c2410_adc_ioctl,	
	release:	s3c2410_adc_release,
};

static struct miscdevice misc = {
	.minor	= MISC_DYNAMIC_MINOR,
	.name	= DEVICE_NAME,
	.fops	= &dev_fops,
};

static int __init dev_init(void)
{
	int ret;

	base_addr = ioremap(SAMSUNG_PA_ADC, 0x20);
	if (base_addr == NULL) {
		printk(KERN_ERR "Failed to remap register block\n");
		return -ENOMEM;
	}

	adc_clock = clk_get(NULL, "adc");
	if (!adc_clock) {
		printk(KERN_ERR "failed to get adc clock source\n");
		return -ENOENT;
	}
	clk_enable(adc_clock);
	
	/* normal ADC */
	//ADCTSC = 0;

	ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);
	if (ret) {
		iounmap(base_addr);
		return ret;
	}
	printk (DEVICE_NAME"\therr\n");

	ret = misc_register(&misc);

	printk (DEVICE_NAME"\tinitialized\n");
	return ret;
}

static void __exit dev_exit(void)
{
	free_irq(IRQ_ADC, &adcdev);
	iounmap(base_addr);

	if (adc_clock) {
		clk_disable(adc_clock);
		clk_put(adc_clock);
		adc_clock = NULL;
	}

	misc_deregister(&misc);
}

module_init(dev_init);
module_exit(dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Forlinx Inc.");
用户中也使用_IOW()构造命令
//adc_app.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <errno.h>

#define DEBUG
#ifdef DEBUG  
#define DBG(...) fprintf(stderr, " DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); fprintf(stderr, __VA_ARGS__)  
#else  
#define DBG(...)  
#endif  


#define ADC8_IOC_MAGIC 0xfe
#define ADC8_IOC_SELECT_CHANNEL _IOW(ADC8_IOC_MAGIC,0,int)

int main()
{
	int fd,ret,i;
	int value[8]={0};
	int len=sizeof(value[0]);
	fd = open("/dev/adc", 0);
	if (fd < 0) {
	    exit(1);
	 }

//while(1){
//printf("\n");
	for(i=0;i<8;i++) {
		ret = ioctl(fd,ADC8_IOC_SELECT_CHANNEL,i);//cmd,arg
		DBG("ADC8_IOC_SELECT_CHANNEL=%d\n",ADC8_IOC_SELECT_CHANNEL);
		if(ret < 0) {
		perror("ioctl ADC error");
		exit(1);
		}

		int ret = read(fd, &value[i],len);
		if(ret==len)  
		{
			printf("ADC %d Value: %d,len=%d\n", i,value[i],len);
		}
	 }
//}

      return 0;

}

执行
[root@FORLINX6410]# /mnt/adc_app
 DBG(drivers/char/adc.c, s3c2410_adc_open(), 140): adc opened
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): 
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=0
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 0
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[0] = 0x030d, 1
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): 
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=1
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 1
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[1] = 0x0129, 1
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): 
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=2
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 2
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[2] = 0x00b9, 1
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): 
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=3
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 3
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[3] = 0x00a9, 1
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): 
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=4
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 4
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[4] = 0x0081, 1
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): 
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=5
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 5
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[5] = 0x0131, 1
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): 
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=6
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 6
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[6] = 0x0090, 1
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 146): 
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 147): cmd=1074068992,arg=7
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 148): ADC8_IOC_SELECT_CHANNEL=1074068992
 DBG(drivers/char/adc.c, s3c2410_adc_ioctl(), 153): adcdev.channel= 7
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 115): AIN[7] = 0x0121, 1
 DBG(drivers/char/adc.c, s3c2410_adc_read(), 129): len=4,count=4,r=0
 DBG(drivers/char/adc.c, s3c2410_adc_release(), 164): adc closed
 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992
ADC 0 Value: 781,len=4
 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992
ADC 1 Value: 297,len=4
 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992
ADC 2 Value: 185,len=4
 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992
ADC 3 Value: 169,len=4
 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992
ADC 4 Value: 129,len=4
 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992
ADC 5 Value: 305,len=4
 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992
ADC 6 Value: 144,len=4
 DBG(adc_app.c, main(), 40): ADC8_IOC_SELECT_CHANNEL=1074068992
ADC 7 Value: 289,len=4



多说一点,6410的adc分辨率是10位或者12位的,可以通过ADCCON.16来配置
RESSEL [16]
 A/D converter resolution selection
0 = 10-bit A/D conversion
1 = 12-bit A/D conversion
不同分辨率时,结果数据在ADCDAT0占用的位数不一样。10位分辨率时用到10位,12位分辨率时用到12位。上面程序用的是10位分辨率。
XPDATA_12[11:10]         When A/D resolution is 12bit, this is X-position conversion data [11:0] value.
XPDATA(Normal ADC)[9:0]  X-Position Conversion data value (Includes Normal ADC Conversion data value)  Data value : 0x0 ~ 0x3FF
电压和测量数据对应关系:
10位分辨率时:0-3.3------>0-1023
12位分辨率时:0-3.3------>0-4095


关于分辨率和精度的区别:
http://bbs.ednchina.com/BLOG_ARTICLE_2058763.HTM

简单点说,“精度”是用来描述物理量的准确程度的,而“分辨率”是用来描述刻度划分的。从定义上看,这两个量应该是风马牛不相及的。(是不是有朋友感到愕然^_^)。很多卖传感器的JS就是利用这一点来糊弄人的了。简单做个比喻:有这么一把常见的塑料尺(中学生用的那种),它的量程是10厘米,上面有100个刻度,最小能读出1毫米的有效值。那么我们就说这把尺子的分辨率是1毫米,或者量程的1%;而它的实际精度就不得而知了(算是0.1毫米吧)。当我们用火来烤一下它,并且把它拉长一段,然后再考察一下它。我们不难发现,它还有有100个刻度,它的“分辨率”还是1毫米,跟原来一样!然而,您还会认为它的精度还是原来的0.1毫米么?(这个例子是引用网上的,个人觉得比喻的很形象!)

回到电子技术上,我们考察一个常用的数字温度传感器:AD7416。供应商只是大肆宣扬它有10位的AD,分辨率是1/1024。那么,很多人就会这么欣喜:哇塞,如果测量温度0-100摄氏度,100/1024……约等于0.098摄氏度!这么高的精度,足够用了。但是我们去浏览一下AD7416的数据手册,居然发现里面赫然写着:测量精度0.25摄氏度!所以说分辨率跟精度完全是两回事,在这个温度传感器里,只要你愿意,你甚至可以用一个14位的AD,获得1/16384的分辨率,但是测量值的精度还是0.25摄氏度^_^

所以很多朋友一谈到精度,马上就和分辨率联系起来了,包括有些项目负责人,只会在那里说:这个系统精度要求很高啊,你们AD的位数至少要多少多少啊……

其实,仔细浏览一下AD的数据手册,会发现跟精度有关的有两个很重要的指标:DNL和INL。似乎知道这两个指标的朋友并不多,所以在这里很有必要解释一下。

DNL:Differencial NonLiner——微分非线性度

INL:Interger NonLiner——积分非线性度(精度主要用这个值来表示)

他表示了ADC器件在所有的数值点上对应的模拟值,和真实值之间误差最大的那一点的误差值。也就是,输出数值偏离线性最大的距离。单位是LSB(即最低位所表示的量)。

当然,像有的AD如△—∑系列的AD,也用Linearity error 来表示精度。

为什么有的AD很贵,就是因为INL很低。分辨率同为12bit的两个ADC,一个INL=±3LSB,而一个做到了±1.5LSB,那么他们的价格可能相差一倍。

所以在这里帮大家把这两个概念理一下,以后大家就可以理直气壮的说精度和分辨率了,而不是将精度理解为分辨率。呵呵,希望对大家有用!

分辨率计算:测量电压范围/(2^AD位数-1);










************************************************
sprintf函数,int-->str

    //test.c  
#include <stdio.h>  
int main()  
{   
    char str[2];  
    int value=0x5678;  
    int i;
    char *cc;  
    sprintf(str, "%x", value);  


    cc=(char*)&value;
    printf("value[0]=%x\n",*cc);
    cc++;
    printf("value[1]=%x\n",*cc);
    cc++;
    printf("value[2]=%x\n",*cc);
    cc++;
    printf("value[3]=%x\n",*cc);

    printf("str=%s\n",str);  
    for( i=0 ;i<7;i++)  
    {  
    printf("str[%d]=%c\n",i,str[i]);  
    }  

    return 0;  
}  
root@song-virtual-machine:test# ./test 
value[0]=78
value[1]=56
value[2]=0
value[3]=0
str=5678
str[0]=5
str[1]=6
str[2]=7
str[3]=8
str[4]=
str[5]=
str[6]=


如果line9 是 sprintf(str, "%d", value);
即将value按照10进制数,每位数字依次塞进str。

root@song-virtual-machine:test# ./test 
value[0]=78
value[1]=56
value[2]=0
value[3]=0
str=22136
str[0]=2
str[1]=2
str[2]=1
str[3]=3
str[4]=6
str[5]=
str[6]=


************************************************
sscanf函数,str-->int

#include <stdio.h>  
int main()  
{   

	char str[20]="56";
	int value;

	sscanf(str, "%d", &value);
	printf("value: %d\n",value);

	sscanf(str, "%x", &value);
	printf("value: %d\n",value);

	return 0;  
}  
root@song-virtual-machine:test# ./test 
value: 56
value: 86




posted on 2012-06-02 09:17  _song  阅读(681)  评论(0编辑  收藏  举报