一、 I2C简单介绍

I2C(Inter-Integrated Circuit)总线是一种由 Philips 公司开发的两线式串行总线,用于连接微控制器及其外围设备。I2C 总线最基本的长处就是简单性和有效性,简单体如今接线简单,仅仅有两根线数据线(SCL)和时钟线(SDA),并且 控制简单。所以一些封装较小的器件多使用I2C总线,常见的使用I2C总线的设备有EEPROM、RTC及一些传感器。这里我们介绍下基于linux的I2C设备驱动的编写。

  • I2C设备驱动的编写有多种方式

一种是直接操作CPU的I2C控制器,正对于某一个设备写一个字符驱动,这样的驱动相对来说比較直接,不须要太依赖于内核相关配置,可是这类设备驱动依赖CPU,可移植性较差。

一种是基于linux内核I2C子系统完毕设备驱动的编写,一般内核会继承相关CPU的控制器驱动即使没有也能够通过技术支持能够获得,所以我们仅仅须要使用linux下I2C子系统提供的相关接口来构建我们的设备驱动即可了。这样我们的设备驱动并不依赖于某一个特定的CPU,可移植性较好。


IIC驱动主要分为Master和Slave,Master就是主机控制器,像A10内部的IIC控制器就是一个Master, Slave就是IIC从机设备,它要被挂接到Master上才干工作

智能手机和平板电脑上用的sensor差点儿都是IIC设备,最经常使用的IIC设备就是电容触摸屏和摄像头,接下来,我们将针对触摸屏、EEPROM、摄像头等驱动来分析。


  • I2C总线工作原理

I2C 总线是由数据线 SDA 和时钟 SCL 构成的串行总线,各种被控制器件均

并联在这条总线上,每一个器件都有一个唯一的地址识别,能够作为总线上的一个

发送器件或接收器件(详细由器件的功能决定)。I2C 总线的接口电路结构如图 1所看到的




  • I2C 总线的几种信号状态

1. 空暇状态:SDA 和 SCL 都为高电平。

2. 開始条件(S):SCL 为高电平时,SDA 由高电平向低电平跳变,開始传送数据。

3. 结束条件(P):SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。

4. 数据有效:在 SCL 的高电平期间,SDA 保持稳定,数据有效。SDA 的改变仅仅能发生在 SCL 的低电平期间。

5. ACK 信号:传输数据的过程中,接收器件每接收一个字节数据要产生一个 ACK 信号,向发送器件发出特定的低电平脉冲,表示已经收到数据。


  • I2C 总线基本操作

I2C 总线必须由主器件(通常为微控制器)控制,主器件产生串行时钟(SCL),同一时候控制总线的传输方向,并产生開始和停止条件。

传输数据中,首先由主器件产生開始条件,随后是器件的控制字节(前七位是从器件的地址,最后一位为读写位)。接下来是读写操作的数据,以及 ACK响应信号。传输数据结束时,主器件产生停止条件。详细的过程如图 2 所看到的。





二、Linux 系统 I2C 驱动程序

  • I2C驱动层次结构

Linux 系统对 I2C 设备具有非常好的支持,Linux 系统下的 I2C 驱动程序从逻 辑上能够分为 3 个部分: 
1. I2C 核心(I2C core):实现对 I2C 总线、I2C adapter 及 I2C driver 的管理。 
2. I2C 控制器驱动 I2C adapter :针对不同类型的 I2C 控制器 ,实现对 I2C 总线訪问的详细方法。 
3. I2C 设备驱动 I2C driver:针对特定的 I2C 设备,实现详细的功能,包含read,write 以及 ioctl 等对用户层操作的接口。 

这三个部分的层次关系如图 3 和图 4 所看到的。









  • I2C 核心(I2C core)

I2C core 是 Linux 内核用来维护和管理 I2C 的核心部分,当中维护了两个静 态的 List,分别记录系统中的 I2C driver 结构和 I2C adapter 结构。I2C core 提供 接口函数,同意一个 I2C adapter,I2C driver 和 I2C client 初始化时在I2C core 中 进行注冊,以及退出时进行注销。同一时候还提供了 I2C 总线读写訪问的一般接口(具 体的实如今与 I2C 控制器相关的
I2C adapter 中实现),主要应用在 I2C 设备驱动中。

  • I2C 控制器驱动(I2C adapter)

