文档章节

I2C/SMBUS 实现方法详解

慎思
 慎思
发布于 2014/01/22 17:40
字数 1336
阅读 270
收藏 1
点赞 0
评论 0
Usually, i2c devices are controlled by a kernel driver. But it is also
possible to access all devices on an adapter from userspace, through
the /dev interface. You need to load module i2c-dev for this.

Each registered i2c adapter gets a number, counting from 0. You can
examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
Alternatively, you can run "i2cdetect -l" to obtain a formated list of all
i2c adapters present on your system at a given time. i2cdetect is part of
the i2c-tools package.

I2C device files are character device files with major device number 89
and a minor device number corresponding to the number assigned as 
explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ..., 
i2c-10, ...). All 256 minor device numbers are reserved for i2c.


C example
=========

So let's say you want to access an i2c adapter from a C program. The
first thing to do is "#include <linux/i2c-dev.h>". Please note that
there are two files named "i2c-dev.h" out there, one is distributed
with the Linux kernel and is meant to be included from kernel
driver code, the other one is distributed with i2c-tools and is
meant to be included from user-space programs. You obviously want
the second one here.

Now, you have to decide which adapter you want to access. You should
inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this.
Adapter numbers are assigned somewhat dynamically, so you can not
assume much about them. They can even change from one boot to the next.

Next thing, open the device file, as follows:

  int file;
  int adapter_nr = 2; /* probably dynamically determined */
  char filename[20];
  
  snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
  file = open(filename, O_RDWR);
  if (file < 0) {
    /* ERROR HANDLING; you can check errno to see what went wrong */
    exit(1);
  }

When you have opened the device, you must specify with what device
address you want to communicate:

  int addr = 0x40; /* The I2C address */

  if (ioctl(file, I2C_SLAVE, addr) < 0) {
    /* ERROR HANDLING; you can check errno to see what went wrong */
    exit(1);
  }

Well, you are all set up now. You can now use SMBus commands or plain
I2C to communicate with your device. SMBus commands are preferred if
the device supports them. Both are illustrated below.

  __u8 register = 0x10; /* Device register to access */
  __s32 res;
  char buf[10];

  /* Using SMBus commands */
  res = i2c_smbus_read_word_data(file, register);
  if (res < 0) {
    /* ERROR HANDLING: i2c transaction failed */
  } else {
    /* res contains the read word */
  }

  /* Using I2C Write, equivalent of 
     i2c_smbus_write_word_data(file, register, 0x6543) */
  buf[0] = register;
  buf[1] = 0x43;
  buf[2] = 0x65;
  if (write(file, buf, 3) ! =3) {
    /* ERROR HANDLING: i2c transaction failed */
  }

  /* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
  if (read(file, buf, 1) != 1) {
    /* ERROR HANDLING: i2c transaction failed */
  } else {
    /* buf[0] contains the read byte */
  }

Note that only a subset of the I2C and SMBus protocols can be achieved by
the means of read() and write() calls. In particular, so-called combined
transactions (mixing read and write messages in the same transaction)
aren't supported. For this reason, this interface is almost never used by
user-space programs.

IMPORTANT: because of the use of inline functions, you *have* to use
'-O' or some variation when you compile your program!


Full interface description
==========================

The following IOCTLs are defined:

ioctl(file, I2C_SLAVE, long addr)
  Change slave address. The address is passed in the 7 lower bits of the
  argument (except for 10 bit addresses, passed in the 10 lower bits in this
  case).

ioctl(file, I2C_TENBIT, long select)
  Selects ten bit addresses if select not equals 0, selects normal 7 bit
  addresses if select equals 0. Default 0.  This request is only valid
  if the adapter has I2C_FUNC_10BIT_ADDR.

ioctl(file, I2C_PEC, long select)
  Selects SMBus PEC (packet error checking) generation and verification
  if select not equals 0, disables if select equals 0. Default 0.
  Used only for SMBus transactions.  This request only has an effect if the
  the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
  doesn't have any effect.

ioctl(file, I2C_FUNCS, unsigned long *funcs)
  Gets the adapter functionality and puts it in *funcs.

ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)
  Do combined read/write transaction without stop in between.
  Only valid if the adapter has I2C_FUNC_I2C.  The argument is
  a pointer to a

  struct i2c_rdwr_ioctl_data {
      struct i2c_msg *msgs;  /* ptr to array of simple messages */
      int nmsgs;             /* number of messages to exchange */
  }

  The msgs[] themselves contain further pointers into data buffers.
  The function will write or read data to or from that buffers depending
  on whether the I2C_M_RD flag is set in a particular message or not.
  The slave address and whether to use ten bit address mode has to be
  set in each message, overriding the values set with the above ioctl's.

ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)
  Not meant to be called  directly; instead, use the access functions
  below.

You can do plain i2c transactions by using read(2) and write(2) calls.
You do not need to pass the address byte; instead, set it through
ioctl I2C_SLAVE before you try to access the device.

