I2C总结

               

让大家最快的了解I2C通信、I2C驱动和I2C读写,如有错误,还请指正。  

        百度网盘下载地址  http://pan.baidu.com/s/1kT7GBDd

DOC文档中有图片,博文的图片就不传了。

一 I2C 概述

   I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,是微电子通信控制领域广泛采用的一种总线标准,串行的8 位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s。具有接口线少,控制方式简单,广泛的应用在各种电路中。比如对E2PROM(AT2402 芯片)的读写,公司使用的是ARM+FPGA的结构使用的是I2C通信,所以I2C起到了很重要的作用。

 

二 I2C 总线协议简述

I2C总线只有两根线,SCK(时钟) SDA(数据),I2C 是基于multi master机制,一条总线上可允许多个master。

图 I2C开始停止时序

   I2C 总线数据的读写如图

图 I2C读写分析

 I2C在读的时候先是一个START信号 再传输7位设备地址(E2PROM的设备地址 原理图上有) 先传输的是最高位最后是最低位,第8位是R/W位,0表示写,1表示读。第9位是ACK应答位,在数据成功的读写后,ACK会置高表示成功。传输完7位设备地址后接着同样传输寄存器地址(E2PROM的寄存器地址)可能是 1 byte ,2 byte 等,再是写入的 N byte数据 ,最后发送STOP信号结束通信。要强调的是 一般先写入设备地址,再写入寄存器地址,再写入数据。有少数的是 寄存器地址和数据在一块,只需要写入设备地址和数据。还要说明的是 这里使用是 7位的寻址,还有10位的寻址,10位的寻址是兼容7位的。

好了,原理性的东西有这些就够了。

三 I2C linux驱动分析

我们从最上层开始,抓住I2C读写的主线进行分析,让过程简单易懂。

 

 

 

 

 

 

 

 

图 I2C读写调用过程

首先在用户模式下打开一个I2C设备获得文件句柄,然后使用read write进行读写,在驱动中(drivers/i2c/i2c_dev.c)I2C驱动中file_operations结构体指向了i2cdev_read和i2cdev_write, 同时在 drivers/i2c/i2c_dev.c文件中有

static int __init i2c_dev_init(void);

static void __exit i2c_dev_exit(void);

驱动程序加载卸载函数,在 i2c_dev_init中 使用register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops); 注册了主设备号位89的设备。

在 i2c_dev_exit 函数中使用了 unregister_chrdev对设备卸载(这些是不是很熟悉)。

我们继续看 i2c_dev_read函数,在函数中调用了i2c_master_recv ,同样 i2c_dev_write函数调用的是 i2c_master_send, i2c_dev_write和 i2c_master_send位于 drivers/i2c/i2c-core.c.

在 i2c_dev_write和 i2c_master_send函数中都会使用 i2c_transfer完成数据传输,i2c_transfer 函数用于进行I2C适配器和I2C设备之间的一组消息交互,i2c_master_send函数和i2c_master_recv 函数会调用i2c_transfer()函数分别完成一条写消息和一条读消息。在 i2c_tansfer函数中有struct i2c_adapter *adap 结构体,adap->algo->master_xfer 指向不同平台的I2C实现函数,我们这里用是的 IT AM335X系列,最后就是调用的 位于 /drivers/i2c/bussess/i2c-omap.c 文件中的omap_i2c_xfer函数,不同的平台最后调用的函数不一样。在 omap_i2c_xfer函数中调用omap_i2c_xfer_msg完成底层的操作。

上面从函数调用的过程分析了I2C的读写,下面我们从层次上分析I2C驱动。

 

Linux的I2C构架分为三个部分:

1)I2C core框架

