I2C | i2c_msg
文章目录
- 一. 对 i2c_msg 的理解我认为应该分为两个主要层面:
- 二. 常见的Slave 驱动程序对 i2c read和write函数实现方式如下:
背景介绍:
这两天在解决客户的一个i2c传输问题时发现对i2c的理解有很多盲点,冒出一身冷汗- -!,问题解决后赶紧复盘总结一下。
带着问题去学习是最快的方法
思考题
:
- 为什么常见的i2c外设驱动中 i2c read 函数要构造 2个 i2c_msg,而 i2c write 函数只要1个i2c_msg?
- 常见i2c外设寄存器地址是8bits的,那么遇到16bits或者32bits的外设寄存器地址该如何构造i2c_msg呢?
如果以上问题你已经熟知,那么大佬,接下来的内容可以忽略不看了,如果有疑问,不妨在小店驻留几分钟。
一. 对 i2c_msg 的理解我认为应该分为两个主要层面:
- i2c_msg的设计角度:
一个i2c_msg
代表着Slave
(i2c client)和Host
(i2c controller)之间的一次单向数据传输
。 - 支持i2c传输协议的外设驱动程序使用 i2c_msg 的角度:
这里又分为四点- i2c 传输是以字节为单位的,具体到i2c_msg.len 指的是以字节指针i2c_msg.buf指向的buffer中字节个数。
- 外设驱动要实现 xxx_i2c_read_bytes 和 xxx_i2c_write_bytes 两个底层函数;
- xxx_i2c_read_bytes 由
2个i2c_msg组成的数组
构成
因为这存在host send和host receive两个数据传输方向;第一个msg.buf用来暂存host向slave发出slave目标寄存器地址,msg.len表示寄存器地址字节长度;第二个msg.buf用来接收slave向host返回数据,msg.len表示期望读到数据的字节长度; - xxx_i2c_write_bytes 仅由
1个i2c_msg
构成
因为只有host send to slave这一个数据传输方向;整个msg.buf暂存了从机目标寄存器地址和待写入其中的数据,msg.len表示整体的字节长度;
(注:数组的目的是为了访问连续,因为数组是连续内存存储的)
注:常见的Slave有Touchscreen,Sensor;i2c controller实际上就是SOC ARM上的一组i2c registers。
二. 常见的Slave 驱动程序对 i2c read和write函数实现方式如下:
- xxx_i2c_read_bytes
(host 发出 slave 地址来建立通信)(host驱动中实现)
host 向 slave 发出 slave 目标寄存器地址;(salve驱动中实现)
slave 向 host 返回 目标寄存器数据;(salve驱动中实现)
static int xxx_i2c_read_bytes(u8 index, u8 *rx_buff, u8 length)
{int ret = -1;struct i2c_msg msgs[] = { /* 注:i2c read因为包含两个方向,所以只需要两个i2c_msg */{//第一个i2c_msg用来发送需要读取的从设备目标寄存器的地址.addr = xxx_client->addr, /* chip address, 7bit */.flags = 0, /* write */.len = lenght1, /* bytes number(注意这里一定是byte为单位),这也是从设备目标寄存器地址的字节长度*/.buf = &index, /* client register address pointer */},{//第二个i2c_msg用来设置接收从设备目标寄存器返回数据的buff以及数据长度.addr = xxx_client->addr,.flags = I2C_M_RD, /* read */.len = length2, /* bytes number(注意这里一定是byte为单位)*/.buf = rx_buff, /* 用来接收数据的缓冲区指针*/},};ret = i2c_transfer(this_client->adapter, msgs, 2); /* i2c host master_xfer callback func */if (ret != 2)PRINT_ERR("READ ERROR!ret=%d\n", ret);return ret;
}
- xxx_i2c_write_bytes
(host 发出 slave 地址来建立通信)(host 驱动中实现)
host 向 slave 发出 slave 目标寄存器地址以及需要往目标寄存器中写入的数据;(salve驱动中实现)
static int xxx_i2c_write_bytes(u8 *tx_buff, u8 length)
{int ret = -1;struct i2c_msg msgs[1]; /*注:i2c write因为是单方向,所以只需要一个i2c_msg*/msgs[0].addr = xxx_client->addr;msgs[0].flags = 0; /* write */msgs[0].len = length; /* bytes number(注意这里一定是byte为单位)*/msgs[0].buf = tx_buff; /* 待写出的数据指针;数据通常为 client register address + data*/ret = i2c_transfer(xxx_client->adapter, msgs, 1); /* i2c host master_xfer callback func */if (ret != 1)PRINT_ERR("WRITE ERROR!ret=%d\n", ret);return ret;
}
总结:
好了,回答前面提出的两个问题:
第一题:一个i2c_msg代表着一次单项数据传输。因为i2c read包含host向slave发送寄存器地址和slave返回数据两个数据传输方向,所以需要两个i2c_msg;而 i2c write时host向slave发送寄存器地址和host往slave寄存器写数据属于同一个数据传输方向,所以只需要一个i2c_msg。
第二题:举例slave寄存器地址为16bits的解决方案,32bits的类似。当slave寄存器地址是16bits时,slave驱动构造的i2c read函数中的第一个i2c_msg对应的len成员表示寄存器地址字节长度,buf成员传入的是寄存器其地址指针;i2c write函数中方法同i2c read,只不过buf后面还跟着待写入寄存器的数据。
I2C | i2c_msg相关推荐
- linux i2c核心,总线与设备驱动,Linux2.6.37 I2C驱动框架分析(一)
最近工作中又使用到了I2C,所以借S3C2440开发板GT2440为硬件平台温习一遍I2C驱动体系. linux内核中IIC驱动的体系框架 linux内核中IIC部分驱动代码位于:/drivers/i ...
- 设备树与驱动的关系_Linux I2C驱动竟然如此简单?手把手教你写i2c驱动
Linux中I2C驱动框架分析 I2C核心(i2c_core) I2C核心维护了i2c_bus结构体,提供了I2C总线驱动和设备驱动的注册.注销方法,维护了I2C总线的驱动.设备链表,实现了设备.驱动 ...
- linux下i2c设备驱动程序,Linux I2C 设备驱动
I2C 设备驱动要使用 i2c_driver 和 i2c_client 数据结构并填充其中的成员函数.i2c_client 一般被包含在设备的私有信息结构体yyy_data 中,而 i2c_drive ...
- linux 脚本给设备节点权限,[Linux] I2C设备读写及文件节点创建
Linux Kernel Version:3.0.35 Platform:Freescale DSA2L 通过I2C读取VGA屏的EDID信息(主要是分辨率),解析后喂给CH7036芯片(LVDS转V ...
- 实例解析linux内核I2C体系结构
实例解析linux内核I2C体系结构 一.概述 谈到在linux系统下编写I2C驱动,目前主要有两种方式,一种是把I2C设备当作一个普通的字符设备来处理,另一种是利用linux I2C驱动体系结构来完 ...
- 在Android源码树中添加userspace I2C读写工具(i2c-util)
by LiAnLab.org / 宋宝华 通过/dev/i2c-n节点,用户可以在userspace直接访问板上的i2c外设寄存器,主要是透过I2C_RDWR这个IO控制命令将i2c_msg数组传递给 ...
- linux驱动之i2c学习
最近在研究linux的i2c驱动,从最底层i2c控制器初始化到应用层与i2c设备交互基本打通了. 一.linux的i2c架构可以用下图表示: IIC适配器对应一条i2c总线,linux里面用i2c_a ...
- linux在内核下使用iic,实例解析linux内核I2C体系结构(2)
四.在内核里写i2c设备驱动的两种方式 在 (1) Adapter方式(LEGACY) (下面的实例代码是在2.6.27内核的pca953x.c基础上修改的,原始代码采用的是本文将要讨论的第2种方式, ...
- 【驱动】linux下I2C驱动架构全面分析
I2C 概述 I2C是philips提出的外设总线. I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL ,使用SCL,SDA这两根信号线就实现了设备之间的数据交互,它方便了工程师的布线. ...
- I.MX6 I2C DS1337 disable square-wave output
linux I2C DS1337 disable square-wave output\\\\\\\\\\\-*- 目录 -*-//| 一.DS1337访问寄存器说明: | 二.cat main.c| ...
最新文章
- Android中shape属性详解
- mysql mydumper_mysql数据库备份之mydumper
- UNIX再学习 -- 可重入函数和 SIGCHLD 语义
- tortoisegit图标消失_TortoiseGit文件夹和文件图标不显示解决方法
- win10c语言安装未响应,重新安装win10以后,系统总会死机,不响应任何操作,严重影响正常使用。...
- WGCNA分析,简单全面的最新教程(在线做,但也需要懂原理)
- Ubuntu16.04下实时监控CPU/GPU内存的使用情况
- HTML map 设置图热点
- Python:货币转换(写一个程序进行人民币和美元货币之间的币值转换)
- win10下装黑苹果双系统_Ubuntu 18.04.3+Windows10双系统安装全教程
- [自制]python批量压缩图像
- Excel应用技巧之二——常用函数
- 广告监测系统如何进行广告舆情监测?
- 2016年10月9日 星期日 --出埃及记 Exodus 18:20
- 西南大学计算机考研808真题分享
- Oracle表空间系列
- Oracle VM VirtualBox虚拟MS-DOS时失败,提示内存不能为“written”
- Java、JSP电影订票网站的设计实现
- 解决电脑不能够发现蓝牙键盘,不能够连接蓝牙键盘问题
- Linu进程间通信(一)