I2C adapter 是针对不同类型 I2C 控制器硬件,实现比較底层的对 I2C 总线訪 问的详细方法。I2C adapter 构造一个对 I2C core 层接口的数据结构,并通过接口函数向 I2C core 注冊一个控制器。 
I2C adapter 主要实现对 I2C 总线訪问的算法,master_xfer()函数就是 I2C adapter 底层对 I2C 总线读写方法的实现。同一时候 I2C adapter 中还实现了对 I2C 控制器中断的处理函数。


  • I2C 设备驱动(I2C driver)

I2C driver 是对 I2C 从设备的软件实现。I2C driver 中提供了一个通用的 I2C 设备的驱动程序,实现了字符类型设备的訪问接口,对设备的详细訪问是通过 I2C adapter 来实现的。I2C driver 构造一个对 I2C core 层接口的数据结构,通过 接口函数向 I2C Core 注冊一个 I2C 设备驱动。同一时候 I2C driver 构造一个对用户层接口的数据结构,并通过接口函数向内核注冊为一个主设备号为
89 的字符类型设备。I2C driver 实现用户层对 I2C 设备的訪问,包含 open,read,write,ioctl,release 等常规文件操作,能够通过 open 函数打开 I2C 设备文件,通过 ioctl 函数设定要訪问 I2C 设备的地址,然后就能够通过 read 和 write 函数完毕对 I2C 设备的读写操作。通过 I2C driver 提供的通用方法能够訪问不论什么一个 I2C 的设备,可是当中实 现的 read,write 及 ioctl 等功能全然是基于一般设备的实现,全部的操作数据都是基于字节流,没有明白的格式和意义。为了更方便和有效地使用
I2C 设备,可 以为一个详细的 I2C 设备开发特定的 I2C 设备驱动程序,在驱动中完毕对特定的数据格式的解释以及实现一些专用的功能。


三、 基于 SUNXI 平台的 I2C 控制器驱动

位于drivers/i2c/busses文件夹下的文件i2c-sunxi.c,是基于sunxi平台实现的I2C 总线控制器驱动。它的职责是为系统中 3 条 I2C 总线实现对应的读写方法,可是控制器驱动本身并不会进行不论什么的通讯,而是等待设备驱动调用其函数。 
图 5 是基于 SUNXI 平台的 I2C 驱动层次架构图,图中有 3 块 I2C adapter,分别相应 SUNXI 平台上的 3 块 I2C 控制器


系统开机时,I2C 控制器驱动首先被装载,I2C 控制器驱动用于支持 I2C 总 线 的读 写。i2c_sunxi_algorithm 结构体中定 义了 I2C 总线通信方 法函数i2c_sunxi_xfer(),该函数实现了对 I2C 总线訪问的详细方法,设备驱动通过调用 
这个函数,实现对 I2C 总线的訪问;而在函数 i2c_sunxi_probe()中完毕了对 I2C adapter 的初始化。


  • I2C 驱动源代码结构

在 drivers/i2c/文件夹下,包括有几个关键文件和文件夹,例如以下:
1. 文件 i2c-core.c:I2C 子系统核心功能的实现; 
2. 文件 i2c-dev.c:通用的从设备驱动实现; 
3. 文件夹 busses:里面包含基于不同平台实现的 I2C 总线控制器驱动; 
4. 文件夹 algos:里面实现了一些 I2C 总线控制器的 algorithm。

四、I2C 设备驱动程序的开发

  • I2C 设备驱动一般结构

一个详细的 I2C 设备驱动须要实现两个方面的接口,一方面是对 I2C core 层的接口,用以挂接 I2C adapter 来实现对 I2C 总线及 I2C 设备详细的訪问方法, 包含要实现 probe,remove,detect 等接口函数;还有一方面是对用户应用层的接 口,提供用户程序訪问 I2C 设备的接口,包含实现 open,release,read,write 以及最重要的 ioctl 等标准文件操作的接口函数。 
对 I2C core 层的接口函数的详细功能解释例如以下:

probe:I2C driver 进行设备绑定的回调函数。
remove:I2C driver 解除设备绑定的回调函数。
detect:I2C 设备探測回调函数,它会识别所支持的设备(返回 0 表示支持, 否则返回-ENODEV);此外,须要定义一个供探測的地址列表(address_list)和 一个设备类型(class),这样使那些仅匹配设备类型的 i2c 总线被探測到。比如, 对 于 一 个 自 动 监 測 硬 件 芯 片 的 驱 动 将 会 设 置 它 的 class 域 为 I2C_CLASS_HWMON,仅仅有那些 class 域为 I2C_CLASS_HWMON
的控制器能 够被驱动探測。

  • 经常使用数据结构解析

 i2c_adapter 

