I2C调试小结
来源:互联网 发布:中国 20年 人口 知乎 编辑:程序博客网 时间:2024/05/23 10:54
文章首发:http://user.qzone.qq.com/276546441/blog/1303712793
1、硬件部分
I2C物理组成上,只有两根线,一根时钟线,一根数据线,线的具体位置原理图都为标注的,找ISCL和ISDA管脚即可。I2C的时钟线不像一般总线的时钟,时刻都存在,只有当总线上有数据发送时,才会产生时钟信号;数据线在没有数据传送时,一直为高电平,故如果发送数据时发现返回总线忙的错误,原因一般为数据线上电平被拉低了。
调试I2C信号时,示波器需要设置为触发式,如果需要查看发送数据是否正确,最好用两个探头同时测时钟与数据信号,这样可以方便看出捕获的数据值。
2、软件部分
硬件了解清楚,便需要注意软件部分了。软件部分分为驱动程序与应用程序。接下来我们分别描述。
2.1 驱动程序
由于操作系统的存在,应用软件和硬件打交道需要通过驱动来进行。笔者使用的设备都基于Linux系统,故本文描述内容基于Linux系统。
驱动部分需要了解两个方面内容:I2C设备体系结构和I2C协议含义。
驱动一般分为总线驱动与设备驱动。由于Linux内核是开源的,所有有人都可以定制内核来适应自己的硬件系统来使用。所以一般情况下,我们要写的设备的总线驱动最新内核中都会包含的,有兴趣的可以通过阅读内核代码来了解其工作原理。
设备驱动只需按总线驱动的要求构造数据结构,实现操作函数注册设备即可。代码结构可以参考已有的驱动代码(附录中提供了一种简单协议的I2C驱动代码,有兴趣可以参考一下),复用已有框架代码,实现自己的设备对应的协议便可以。
I2C直观来说只是通信通道,芯片需要设置寄存器数据时,可以自定义通信协议,应用程序按照协议规定组织好数据发给I2C总线即可。协议制定时,不同芯片的协议有可能不同,常见的协议是 | I2C地址 | 寄存器地址 | 节数据 |,这些协议在芯片手册中都会有明确说明。比如某款镜头的协议如下图:
图表 1: I2C写时序
图表 1为该镜头的写操作协议(时序),由图可知,该镜头在I2C体系中的地址是0xBA(说白了也就是协议头),设备地址为了区分读写操作,一个字节中的前七位为设备地址,当最后一位是0时为写操作,值是1时为读操作,紧跟着的一个字节是寄存器地址0x09,然后是写入寄存器的两字节值0000 0010 1000 0100,所以在写这镜头寄存器时给I2C总线发送的数据为0xBA 0x09 0x02 0x84,发送完后,镜头解析完命令便把地址为0x09寄存器的值设置为0x0284。
图表 2:I2C读时序
图表 2为该镜头的读操作协议(时序),进行读操作之前需要先写入要读的寄存器地址,这便是0xBA 0x09的作用,然后直接读操作,0xBB便是对0xBA地址的I2C设备进行读操作,读出两字节内容,便是0x09对应的寄存器值。
而另一款镜头的协议则有些复杂。见下图。
图表 3:写时序
这个协议的制定格式为| 设备地址 | 44字节数据 |。44字节数据的协议有明确的说明文档,只要按照文档说明组织内容即可达到自己想要的操作。
2.2 应用程序
应用程序主要通过驱动的IOCONTRL接口操作I2C,按手册提供的协议说明发送命令即可,可以参考附录中应用程序部分代码。
3 附录
3.1 简单I2C协议驱动代码#include <dev_i2c.h>#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/fs.h> /* everything... */#include <linux/cdev.h>#include <linux/mm.h>#include <linux/i2c.h>#include <linux/kernel.h> /* printk() */#include <linux/slab.h> /* kmalloc() */#include <asm/uaccess.h> /* copy_*_user */static unsigned short gI2C_curAddr;typedef struct { int devAddr; struct i2c_client client; //!< Data structure containing general access routines. struct i2c_driver driver; //!< Data structure containing information specific to each client. char name[20]; int nameSize; int users; } I2C_Obj;typedef struct { struct cdev cdev; /* Char device structure */ int major; struct semaphore semLock; I2C_Obj *pObj[I2C_DEV_MAX_ADDR]; uint8_t reg[I2C_TRANSFER_BUF_SIZE_MAX]; uint8_t buffer[I2C_TRANSFER_BUF_SIZE_MAX*4]; } I2C_Dev;I2C_Dev gI2C_dev;int I2C_detectClient(struct i2c_adapter *adapter, int address){ I2C_Obj *pObj; struct i2c_client *client; int err = 0; #ifdef I2C_DEBUG printk(KERN_INFO "I2C: I2C_detectClient() at address %x ...\n", address); #endif if(address > I2C_DEV_MAX_ADDR) { printk( KERN_ERR "I2C: ERROR: Invalid device address %x\n", address); return -1; } pObj = gI2C_dev.pObj[address]; if(pObj==NULL) { printk( KERN_ERR "I2C: ERROR: Object not found for address %x\n", address); return -1; } client = &pObj->client; if(client->adapter) return -EBUSY; /* our client is already attached */ memset(client, 0x00, sizeof(struct i2c_client)); client->addr = pObj->devAddr; client->adapter = adapter; client->driver = &pObj->driver; #ifdef I2C_DEBUG printk(KERN_INFO "I2C: i2c_attach_client() ...\n"); #endif if((err = i2c_attach_client(client))) { printk( KERN_ERR "I2C: ERROR: Couldn't attach %s (address=%x)\n", pObj->name, pObj->devAddr); client->adapter = NULL; return err; } #ifdef I2C_DEBUG printk( KERN_INFO "I2C: %s client registered at address %x !\n", pObj->name, pObj->devAddr ); #endif return 0;}int I2C_detachClient(struct i2c_client *client){ int err; if(!client->adapter) return -ENODEV; /* our client isn't attached */ if((err = i2c_detach_client(client))) { printk( KERN_ERR "Client deregistration failed (address=%x), client not detached.\n", client->addr); return err; } client->adapter = NULL; return 0;}int I2C_attachAdapter(struct i2c_adapter *adapter){ #ifdef I2C_DEBUG printk(KERN_INFO "I2C: I2C_attachAdapter() ...\n"); #endif return I2C_detectClient(adapter, gI2C_curAddr);}void *I2C_create(int devAddr) { int ret; struct i2c_driver *driver; struct i2c_client *client = client; I2C_Obj *pObj; #ifdef I2C_DEBUG printk(KERN_INFO "I2C: Driver registration in progress for address %x...\n", devAddr); #endif devAddr >>= 1; if(devAddr>I2C_DEV_MAX_ADDR) return NULL; if(gI2C_dev.pObj[devAddr]!=NULL) { // already allocated, increment user count, and return the allocated handle gI2C_dev.pObj[devAddr]->users++; return gI2C_dev.pObj[devAddr]; } pObj = (void*)kmalloc( sizeof(I2C_Obj), GFP_KERNEL); gI2C_dev.pObj[devAddr] = pObj; memset(pObj, 0, sizeof(I2C_Obj)); pObj->client.adapter = NULL; pObj->users++; pObj->devAddr = devAddr; gI2C_curAddr = pObj->devAddr; driver = &pObj->driver; pObj->nameSize=0; pObj->name[pObj->nameSize++] = 'I'; pObj->name[pObj->nameSize++] = '2'; pObj->name[pObj->nameSize++] = 'C'; pObj->name[pObj->nameSize++] = '_'; pObj->name[pObj->nameSize++] = 'A' + ((pObj->devAddr >> 0) & 0xF); pObj->name[pObj->nameSize++] = 'B' + ((pObj->devAddr >> 4) & 0xF); pObj->name[pObj->nameSize++] = 0; driver->driver.name = pObj->name; driver->id = I2C_DRIVERID_MISC; driver->attach_adapter = I2C_attachAdapter; driver->detach_client = I2C_detachClient; #ifdef I2C_DEBUG printk(KERN_INFO "I2C: i2c_add_driver() ...\n"); #endif if((ret = i2c_add_driver(driver))) { printk( KERN_ERR "I2C: ERROR: Driver registration failed (address=%x), module not inserted.\n", pObj->devAddr); } #ifdef I2C_DEBUG printk(KERN_INFO "I2C: Driver registration successful (address=%x)\n", pObj->devAddr); #endif if(ret<0) { gI2C_dev.pObj[pObj->devAddr] = NULL; kfree(pObj); return NULL; } return pObj;}int I2C_delete(I2C_Obj *pObj){ if(pObj==NULL) return -1; pObj->users--; if(pObj->users<=0) { if(pObj->client.adapter!=NULL) { if(i2c_del_driver(&pObj->driver)) printk(KERN_ERR "I2C: ERROR: Driver remove failed (address=%x), module not removed.\n", pObj->devAddr); pObj->client.adapter = NULL; gI2C_dev.pObj[pObj->devAddr] = NULL; kfree(pObj); } } return 0;}int I2C_read(I2C_Obj *pObj, uint8_t *reg, uint8_t *buffer, uint8_t count, uint8_t dataSize){ uint8_t i; int err; struct i2c_client *client;struct i2c_msg msg[1];unsigned char data[1]; if(pObj==NULL) return -ENODEV; client = &pObj->client; if(!client->adapter) return -ENODEV; if(dataSize<=0||dataSize>4) return -1; for(i=0; i<count; i++) {msg->addr = client->addr;msg->flags = 0;msg->len = 1;msg->buf = data;data[0] = reg[i];err = i2c_transfer(client->adapter, msg, 1);if(err<0) { printk( KERN_ERR " i2c_transfer(0x%x, %x)\n", msg->addr, msg->buf[0]);}if (err >= 0) {msg->flags = I2C_M_RD; msg->len = dataSize;err = i2c_transfer(client->adapter, msg, 1);if (err >= 0) { if(dataSize==1) { buffer[i] = data[0]; } else if(dataSize==2) { buffer[2*i] = data[1]; buffer[2*i+1] = data[0]; }}} if (err<0) return -ENODEV; } return 0;}int I2C_write(I2C_Obj *pObj, uint8_t *reg, uint8_t *buffer, uint8_t count, uint8_t dataSize){ uint8_t i; int err; struct i2c_client *client;struct i2c_msg msg[1];unsigned char data[8]; if(pObj==NULL) return -ENODEV; client = &pObj->client; if(!client->adapter) return -ENODEV; if(dataSize<=0||dataSize>4) return -1; for(i=0; i<count; i++) { msg->addr = client->addr;msg->flags= 0;msg->buf = data;data[0] = reg[i];if(dataSize==1) { data[1] = buffer[i]; msg->len = 2; }elseif(dataSize==2) { data[1] = buffer[2*i+1]; data[2] = buffer[2*i]; msg->len = 3;} err = i2c_transfer(client->adapter, msg, 1); if( err < 0 ) return err; } return 0;}int I2C_devOpen(struct inode *inode, struct file *filp){ int minor, major; minor = iminor(inode); major = imajor(inode);#ifdef I2C_DEBUG printk(KERN_INFO "I2C: I2C_devOpen() , %4d, %2d \n", major, minor);#endif filp->private_data = NULL; return 0; /* success */}int I2C_devRelease(struct inode *inode, struct file *filp){ I2C_Obj *pObj; pObj = (I2C_Obj *)filp->private_data; if(pObj==NULL) return 0;#ifdef I2C_DEBUG printk(KERN_INFO "I2C: I2C_devRelease(), %x, %d \n", pObj->devAddr, pObj->users);#endif I2C_delete(pObj); return 0;}int I2C_devIoctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ I2C_Obj *pObj; int status=0; I2C_TransferPrm transferPrm; pObj = (I2C_Obj *)filp->private_data;#ifdef I2C_DEBUG printk(KERN_INFO "I2C: I2C_devIoctl() \n");#endif if(!I2C_IOCTL_CMD_IS_VALID(cmd)) return -1; cmd = I2C_IOCTL_CMD_GET(cmd); down_interruptible(&gI2C_dev.semLock); switch(cmd) { case I2C_CMD_SET_DEV_ADDR: filp->private_data = I2C_create(arg); if(filp->private_data==NULL) status = -1; break; case I2C_CMD_WRITE: status = copy_from_user(&transferPrm, (void *)arg, sizeof(transferPrm)); if(status==0) { status = copy_from_user(gI2C_dev.reg, transferPrm.reg, transferPrm.count); status |= copy_from_user(gI2C_dev.buffer, transferPrm.value, transferPrm.count*transferPrm.dataSize); if(status==0) { status = I2C_write(pObj, gI2C_dev.reg, gI2C_dev.buffer, transferPrm.count, transferPrm.dataSize); } } break; case I2C_CMD_READ: status = copy_from_user(&transferPrm, (void *)arg, sizeof(transferPrm)); if(status==0) { status = copy_from_user(gI2C_dev.reg, transferPrm.reg, transferPrm.count); if(status==0) { status = I2C_read(pObj, gI2C_dev.reg, gI2C_dev.buffer, transferPrm.count, transferPrm.dataSize); if(status==0) { status = copy_to_user(transferPrm.value, gI2C_dev.buffer, transferPrm.count*transferPrm.dataSize); } } } break; default: status = -1; break; } up(&gI2C_dev.semLock); return status;}struct file_operations gI2C_devFileOps = { .owner = THIS_MODULE, .open = I2C_devOpen, .release = I2C_devRelease, .ioctl = I2C_devIoctl,};int I2C_devInit(void){ int result, i; dev_t dev = 0;#ifdef I2C_DEBUG printk(KERN_INFO "I2C: I2C_devInit() \n");#endif result = alloc_chrdev_region(&dev, 0, 1, I2C_DRV_NAME); if (result < 0) { printk(KERN_WARNING "I2C: can't get device major num \n"); return result; } for(i=0; i<I2C_DEV_MAX_ADDR; i++) { gI2C_dev.pObj[i]=NULL; } gI2C_dev.major = MAJOR(dev); sema_init(&gI2C_dev.semLock, 1); cdev_init(&gI2C_dev.cdev, &gI2C_devFileOps); gI2C_dev.cdev.owner = THIS_MODULE; gI2C_dev.cdev.ops = &gI2C_devFileOps; result = cdev_add(&gI2C_dev.cdev, dev, 1); if (result) printk(KERN_WARNING "I2C: Error [%d] while adding device [%s] \n", result, I2C_DRV_NAME); printk(KERN_INFO "I2C: Module install successful, device major num = %d \n", gI2C_dev.major); return result;}void I2C_devExit(void){ dev_t devno = MKDEV(gI2C_dev.major, 0);#ifdef I2C_DEBUG printk(KERN_INFO "I2C: I2C_devExit() \n");#endif cdev_del(&gI2C_dev.cdev); unregister_chrdev_region(devno, 1);}3.2 应用程序#include <drv_i2c.h>#include <dev_i2c.h>#include <sys/ioctl.h>#include <fcntl.h>#include <unistd.h>int DRV_i2cOpen(DRV_I2cHndl *hndl, Uint8 devAddr){ char deviceName[20]; Uint32 cmd; int status; sprintf(deviceName, "/dev/%s", I2C_DRV_NAME); hndl->fd = open(deviceName, O_RDWR); if(hndl->fd<0) return OSA_EFAIL; cmd = I2C_IOCTL_CMD_MAKE(I2C_CMD_SET_DEV_ADDR); status = ioctl(hndl->fd, cmd, devAddr); if(status<0) close(hndl->fd); return status;}int DRV_i2cRead8(DRV_I2cHndl *hndl, Uint8 *reg, Uint8 *value, Uint8 count){ I2C_TransferPrm prm; Uint32 cmd; int status; prm.dataSize = 1; prm.reg = reg; prm.count = count; prm.value = value; cmd = I2C_IOCTL_CMD_MAKE(I2C_CMD_READ); status = ioctl(hndl->fd, cmd, &prm); return status; }int DRV_i2cWrite8(DRV_I2cHndl *hndl, Uint8 *reg, Uint8 *value, Uint8 count){ I2C_TransferPrm prm; Uint32 cmd; int status; prm.dataSize = 1; prm.reg = reg; prm.count = count; prm.value = value; cmd = I2C_IOCTL_CMD_MAKE(I2C_CMD_WRITE); status = ioctl(hndl->fd, cmd, &prm); return status; }int DRV_i2cRead16(DRV_I2cHndl *hndl, Uint8 *reg, Uint16 *value, Uint8 count){ I2C_TransferPrm prm; Uint32 cmd; int status; prm.dataSize = 2; prm.reg = reg; prm.count = count; prm.value = value; cmd = I2C_IOCTL_CMD_MAKE(I2C_CMD_READ); status = ioctl(hndl->fd, cmd, &prm); return status; }int DRV_i2cWrite16(DRV_I2cHndl *hndl, Uint8 *reg, Uint16 *value, Uint8 count){ I2C_TransferPrm prm; Uint32 cmd; int status; prm.dataSize = 2; prm.reg = reg; prm.count = count; prm.value = value; cmd = I2C_IOCTL_CMD_MAKE(I2C_CMD_WRITE); status = ioctl(hndl->fd, cmd, &prm); return status; }int DRV_i2cClose(DRV_I2cHndl *hndl){ return close(hndl->fd);}int DRV_i2cTestShowUsage(char *str){ OSA_printf(" \n"); OSA_printf(" I2C Test Utility, \r\n"); OSA_printf(" Usage: %s -r|-w <devAddrInHex> <regAddrInHex> <regValueInHex or numRegsToReadInDec> <regSizeInBytes>\r\n", str); OSA_printf(" \n"); return 0;}int DRV_i2cTestMain(int argc, char **argv){ DRV_I2cHndl i2cHndl; Uint8 devAddr, numRegs; Bool doRead; Uint8 dataSize=1; int status, i; static Uint8 regAddr[256], regValue8[256]; static Uint16 regValue16[256]; if(argc<3) { DRV_i2cTestShowUsage(argv[0]); return -1; } if(strcmp(argv[1], "-r")==0) doRead=TRUE; else if(strcmp(argv[1], "-w")==0) doRead=FALSE; else { DRV_i2cTestShowUsage(argv[0]); return -1; } devAddr = 0; numRegs = 4; regValue8[0] = 0; regValue16[0] = 0; regAddr[0] = 0; if(argc>2) devAddr = xstrtoi(argv[2]); if(argc>3) regAddr[0] = xstrtoi(argv[3]); if(argc>5) dataSize = atoi(argv[5]); if(dataSize>2 || dataSize<=0) dataSize=1; if(argc>4) { if(doRead) numRegs = atoi(argv[4]); else { if(dataSize==1) regValue8[0] = xstrtoi(argv[4]); else if(dataSize==2) regValue16[0] = xstrtoi(argv[4]); } } if(devAddr==0) { OSA_printf(" I2C: Invalid device address\n"); DRV_i2cTestShowUsage(argv[0]); return -1; } // OSA_printf(" I2C: Opening I2C at device address %x ...\n", devAddr); status = DRV_i2cOpen(&i2cHndl, devAddr); if(status != OSA_SOK) { OSA_ERROR("DRV_i2cOpen(%d)", devAddr); return status; } if(status==OSA_SOK) { #if 1 if(doRead) { for(i=1; i<numRegs; i++) regAddr[i] = regAddr[0]+i; if(dataSize==1) status = DRV_i2cRead8(&i2cHndl, regAddr, regValue8, numRegs); else if(dataSize==2) status = DRV_i2cRead16(&i2cHndl, regAddr, regValue16, numRegs); OSA_printf(" \n"); if(status==OSA_SOK) { for(i=0; i<numRegs; i++) { if(dataSize==1) { OSA_printf(" I2C: 0x%02x = 0x%02x \n", regAddr[i], regValue8[i] ); } else if(dataSize==2) OSA_printf(" I2C: 0x%02x = 0x%04x \n", regAddr[i], regValue16[i] ); } } else { OSA_printf(" I2C: Read ERROR !!!\n"); } OSA_printf(" \n"); } else { OSA_printf(" \n"); if(dataSize==1) { status = DRV_i2cWrite8(&i2cHndl, regAddr, regValue8, 1); if(status==OSA_SOK) { status = DRV_i2cRead8(&i2cHndl, regAddr, regValue8, 1); } } else if(dataSize==2) { status = DRV_i2cWrite16(&i2cHndl, regAddr, regValue16, 1); if(status==OSA_SOK) { status = DRV_i2cRead16(&i2cHndl, regAddr, regValue16, 1); } } if(status==OSA_SOK) { if(dataSize==1) { OSA_printf(" I2C: 0x%02x = 0x%02x \n", regAddr[0], regValue8[0] ); } else if(dataSize==2) OSA_printf(" I2C: 0x%02x = 0x%04x \n", regAddr[0], regValue16[0] ); } else { OSA_printf(" I2C: Write ERROR !!!\n"); } OSA_printf(" \n"); } #endif DRV_i2cClose(&i2cHndl); }
- I2C调试小结
- SPI和I2C调试小结
- <I2C小结>
- I2C 小结
- I2C 小结
- 调试i2c
- I2C调试
- I2C调试
- linux I2C 驱动小结
- I2C驱动小结---心得
- I2C协议小结
- DM355的I2C调试
- i2c驱动调试经验
- i2c驱动调试经验
- i2c驱动调试经验
- i2c驱动调试经验
- i2c驱动调试经验
- I2C eeprom调试经验
- [NHibernate] Guid 作主键速度超慢的背后
- 关于博客的暂时迁移
- 困惑--上半年我国居民消费价格总水平(CPI)同比上涨5.4%!
- Posix多线程编程-线程属性2
- IIS中没有frontpage服务器扩展解决方法
- I2C调试小结
- 用 Groovy 进行 Ant 脚本编程
- Ubuntu移植qt4.4.3到mips平台
- TextView跑马灯必成五属性
- 时间格式
- MMORPG服务器 - Analysis Architecture
- http://download.csdn.net/source/1481232
- 图案打印: 记法与解释器
- 学习CSS总结