提供了核心数据结构的定义和相关接口函数,用来实现I2C适配器驱动和设备驱动的注册、注销管理,以及I2C通信方法上层的、与具体适配器无关的代码,为系统中每个I2C总线增加相应的读写方法。I2C core框架具体实现在/drivers/i2c目录下的i2c-core.c和i2c-dev.c

 2) I2C总线驱动

 定义描述具体I2C总线适配器的i2c_adapter数据结构、实现在具体I2C适配器上的I2C总线通信方法,并由i2c_algorithm数据结构进行描述。 经过I2C总线驱动的的代码,可以为我们控制I2C产生开始位、停止位、读写周期以及从设备的读写、产生ACK等。

 

I2C总线驱动具体实现在/drivers/i2c目录下busses文件夹。例如:Linux I2C GPIO总线驱动为i2c_gpio.c. I2C总线算法在/drivers/i2c目录下algos文件夹。例如:Linux I2C GPIO总线驱动算法实现在i2c_algo_bit.c.

 3) I2C 设备驱动

 是对具体I2C硬件驱动的实现。I2C 设备驱动通过I2C适配器与CPU通信。其中主要包含i2c_driver和i2c_client数据结构,i2c_driver结构对应一套具体的驱动方法,例如:probe、remove、suspend等,需要自己申明。i2c_client数据结构由内核根据具体的设备注册信息自动生成,设备驱动根据硬件具体情况填充。具体使用下面介绍。

  I2C 设备驱动具体实现放在在/drivers/i2c目录下chips文件夹。

 

 

最后用上图表示所有的层次关系。

好了,驱动大致知道这么多久可以了。有关I2C驱动的更详细的介绍

http://www.360doc.com/content/13/0715/21/9171956_300228309.shtml

 

四 I2C 读写

有了I2C的驱动,我们对I2C的读写使用open read write ioctl close就可以了。

需要包含的头文件

#include <linux/i2c-dev.h>

#include <linux/i2c.h>

 

//打开I2C设备

int fd_i2c_dev = open("/dev/i2c-2",O_RDWR);

//I2C初始化

//使用7位地址

ioctl(fd_dev,I2C_TENBIT,0);

//失败重复次数 2 次

ioctl(fd_dev,I2C_RETRIES,2);

//超时50 ms

ioctl(fd_dev,I2C_TIMEOUT,50);

 

封装i2c_read和i2c_write读写函数

/*

*>

struct i2c_msg  i2c_msg[2];

        struct i2c_rdwr_ioctl_data  ioctl_data;

        ioctl_data.msgs = i2c_msg;

        ioctl_data.nmsgs = 2;

 

//write 8-bit register address

tmpbuf = register_addr;

i2c_msg[0].addr  = i2c_devaddr;

        i2c_msg[0].flags = 0;

        i2c_msg[0].buf   = &tmpbuf;

        i2c_msg[0].len   = 1;

        

//read date from i2c store in tmpbuf

        i2c_msg[1].addr  = i2c_devaddr;

        i2c_msg[1].flags = 1;

        i2c_msg[1].buf   = buf;

        i2c_msg[1].len   = count;

int rt_val = 0;

 

        rt_val = ioctl(fd_i2c,0x707,&ioctl_data);

if ( rt_val < 0 ){

printf(" read i2c error in i2c_read_A8 function \n");

}

return rt_val;

}

 

/*

*>

static unsigned char tmpbuf[1024] = { '\0' };

tmpbuf[0] = register_addr;

if ( count >= 1024 ){

return -1;

}

memcpy(tmpbuf+1,buf,count);

rt_val = ioctl(fd_i2c,I2C_SLAVE,i2c_devaddr);

if ( rt_val < 0 ){

printf(" ioctl i2c in ioctl function  m_i2c.c\n");

}

        rt_val = write(fd_i2c,tmpbuf,count+1);

if ( rt_val < 0 ){

printf(" write i2c error in i2c_write_A8 function m_i2c.c \n");

}

return rt_val;

}

 

好了直接调用 i2c_read_A8就可以进行I2C读操作了

eg:

//从设备地址0x10 寄存器地址0x1 读1个字节

char tmp_buf;

i2c_write_A(0x10,0x1,1,&tmp_buf,1);



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值