Chinaunix首页 | 论坛 | 博客
  • 博客访问: 561224
  • 博文数量: 105
  • 博客积分: 3274
  • 博客等级: 中校
  • 技术积分: 1161
  • 用 户 组: 普通用户
  • 注册时间: 2010-02-21 12:14
文章分类

全部博文(105)

文章存档

2011年(1)

2010年(104)

分类: LINUX

2010-07-14 19:58:44

I2c协议介绍

Key to symbols

==============

S     (1 bit) : Start bit 开始位

P     (1 bit) : Stop bit  结束位

Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.

A, NA (1 bit) : Accept and reverse accept bit.应答位和不应答位

Addr  (7 bits): I2C 7 bit address. Note that this can be expanded as usual to

                get a 10 bit I2C address.

Comm  (8 bits): Command byte, a data byte which often selects a register on

                the device.

Data  (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh

                for 16 bit data.

Count (8 bits): A data byte containing the length of a block operation.

[..]: Data sent by I2C device, as opposed to data sent by the host adapter.

 

Simple send transaction  简单发送传输

======================

This corresponds to i2c_master_send.

  S Addr Wr [A] Data [A] Data [A] ... [A] Data [A] P

 

Simple receive transaction简单接收传输

===========================

This corresponds to i2c_master_recv

  S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P

 

Combined transactions 复合传输

====================

This corresponds to i2c_transfer.

They are just like the above transactions, but instead of a stop bit Pa start bit S is sent and the transaction continues. An example of a byte read, followed by a byte write:

  S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P

 

Modified transactions

=====================

We have found some I2C devices that needs the following modifications:

  Flag I2C_M_NOSTART:

    In a combined transaction, no 'S Addr Wr/Rd [A]' is generated at some    point. For example, setting I2C_M_NOSTART on the second partial message generates something like:

      S Addr Rd [A] [Data] NA Data [A] P

    If you set the I2C_M_NOSTART variable for the first partial message, we do not generate Addr, but we do generate the startbit S. This will probably confuse all other clients on your bus, so don't try this.

  Flags I2C_M_REV_DIR_ADDR

    This toggles the Rd/Wr flag. That is, if you want to do a write, but Normally message is interrupted immediately if there is [NA] from the client. Setting this flag treats any [NA] as [A], and all of message is sent.

These messages may still fail to SCL lo->hi timeout.

 

  Flags I2C_M_NO_RD_ACK

In a read message, master A/NA bit is skipped.

 

Terminology 术语

===========

When we talk about I2C, we use the following terms:

  Bus    -> Algorithm

            Adapter

  Device -> Driver

            Client

An Algorithm driver contains general code that can be used for a whole class of I2C adapters. Each specific adapter driver either depends on one algorithm driver, or includes its own implementation.

A Driver driver (yes, this sounds ridiculous, sorry) contains the general code to access some type of device. Each detected device gets its own data in the Client structure. Usually, Driver and Client are more closely integrated than Algorithm and Adapter.

For a given configuration, you will need a driver for your I2C bus, and drivers for your I2C devices (usually one driver for each device).

At this time, Linux only operates I2C (or SMBus) in master mode; you can't use these APIs to make a Linux system behave as a slave/device, either to speak a custom protocol or to emulate some other device.

 

   I2c-dev.c文件完全可以被看作一个i2c设备驱动,它可以被用于用户空间访问adapter.它实现的一个i2c_client是虚拟、临时的,随着设备文件的打开而产生,并随设备文件的关闭而撤销。

   I2c-dev.c提供以下几个函数,如下

static const struct file_operations i2cdev_fops = {

       .owner           = THIS_MODULE,

       .llseek            = no_llseek,

       .read              = i2cdev_read,

       .write             = i2cdev_write,

       .unlocked_ioctl      = i2cdev_ioctl,

       .open             = i2cdev_open,

       .release    = i2cdev_release,

};

实际使用时, i2cdev_readi2cdev_write使用比较少,不建议使用,因为他们不具有太强的通用性。使用的时候一般就使用i2cdev_ioctl,当然i2cdev_openi2cdev_release也是需要使用的。

要使用i2c-dev,首先必须把I2C support里面的I2C device interface选上。

 

下面是一个例子,参考的华清远见的刘老师的,如下

/*i2c_test.c
        * hongtao_liu <>
        */
#include
#include
#include
#include
#include
#include
#include
#include
#define I2C_RETRIES 0x0701
#define I2C_TIMEOUT 0x0702
#define I2C_SLAVE   0x0703
#define I2C_RDWR    0x0707
/*********定义struct i2c_rdwr_ioctl_data和struct i2c_msg,要和内核一致*******/
struct i2c_msg
{
        unsigned short addr;
        unsigned short flags;
#define I2C_M_TEN 0x0010
#define I2C_M_RD 0x0001
        unsigned short len;
        unsigned char *buf;
};

struct i2c_rdwr_ioctl_data
{
    struct i2c_msg *msgs;
    int nmsgs;
   /* nmsgs这个数量决定了有多少开始信号,对于“单开始时序”,取1*/
};

#define SLAVE_ADD  0x50
/***********主程序***********/
int main()
{
    int fd,ret;
    struct i2c_rdwr_ioctl_data e2prom_data;
    fd=open("/dev/i2c0",O_RDWR);
/*
dev/i2c-0是在注册i2c-dev.c后产生的,代表一个可操作的适配器。如果不使用i2c-dev.c
的方式,就没有,也不需要这个节点。
*/
    if(fd<0)
    {
            perror("open error");
    }
   
    e2prom_data.nmsgs=2;
    /*因为操作时序中,最多是用到2个开始信号(字节读操作中),所以此将e2prom_data.nmsgs配置为2 */  
    e2prom_data.msgs=(struct i2c_msg*)malloc(e2prom_data.nmsgs*sizeof(struct i2c_msg));
    if(!e2prom_data.msgs)
    {
            perror("malloc error");
            exit(1);
    }
    ioctl(fd,I2C_TIMEOUT,1);/*超时时间*/
    ioctl(fd,I2C_RETRIES,2);/*重复次数*/
    /***write data to e2prom**/
     e2prom_data.nmsgs=1;
    (e2prom_data.msgs[0]).len=3; //1个 e2prom 写入目标的地址和1个数据
    (e2prom_data.msgs[0]).addr=SLAVE_ADD;//e2prom 设备地址
    (e2prom_data.msgs[0]).flags=0; //write
    (e2prom_data.msgs[0]).buf=(unsigned char*)malloc(3);
    (e2prom_data.msgs[0]).buf[0]=0x10;// e2prom 写入目标的地址
    (e2prom_data.msgs[0]).buf[1]=0x55;//the data to write
    (e2prom_data.msgs[0]).buf[2]=0xaa;//the data to write

    ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);
    if(ret<0)
    {
            perror("ioctl error1");
    }
    sleep(1);
/******read data from e2prom*******/
    e2prom_data.nmsgs=2;
    (e2prom_data.msgs[0]).len=1; //e2prom 目标数据的地址
    (e2prom_data.msgs[0]).addr=SLAVE_ADD; // e2prom 设备地址
    (e2prom_data.msgs[0]).flags=0;//write
    (e2prom_data.msgs[0]).buf[0]=0x10;//e2prom数据地址
    (e2prom_data.msgs[1]).len=2;//读出的数据
    (e2prom_data.msgs[1]).addr=SLAVE_ADD;// e2prom 设备地址
    (e2prom_data.msgs[1]).flags=I2C_M_RD;//read
    (e2prom_data.msgs[1]).buf=(unsigned char*)malloc(2);//存放返回值的地址。
    (e2prom_data.msgs[1]).buf[0]=0;//初始化读缓冲
    (e2prom_data.msgs[1]).buf[1]=0;//初始化读缓冲

    ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);
    if(ret<0)
    {
            perror("ioctl error2");
    }
    printf("buff[0]=0x%x,buff[1]=0x%x\n",(e2prom_data.msgs[1]).buf[0],(e2prom_data.msgs[1]).buf[1]);
 
    close(fd);
    return 0;
}
   


 

 

 

阅读(4589) | 评论(0) | 转发(0) |
0

上一篇:device_create分析

下一篇:Led在/sys 属性分析

给主人留下些什么吧!~~