struct i2c_adapter {
struct module *owner; /* 所属模块 */ 
unsigned int id; /* algorithm 的类型,定义于 i2c-id.h,以 I2C_ALGO_開始 */ 
unsigned int class;
const struct i2c_algorithm *algo; /* 总线通信方法结构体指针 */
void *algo_data;  /* algorithm 数据 */ 
struct rt_mutex bus_lock;
int timeout;  /* 超时时间,以 jiffies 为单位 */ 
int retries;  /* 重试次数 */ 
struct device dev;  /* 控制器设备 */ 
int nr;
char name[48]; /* 控制器名称 */ 
struct completion dev_released; /* 用于同步 */ 
struct mutex userspace_clients_lock;
struct list_head userspace_clients;
};

i2c_adapter 相应于物理上的一个控制器。一个 I2C 控制器须要 i2c_algorithm 中提供的通信函数来控制控制器上产生特定的訪问周期。 


i2c_algorithm 

struct i2c_algorithm {
/* I2C 传输函数指针 */
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
/* smbus 传输函数指针 */
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write,  u8 command, int size, union i2c_smbus_data *data); 
/* 返回控制器支持的功能 */
u32 (*functionality) (struct i2c_adapter *);
};
i2c_algorithm中的关键函数master_xfer()用于产生I2C訪问周期须要的信号, 以 i2c_msg(即 I2C 消息)为单位。 


i2c_msg 

struct i2c_msg {
__u16 addr; /* 从设备地址 */ 
__u16 flags; /* 消息类型 */ 
__u16 len; /* 消息长度 */ 
__u8 *buf; /* 消息数据 */ 
};

i2c_msg 是 I2C 传输的基本单位,它包括了从设备的详细地址,消息的类型 以及要传输的详细数据信息。每一个 I2C 消息传输前,都会产生一个開始位,紧接 着传送从设备地址,然后開始数据的发送或接收,对最后的消息还需产生一个停止位。 

 i2c_client 

struct i2c_client {
unsigned short flags; /* 标志 */ 
unsigned short addr; /* 低 7 位的芯片地址 */ 
char name[I2C_NAME_SIZE];  /* 设备名称 */ 
struct i2c_adapter *adapter; /* 依附的 i2c_adapter */ 
struct i2c_driver *driver; /* 依附的 i2c_driver */ 
struct device dev;  
int irq;  /* 设备使用的中断号 */ 
struct list_head detected;
};

i2c_client 相应于真实的物理设备,每一个 I2C 设备都须要一个 i2c_client 来描
述。

 i2c_driver 

struct i2c_driver {
unsigned int class;
int (*attach_adapter)(struct i2c_adapter *); /* 依附 i2c_adapter 函数指针 */ 
int (*detach_adapter)(struct i2c_adapter *); /* 脱离 i2c_adapter 函数指针 */ 
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
void (*alert)(struct i2c_client *, unsigned int data);
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
struct device_driver driver;
const struct i2c_device_id *id_table;  /* 该驱动所支持的设备 ID 表 */ 
int (*detect)(struct i2c_client *, struct i2c_board_info *); /* 设备探測函数 */ 
const unsigned short *address_list; /* 驱动支持的设备地址 */ 
struct list_head clients; /* 挂接探測到的支持的设备 */ 
};

i2c_driver 相应一套驱动方法,其主要成员函数是 probe()、remove()、 suspend()、resume()等,另外id_table是该驱动所支持的I2C设备的ID表。i2c_driver 与 i2c_client
的关系是一对多,一个 i2c_driver 上能够支持多个同等类型的 i2c_client。


