硬件 tiny 6410 ds18b20 传感器
系统:linux 2.3.68
问题:读取的数据有时候会产生错误,例如突然变成0度 或者1000度 然后在恢复。
驱动代码。
- C/C++ code
驱动代码/* * Temperature sensor driver for zc6410 * register list: * DQ:EINT8(GPN8) * GPNCON:0x7F008830 * GPNDAT:0x7F008834 * GPNPUD:0x7F008838 * * register contorl: * GPN8[17:16] 00=input 01=output 10=Ext.interrupt[8] 11=reserved * */#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/cdev.h>#include <linux/miscdevice.h>#include <linux/ioctl.h>#include <linux/io.h>#include <linux/ioport.h>#include <asm/uaccess.h>//#include <regs-gpio.h>//#include <mach/hardware.h>#define DEBUG_18B20 0#define DEVICE_NAME "ds18b20"#define DSDATA 0x7F008830#define DATAOUTP 1#define DATAINP 0#define DS18B20_MAGIC 'k'#define DS18B20_RESET _IO(DS18B20_MAGIC, 0)static void *pVmem = NULL;#define s3c6410_gpio_cfgpin(pin, state) \ (state?({unsigned int vmem; vmem = ioread32(pin); vmem &= ~(3<<16); vmem |= 1<<16; iowrite32(vmem, pin);}):({unsigned int vmem; vmem = ioread32(pin); vmem &= ~(3<<16); iowrite32(vmem, pin);}))#define s3c6410_gpio_setpin(pin, state) \ (state?({unsigned int vmem; vmem = ioread32(pin+4); vmem |= (1<<8); iowrite32(vmem, pin+4);}):({unsigned int vmem; vmem = ioread32(pin+4); vmem &= ~(1<<8); iowrite32(vmem, pin+4);}))#define s3c6410_gpio_getpin(pin) ((ioread32(pin+4)>>8) & 1)static ssize_t ds18b20_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){ volatile int i, size=count; unsigned char ddat = 0; if (size > 2) size = 1; for (i=0; i<8; i++) { ddat >>= 1; s3c6410_gpio_cfgpin(pVmem, DATAOUTP); s3c6410_gpio_setpin(pVmem, 0); udelay(4); //4us s3c6410_gpio_setpin(pVmem, 1); s3c6410_gpio_cfgpin(pVmem, DATAINP); if ( s3c6410_gpio_getpin(pVmem) ) { ddat |= 0x80; } udelay(80); // >70us s3c6410_gpio_cfgpin(pVmem, DATAOUTP); s3c6410_gpio_setpin(pVmem, 1); udelay(3); // >1us } s3c6410_gpio_cfgpin(pVmem, DATAINP); if(copy_to_user(buff, &ddat, size)) { return -1; } return size;}static ssize_t ds18b20_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp){ volatile int i, size=count; char ddat=0; if (size > 2) size = 1; if (copy_from_user(&ddat, buff, size)) { printk("write data error\n"); return -1; } s3c6410_gpio_cfgpin(pVmem, DATAOUTP); for (i=0; i<8; i++) { s3c6410_gpio_setpin(pVmem, 0); udelay(5); //5us if (ddat & 0x01) { s3c6410_gpio_setpin(pVmem, 1); } udelay(80); // >70us s3c6410_gpio_setpin(pVmem, 1); udelay(3); // >1us ddat >>= 1; } s3c6410_gpio_cfgpin(pVmem, DATAINP); return size;}static int ds18b20_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int ret = 0; switch(cmd) { //case DS18B20_RESET: // reset case 0: // reset s3c6410_gpio_cfgpin(pVmem, DATAOUTP); s3c6410_gpio_setpin(pVmem, 1); udelay(27); s3c6410_gpio_setpin(pVmem, 0); udelay(500); // 500us s3c6410_gpio_setpin(pVmem, 1); udelay(27); s3c6410_gpio_cfgpin(pVmem, DATAINP); udelay(60); ret = s3c6410_gpio_getpin(pVmem); msleep(3); default: return -EINVAL; } return ret;}static int ds18b20_open(struct inode *inode, struct file *file){ /* GPN8[17:16] = 00 */ s3c6410_gpio_cfgpin(pVmem, DATAINP); #if DEBUG_18B20 printk("context of 0x%x is 0x%x\n", DSDATA, ioread32(pVmem));#endif return 0;}static int ds18b20_release(struct inode *inode, struct file *file){ return 0;}static struct file_operations ds18b20_fops = { .owner = THIS_MODULE, .open = ds18b20_open, .release = ds18b20_release, .unlocked_ioctl = ds18b20_ioctl, .read = ds18b20_read, .write = ds18b20_write, //.compat_ioctl = ds18b20_ioctl,};static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &ds18b20_fops,};// register ds18b20static int __init dev_init(void){ int ret; ret = misc_register(&misc); if(!request_mem_region(DSDATA, 0x8, DEVICE_NAME)) goto error; pVmem = ioremap(DSDATA, 0x8); printk(DEVICE_NAME"\tinitialized\n"); return ret;error: misc_deregister(&misc); return -EFAULT; /* bad address */}// unregister ds18b20static void __exit dev_exit(void){ iounmap(pVmem); release_mem_region(DSDATA, 0x8); misc_deregister(&misc);}module_init(dev_init);module_exit(dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("modified by __eabi");