You can do SMBus level transactions (see documentation file smbus-protocol 
for details) through the following functions:
  __s32 i2c_smbus_write_quick(int file, __u8 value);
  __s32 i2c_smbus_read_byte(int file);
  __s32 i2c_smbus_write_byte(int file, __u8 value);
  __s32 i2c_smbus_read_byte_data(int file, __u8 command);
  __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value);
  __s32 i2c_smbus_read_word_data(int file, __u8 command);
  __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value);
  __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value);
  __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);
  __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, 
                                   __u8 *values);
All these transactions return -1 on failure; you can read errno to see
what happened. The 'write' transactions return 0 on success; the
'read' transactions return the read value, except for read_block, which
returns the number of values read. The block buffers need not be longer
than 32 bytes.

The above functions are all inline functions, that resolve to calls to
the i2c_smbus_access function, that on its turn calls a specific ioctl
with the data in a specific format. Read the source code if you
want to know what happens behind the screens.


Implementation details
======================

For the interested, here's the code flow which happens inside the kernel
when you use the /dev interface to I2C:

1* Your program opens /dev/i2c-N and calls ioctl() on it, as described in
section "C example" above.

2* These open() and ioctl() calls are handled by the i2c-dev kernel
driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(),
respectively. You can think of i2c-dev as a generic I2C chip driver
that can be programmed from user-space.

3* Some ioctl() calls are for administrative tasks and are handled by
i2c-dev directly. Examples include I2C_SLAVE (set the address of the
device you want to access) and I2C_PEC (enable or disable SMBus error
checking on future transactions.)

4* Other ioctl() calls are converted to in-kernel function calls by
i2c-dev. Examples include I2C_FUNCS, which queries the I2C adapter
functionality using i2c.h:i2c_get_functionality(), and I2C_SMBUS, which
performs an SMBus transaction using i2c-core.c:i2c_smbus_xfer().

The i2c-dev driver is responsible for checking all the parameters that
come from user-space for validity. After this point, there is no
difference between these calls that came from user-space through i2c-dev
and calls that would have been performed by kernel I2C chip drivers
directly. This means that I2C bus drivers don't need to implement
anything special to support access from user-space.

5* These i2c-core.c/i2c.h functions are wrappers to the actual
implementation of your I2C bus driver. Each adapter must declare
callback functions implementing these standard calls.
i2c.h:i2c_get_functionality() calls i2c_adapter.algo->functionality(),
while i2c-core.c:i2c_smbus_xfer() calls either
adapter.algo->smbus_xfer() if it is implemented, or if not,
i2c-core.c:i2c_smbus_xfer_emulated() which in turn calls
i2c_adapter.algo->master_xfer().

After your I2C bus driver has processed these requests, execution runs
up the call chain, with almost no processing done, except by i2c-dev to
package the returned data, if any, in suitable format for the ioctl.


本文转载自:

共有 人打赏支持
慎思
粉丝 27
博文 110
码字总数 5948
作品 0
深圳
程序员
linux的i2c体系结构

i2c体系结构分为3个组成部分: (1)i2c核心 (2)i2c总线驱动 (3)i2c设备驱动 i2c核心:提供了i2c总线驱动和设备驱动的注册,注销方法,i2c通信方法的上层的,与具体适配器无关的代码以及...

长平狐 ⋅ 2012/08/28 ⋅ 0

Linux i2c bus 与smbus什么关系

Linux kernel把smbus放到i2c目录下,网上说smbus与i2c bus相似,那他们之间具体什么关系,在写驱动时注意什么?最近在QEMU上要模拟一款x86架构下的i2c设备。 谢谢!...

Honghe ⋅ 2013/08/29 ⋅ 0

树莓派RaspberryPi的RPi.GPIO使用指南

Python操作树莓派GPIO的必要准备 sudo apt-get install python-setuptoolssudo easy_install -U distributesudo apt-get install python-devsudo easy_install RPi.GPIO 树莓派GPIO定义图 PR......

quanpower ⋅ 2013/11/26 ⋅ 0

RHEL7.0启动时end_request I/O error及piix4_smbus错误提示处理

  在VMWARE虚拟机下安装RHEL7.0,启动时有以下提示。经网上搜索,答复为floppy及piix4_smbus设备加载时找不到设备所致。   解决办法如下: floppy,在BIOS里禁用软驱,重启 piix4smbus,...

科技小能手 ⋅ 2017/11/12 ⋅ 0

Linux的i2c驱动详解

1 简介 I2C 总线仅仅使用 SCL 、 SDA 两根信号线就实现了设备之间的数据交互,极大地简化对硬件资源和 PCB 板布线空间的占用。因此, I2C 总线被非常广泛地应用在 EEPROM 、实时钟、小型 LC...

nothingfinal ⋅ 2012/04/18 ⋅ 0

【4412开发板使用经验分享】迅为4412开发板I2C驱动问题

