完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本帖最后由 ycd37850105 于 2016-9-19 23:51 编辑
使用camera imgsensor部分的i2c读写程序进行分析。先亮剑(代码) 代码目录:mediatek/custom/common/kernel/imgsensor/src/kd_sensorlist.c /**************************************************************************** 功能:读取从机数据 iReadRegI2C函数调用i2c_master_send函数来发送从机寄存器地址,接着调用i2c_master_recv函数来发送读地址并读取寄存器中的值。 参数: a_pSendData:寄存器的地址 a_sizeSendData:寄存器地址的字节数 a_pRecvData:读取数据存放区 a_sizeRecvData:读取数据字节数 i2cId:读地址 ***************************************************************************/ int iReadRegI2C(u8 *a_pSendData , u16 a_sizeSendData, u8 * a_pRecvData, u16 a_sizeRecvData, u16 i2cId) { int i4RetValue = 0; spin_lock(&kdsensor_drv_lock); g_psti2Cclient->addr = (i2cId >> 1); spin_unlock(&kdsensor_drv_lock); i4RetValue = i2c_master_send(g_pstI2Cclient, (char *)a_pSendData, a_sizeSendData); if (i4RetValue != a_sizeSendData) { PK_DBG("[CAMERA SENSOR] I2C send failed!!, Addr = 0x%xn", a_pSendData[0]); return -1; } i4RetValue = i2c_master_recv(g_pstI2Cclient, (char *)a_pRecvData, a_sizeRecvData); if (i4RetValue != a_sizeRecvData) { PK_DBG("[CAMERA SENSOR] I2C read failed!! n"); return -1; } return 0; } /**************************************************************************** 功能:向从机写入数据 iWriteRegI2C函数调用i2c_master_send函数来发送从机寄存器地址和要写入该寄存器的数据。 参数: a_pSendData:要写入的数据(包括寄存器地址和写入寄存器的数据) a_sizeSendData:发送数据字节数 i2cId:写地址 ***************************************************************************/ int iWriteRegI2C(u8 *a_pSendData , u16 a_sizeSendData, u16 i2cId) { int i4RetValue = 0; int retry = 3; spin_lock(&kdsensor_drv_lock); g_pstI2Cclient->addr = (i2cId >> 1); spin_unlock(&kdsensor_drv_lock); do { i4RetValue = i2c_master_send(g_pstI2Cclient, a_pSendData, a_sizeSendData); if (i4RetValue != a_sizeSendData) { PK_DBG("[CAMERA SENSOR] I2C send failed!!, Addr = 0x%x, Data = 0x%x n", a_pSendData[0], a_pSendData[1] ); } else { break; } uDELAY(50); } while ((retry--) > 0); return 0; } 我们追溯i2c_master_send和i2c_master_recv函数。 代码目录:kernel/drivers/i2c/i2c-core.c /** * i2c_master_send - issue a single I2C message in master transmit mode * @client: Handle to slave device * @buf: Data that will be written to the slave * @count: How many bytes to write, must be less than 64k since msg.len is u16 * * Returns negative errno, or else the number of bytes written. */ int i2c_master_send(const struct i2c_client *client, const char *buf, int count) { int ret; struct i2c_adapter *adap = client->adapter; struct i2c_msg msg; msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.timing = client->timing; msg.len = count; msg.buf = (char *)buf; msg.ext_flag = client->ext_flag; ret = i2c_transfer(adap, &msg, 1); /* * If everything went ok (i.e. 1 msg transmitted), return #bytes * transmitted, else error code. */ return (ret == 1) ? count : ret; } /** * i2c_master_recv - issue a single I2C message in master receive mode * @client: Handle to slave device * @buf: Where to store data read from slave * @count: How many bytes to read, must be less than 64k since msg.len is u16 * * Returns negative errno, or else the number of bytes read. */ int i2c_master_recv(const struct i2c_client *client, char *buf, int count) { struct i2c_adapter *adap = client->adapter; struct i2c_msg msg; int ret; msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.flags |= I2C_M_RD; msg.timing = client->timing; msg.len = count; msg.buf = buf; msg.ext_flag = client->ext_flag; ret = i2c_transfer(adap, &msg, 1); /* * If everything went ok (i.e. 1 msg received), return #bytes received, * else error code. */ return (ret == 1) ? count : ret; } 从源代码中我们可以看出i2c_master_recv和i2c_master_send函数都是对single I2C message 进行处理的,即msg结构体中只有一个消息要处理。对于前面的iReadRegI2C函数,它读取数据需要处理两个消息(一条写消息,一条读消息),因此iReadRegI2C函数可以用下面所示方法实现: int iReadRegI2C(u8 *a_pSendData , u16 a_sizeSendData, u8 * a_pRecvData, u16 a_sizeRecvData, u16 i2cId) { int i4RetValue = 0; spin_lock(&kdsensor_drv_lock); g_pstI2Cclient->addr = (i2cId >> 1) spin_unlock(&kdsensor_drv_lock); struct i2c_msg msgs[] = { { .addr = g_pstI2Cclient->addr, .flags = 0, .timing= g_pstI2Cclient->timing, .len = a_sizeSendData, .buf = a_pSendData, .ext_flag = g_pstI2Cclient->ext_flag, }, { .addr = g_pstI2Cclient->addr, .flags = I2C_M_RD, .len = a_sizeRecvData, .timing= g_pstI2Cclient->timing, .buf = a_pRecvData, .ext_flag = g_pstI2Cclient->ext_flag, }, }; i4RetValue = i2c_transfer(g_pstI2Cclient->adapter, msgs, 2); if(i4RetValue < 0) { PK_DBG("[CAMERA SENSOR] I2C send failed!!, Addr = 0x%xn", a_pSendData[0]); return -1; } } 不管iReadRegI2C函数用哪种方式实现,它最终都会调用到i2c_transfer函数,因为所有读写消息都会传递给i2c_transfer处理。i2c_transfer函数本身不具备驱动适配器物理硬件完成消息交互的能力,它只是寻找到i2c_adapter对应的i2c_algorithm,并使用i2c_algorithm的master_xfer()函数真正驱动硬件流程。 i2c_transfer处理消息机制: 非restart模式下,i2c_transfer函数所引发的对数据读写时序如图1所示,它对每一条消息的处理都会引发开始和停止信号,有多少条消息就会出现多少个开始和停止信号。 图 1 非restart模式下对应时序 restart模式下的时序如图2所示,我们发现整个消息处理过程就只产生一个开始信号和一个停止信号,而时序中会出现restart信号,它仅仅使用一个消息处理。 图 2 restart模式下对应时序 前面所讲的camera imagesensor中的i2c读写函数都是工作在非restart模式下的,而很多稍微复杂一些的i2c设备并不遵循这一读写流程,前段时间在Android平台下调试视频解码芯片ADV7280的i2c通信时就出现了只能写入不能读出的问题,后来仔细查看ADV7280的i2c读写流程时发现,它读数据是在restart模式下,而测试代码是引用了camera imagesensor中的i2c读写函数,因而没有restart信号,读不出数据也是必然了。ADV7280的读写流程如图3所示。 图 3 ADV7280读数据流程 最后经过调整引入restart模式,i2c读OK! 调整后的iReadRegI2C函数: /*************************************************************************** 功能:restart模式下读取从机数据,调用i2c_master_send完成写寄存器地址和读寄存器内容的过程(不需要调用i2c_master_recv读取)。 参数: a_pData:先传入寄存器地址,最后作为读取数据的缓冲区 a_sizeData:高八位为寄存器地址字节数,低八位为接收数据字节数 I2cId:读地址 ***************************************************************************/ int iReadRegI2C(u8 *a_pData , u16 a_sizeData , u16 i2cId) { int i4RetValue = 0; spin_lock(&kdsensor_drv_lock); g_pstI2Cclient->addr = (i2cId >> 1) & I2C_MASK_FLAG | I2C_WR_FLAG | I2C_RS_FLAG;//加入I2C_RS_FLAG,实现restart模式 spin_unlock(&kdsensor_drv_lock); i4RetValue = i2c_master_send(g_pstI2Cclient, a_pData, a_sizeData); if (i4RetValue != a_sizeData) { PK_DBG("[CAMERA SENSOR] I2C send failed!!, Addr = 0x%xn", a_pData[0]); return -1; } g_pstI2Cclient->addr &= I2C_MASK_FLAG; return 0; } |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
9767 浏览 19 评论
10100 浏览 0 评论
3906 浏览 0 评论
8811 浏览 8 评论
2451 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-23 19:48 , Processed in 0.442110 second(s), Total 41, Slave 33 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号