文章目录

  • 一. 对 i2c_msg 的理解我认为应该分为两个主要层面:
  • 二. 常见的Slave 驱动程序对 i2c read和write函数实现方式如下:

背景介绍:
这两天在解决客户的一个i2c传输问题时发现对i2c的理解有很多盲点,冒出一身冷汗- -!,问题解决后赶紧复盘总结一下。

带着问题去学习是最快的方法
思考题

  1. 为什么常见的i2c外设驱动中 i2c read 函数要构造 2个 i2c_msg,而 i2c write 函数只要1个i2c_msg?
  2. 常见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函数实现方式如下:

  1. 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;
}
  1. 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相关推荐

  1. linux i2c核心,总线与设备驱动,Linux2.6.37 I2C驱动框架分析(一)

    最近工作中又使用到了I2C,所以借S3C2440开发板GT2440为硬件平台温习一遍I2C驱动体系. linux内核中IIC驱动的体系框架 linux内核中IIC部分驱动代码位于:/drivers/i ...

  2. 设备树与驱动的关系_Linux I2C驱动竟然如此简单?手把手教你写i2c驱动

    Linux中I2C驱动框架分析 I2C核心(i2c_core) I2C核心维护了i2c_bus结构体,提供了I2C总线驱动和设备驱动的注册.注销方法,维护了I2C总线的驱动.设备链表,实现了设备.驱动 ...

  3. linux下i2c设备驱动程序,Linux I2C 设备驱动

    I2C 设备驱动要使用 i2c_driver 和 i2c_client 数据结构并填充其中的成员函数.i2c_client 一般被包含在设备的私有信息结构体yyy_data 中,而 i2c_drive ...

  4. linux 脚本给设备节点权限,[Linux] I2C设备读写及文件节点创建

    Linux Kernel Version:3.0.35 Platform:Freescale DSA2L 通过I2C读取VGA屏的EDID信息(主要是分辨率),解析后喂给CH7036芯片(LVDS转V ...

  5. 实例解析linux内核I2C体系结构

    实例解析linux内核I2C体系结构 一.概述 谈到在linux系统下编写I2C驱动,目前主要有两种方式,一种是把I2C设备当作一个普通的字符设备来处理,另一种是利用linux I2C驱动体系结构来完 ...

  6. 在Android源码树中添加userspace I2C读写工具(i2c-util)

    by LiAnLab.org / 宋宝华 通过/dev/i2c-n节点,用户可以在userspace直接访问板上的i2c外设寄存器,主要是透过I2C_RDWR这个IO控制命令将i2c_msg数组传递给 ...

  7. linux驱动之i2c学习

    最近在研究linux的i2c驱动,从最底层i2c控制器初始化到应用层与i2c设备交互基本打通了. 一.linux的i2c架构可以用下图表示: IIC适配器对应一条i2c总线,linux里面用i2c_a ...

  8. linux在内核下使用iic,实例解析linux内核I2C体系结构(2)

    四.在内核里写i2c设备驱动的两种方式 在 (1) Adapter方式(LEGACY) (下面的实例代码是在2.6.27内核的pca953x.c基础上修改的,原始代码采用的是本文将要讨论的第2种方式, ...

  9. 【驱动】linux下I2C驱动架构全面分析

    I2C 概述 I2C是philips提出的外设总线. I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL ,使用SCL,SDA这两根信号线就实现了设备之间的数据交互,它方便了工程师的布线. ...

  10. I.MX6 I2C DS1337 disable square-wave output

    linux I2C DS1337 disable square-wave output\\\\\\\\\\\-*- 目录 -*-//| 一.DS1337访问寄存器说明: | 二.cat main.c| ...

最新文章

  1. Android中shape属性详解
  2. mysql mydumper_mysql数据库备份之mydumper
  3. UNIX再学习 -- 可重入函数和 SIGCHLD 语义
  4. tortoisegit图标消失_TortoiseGit文件夹和文件图标不显示解决方法
  5. win10c语言安装未响应,重新安装win10以后,系统总会死机,不响应任何操作,严重影响正常使用。...
  6. WGCNA分析,简单全面的最新教程(在线做,但也需要懂原理)
  7. Ubuntu16.04下实时监控CPU/GPU内存的使用情况
  8. HTML map 设置图热点
  9. Python:货币转换(写一个程序进行人民币和美元货币之间的币值转换)
  10. win10下装黑苹果双系统_Ubuntu 18.04.3+Windows10双系统安装全教程
  11. [自制]python批量压缩图像
  12. Excel应用技巧之二——常用函数
  13. 广告监测系统如何进行广告舆情监测?
  14. 2016年10月9日 星期日 --出埃及记 Exodus 18:20
  15. 西南大学计算机考研808真题分享
  16. Oracle表空间系列
  17. Oracle VM VirtualBox虚拟MS-DOS时失败,提示内存不能为“written”
  18. Java、JSP电影订票网站的设计实现
  19. 解决电脑不能够发现蓝牙键盘,不能够连接蓝牙键盘问题
  20. Linu进程间通信(一)

热门文章

  1. 算法学习笔记:排序算法
  2. 白蛋白纳米-超声微泡载组织型纤溶酶原激活物基因靶向制备研究
  3. stm32L151低功耗学习——Alarm闹钟周期唤醒(10s/10min/10h)
  4. Python贪吃蛇双人大战
  5. 怎样设置默认浏览器,绝对干货!
  6. e^(At)求解方法及其含义–线性微分方程的求解
  7. 利用云服务器搭建解锁网易云变灰歌曲的代理
  8. 关于 傅里叶变换 的一些理解(通俗版)
  9. Python基于django的图书商城管理系统毕业设计源码110938
  10. 2.Raspberrypi 3:树莓派开发板入门