本文转自迅为论坛:bbs.topeetboard.com 我想写DS3231 的驱动 但是读回的数据老是-6 硬件: 我I2C设备连接的这几个GPIO,看了2.5的手册,接口应该是链接正确的 软件 分了两个模块文件 这个是...

歌之王子殿下 ⋅ 2017/03/23 ⋅ 0

树莓派用Python写几个简单程序3_i2c

首先树莓派得安装 python-smbus, i2c-tools, 然后修改文件:sudo nano /etc/modules,添加上 i2c-bcm2708 和i2c-dev 这两行,Raspbian还需要在raspi-config中激活i2c. 用 sudo i2cdetect -y ...

RagingTyphoon ⋅ 2015/08/15 ⋅ 0

Ubuntu下查看CPU温度风扇转速和硬盘温度

夏天到了,这几天本本的温度也飙升起来,在WinXP下玩了会CS,结果CPU一下就到了80度,吓得我赶紧关了。 下午Win7 64位旗舰版也下载完了,准备体验一下,就装个系统,网页都不浏览的情况下CPU...

鉴客 ⋅ 2010/09/13 ⋅ 5

Linux I2C核心、总线与设备驱动

本章导读 I2C总线仅仅使用SCL、SDA两根信号线就实现了设备之间的数据交互,极大地简化对硬件资源和PCB板布线空间的占用。因此,I2C总线被非常广泛地应用在EEPROM、实时钟、小型LCD等设备与C...

我爱咸蛋黄 ⋅ 2013/04/22 ⋅ 0

用软件lm_sensors监测Linux系统和CPU温度(转)

用软件lm_sensors监测Linux系统和CPU温度 详细出处参考:http://www.jb51.net/os/RedHat/1158.html lmsensors的软件可以帮助我们来监控主板,CPU的工作电压,风扇转速、温度等数据。这些数据...

jccpp ⋅ 2013/06/18 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

中标麒麟(龙芯版)7.0优盘安装

########################################## 制作U盘安装盘: 1.准备U盘: PMON环境下U盘必须格式化成ext3; 昆仑固件环境下可以格式化成ext3,ext4 2.把整个镜像 xxx.iso 复制到U盘下面 3....

gugudu ⋅ 23分钟前 ⋅ 0

老司机写的大数据建模五步走

本文将尝试来梳理一下数据建模的步骤,以及每一步需要做的工作。 01 第一步:选择模型或自定义模式 这是建模的第一步,我们需要基于业务问题,来决定可以选择哪些可用的模型。 比如,如果要预...

gulf ⋅ 32分钟前 ⋅ 0

PacificA 一致性协议解读

PacificA 的 paper 在 08 年左右发出来的,比 Raft 早了 6,7 年。 在 PacificA 论文中,他们强调该算法使用范围是 LAN (Local Area Network),讲白了就是对跨机房不友好。 不管是 ZAB,Raf...

黑客画家 ⋅ 34分钟前 ⋅ 0

盘符图标个性化

设置自己的专属盘符图标 准备ico格式的图片文件一个,在根目录下创建autorun.inf文件 文件内容 [Autorun]icon=logo.ico 重新启动或者插拔U盘即可看到结果...

阿豪boy ⋅ 34分钟前 ⋅ 0

Windows下QQ聊天记录中图片的默认存放位置

Windows下QQ聊天记录中图片的默认存放位置在设置中是没有说明的。 实测位置在:D:\Documents\Tencent Files\974101467\Image 其中: “974101467”为对应的QQ号; “C2C”为个人之间的聊天图...

临江仙卜算子 ⋅ 41分钟前 ⋅ 0

GC 的三种基本实现方式

参考资料《代码的未来》(作者: [日] 松本行弘)。 由于并非本人原著(我只是个“搬运工“),SO 未经本人允许请尽情转载。 另外个人像说明一下这里所说的GC指泛指垃圾回收机制,而单指Jav...

xixingzhe ⋅ 42分钟前 ⋅ 0

Android双击退出

/** * 菜单、返回键响应 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // TODO Auto-generated method stub if(keyCode......

王先森oO ⋅ 46分钟前 ⋅ 0

idea 整合 vue 启动

刚学习Vue 搭建了一个项目 只能命令启动 Idea里面不会启动 尝试了一下修改启动的配置 如下: 1.首先你要保证你的package.json没有修改过 具体原因没有看 因为我改了这个name的值 就没办法启动...

事儿爹 ⋅ 51分钟前 ⋅ 0

redis在windows环境的后台运行方法

在后台运行,首先需要安装redis服务,命令为 redis-server.exe --service-install redis.windows.conf --loglevel verbose 启动,命令为 redis-server --service-start 停止,命令为 redis-...

程序羊 ⋅ 54分钟前 ⋅ 0

比特币现金开发者提出新的交易订单规则

本周,四位比特币现金的四位开发者和研究员:Joannes Vermorel(Lokad),AmaurySéchet(比特币ABC),Shammah Chancellor(比特币ABC)和Tomas van der Wansem(Bitcrust)共同发表了一篇关...

lpy411 ⋅ 58分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部