Android 驱动(二) IIC简单介绍的更多相关文章

  1. NDK中android.mk文件的简单介绍和第三方库的调用

    先贴一个样例,然后解释一下: LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := mydjvuapi SRC_FILE_ ...

  2. Android 懒加载简单介绍

    1.懒加载介绍 1.1.效果预览 1.2.效果讲解 当页面可见的时候,才加载当前页面. 没有打开的页面,就不会预加载. 说白了,懒加载就是可见的时候才去请求数据. 1.3.懒加载文章传送门 参考文章: ...

  3. 深入浅出JMS(二)--ActiveMQ简单介绍以及安装

    现实的企业中,对于消息通信的应用一直都非常的火热,而且在J2EE的企业应用中扮演着特殊的角色,所以对于它研究是非常有必要的. 上篇博文深入浅出JMS(一)–JMS基本概念,我们介绍了消息通信的规范JM ...

  4. Android Studio使用心得 - 简单介绍与环境配置

    FBI Warning:欢迎转载,但请标明出处:http://blog.csdn.net/codezjx/article/details/38544823,未经本人允许请勿用于商业用途.感谢支持! 关 ...

  5. 开源项目Universal Image Loader for Android 说明文档 (1) 简单介绍

     When developing applications for Android, one often facesthe problem of displaying some graphical ...

  6. Android中Fragment的简单介绍

    Android是在Android 3.0 (API level 11)引入了Fragment的,中文翻译是片段或者成为碎片(个人理解),可以把Fragment当成Activity中的模块,这个模块有自 ...

  7. Android驱动调试利器Busybox之初体验

    工欲善其事必先利其器,之前做WinCE开发时,经常写一些小工具以提高开发调试的效率,如WinCE驱动调试助手.WinCE串口调试助手.WinCE6.0寄存器访问工具.WinCE远程桌面助手和S3C24 ...

  8. salesforce lightning零基础学习(一) lightning简单介绍以及org开启lightning

    lightning对于开发salesforce人员来说并不陌生,即使没有做过lightning开发,这个名字肯定也是耳熟能详.原来的博客基本都是基于classic基于配置以及开发,后期博客会以ligh ...

  9. Android项目开发全程(二)--Afinal用法简单介绍

    本篇博文接上篇的<Android项目开发全程(一)--创建工程>,主要介绍一下在本项目中用到的一个很重要的框架-Afinal,由于本系列博文重点是项目开发全程,所以在这里就先介绍一下本项目 ...

随机推荐

  1. VC++共享数据段实现进程之间共享数据

    当我写了一个程序,我希望当这个程序同时运行两遍的时候,两个进程之间能共享一些全局变量,怎么办呢?很简单,使用VC\VC++的共享数据段.; #pragma data_seg()//恢复到正常段继续编程 ...

  2. 基于visual Studio2013解决算法导论之042单源最短路径

     题目 单源最短路径 解决代码及点评 // 26单源最短路径bellmanford.cpp : 定义控制台应用程序的入口点. // #include <iostream> #incl ...

  3. 微信平台接入Web页面功能接口(C#)

    微信平台接入web页面功能接口 今年因工作需要,通过微信平台接入公司的Wap页面,回忆下,记录内容,方面以后使用. 1.成为开发者后,你才可以使用公众平台的开发功能.需要填写URL和ToKen,接口配 ...

  4. JavaScript 中的日期和时间

    前言 本篇的介绍涵盖以下部分: 1. 时间标准指的是什么?UCT和GMT 的概念.关联和区别? 2. 时间表示标准有哪些? 3. JS 中时间的处理 日期时间标准 日期的标准就不多说了 -- 公元纪年 ...

  5. JAVA操作Hbase基础例子

    package com.cma.hbase.test; import java.io.BufferedInputStream; import java.io.BufferedReader; impor ...

  6. android JB2连拍降速原理介绍

    1.HAL层 (1)alps\mediatek\platform\mt6589\hardware\camera\core\camshot\MultiShot\MultiShot.cpp sleep实现 ...

  7. 你知道hover、active这四个伪类为什么要按顺序写吗

    刨根问底,你知道:hover等4个伪类为什么要按顺序排列吗 引言 :link,:visited,:hover,:active这4个伪类大家都不陌生,4个伪类要按照LvHa这个爱恨原则来排(外国友人起的 ...

  8. Visual Studio 2012的新技术特性

    前言 我更换了VS2012开发工具,那么它有什么特性呢? [caption id="attachment_1235" align="alignnone" wid ...

  9. 使用jQuery的attr方法来修改onclick值

    这篇文章主要介绍了通过jQuery的attr修改onclick值的解决方法 ,需要的朋友可以参考下 var js = "alert('B:' + this.id); return false ...

  10. Android 去掉Activity的跳转动画

    startActivity或finish的时候调用一句话即可: overridePendingTransition(0, 0);