用户模式I2C驱动


如果有大量低速 I2C 设备,可以考虑从用户空间驱动它们。 i2c-dev 模块有助于开发用户模式 i2c/smbus 设备驱动程序。用户空间代码通过 /dev/i2c-N 节点访问 i2c 设备。为了操作第 N 块适配器,请打开 /dev/i2c-N, 打开文件节点后,通过 ioctl 设置相应的设备为从设备。

 

要使用用户模式I2C,首先配置内核选项,选中

<*>I2C device inerface


 

首先通过一个简单的例子来了解如何通过/dev/i2c-N节点访问i2c设备

 

#include <stdio.h>

#include <sys/ioctl.h>

#include <fcntl.h>

#include <unistd.h>

 

#include <linux/i2c.h>

#include <linux/i2c-dev.h>

 

#define SLAVE_ADDR1 0x20

 

static unsigned char led_onoff_status=0xff;

 

int main(int argc, char *argv[])

{

    int i2c_fd;

    /* open i2c device */

    if((i2c_fd = open("/dev/i2c-0", O_RDWR)) < 0){

        printf("Cant open /dev/i2c-0");

        exit(1);

    }

 

    /* connect the first bank */

    if(ioctl(i2c_fd, I2C_SLAVE, SLAVE_ADDR1) < 0){

        printf("ioctl error\n");

        exit(1);

    }

    /* write i2c device */

    while(1){

//        i2c_smbus_write_byte(i2c_fd, 0xff);

        led_onoff_status = 0xff;

        if(write(i2c_fd, &led_onoff_status, 1) < 1){

            printf("i2c write error.\n");

        };

        usleep(1000 * 500);

        led_onoff_status = 0x00;

        write(i2c_fd, &led_onoff_status, 1);

        usleep(500 * 1000);

    }

    /* switch i2c bank */

    /* ioctl(i2c_fd, I2C_SLAVE, SLAVE_ADDR2) */

   

    close(i2c_fd);

    return 0;

}

 

用户空间应用程序需要包含

 

#include <linux/i2c.h>

#include <linux/i2c-dev.h>

才能访问i2c-N

注意,存在两个"i2c-dev.h"文件: 一个属于Linux kernel,用于内核驱动中;一个由i2c-tools发布,用于用户程序。显然,这里需要使用第二个i2c-dev.h文件。

首次可以通过/sys文件系统了解I2C-N,代表哪个设备


 

这里代表i2c-0代表2410-i2c设备

 

打开设备后,可以通过ioctl配置设备

 

IOCTL支持以下命令

#define I2C_RETRIES         0x0701   /*设置收不到ACK时的重试次数              */

#define I2C_TIMEOUT         0x0702   /* 设置超时时限的jiffies                 */

#define I2C_SLAVE           0x0703   /*设置从机地址                           */

#define I2C_SLAVE_FORCE     0x0706   /* 强制设置从机地址                      */

#define I2C_TENBIT          0x0704   /*选择地址位长:=0 for 7bit , != 0 for 10 bit */

#define I2C_FUNCS           0x0705   /*获取适配器支持的功能                      */

#define I2C_RDWR            0x0707   /*Combined R/W transfer (one STOP only)  */

#define I2C_PEC             0x0708   /* != 0 to use PEC with SMBus            */

#define I2C_SMBUS           0x0720  /*SMBus transfer                         */

 

读写I2C寄存器有两种方法

例如向某个寄存器写入数据 0x6543

   i2c_smbus_write_word_data(file, register, 0x6543)

等同于

buf[0] = reister;
    buf[1] = 0x43;
    buf[2] = 0x65;
  write(file ,buf, 3)       

 

注意,仅有I2CSMBus协议的一部分子集功能可以通过read()write()的调用完成。尤
其,对于组合型的传输(mixing read and write messages in the same transaction)不被read()/write()支持。基于这个原因,read()write()这两个接口几乎不被用户空间程序使用。

需要特别注意的是:i2c-dev.c的read()、write()方法都只适合于如下方式的数据格式(可查看内核相关源码)


图1 单开始信号时序

所以不具有太强的通用性,如下面这种情况就不适用(通常出现在读目标时)。


图2 多开始信号时序

而且read()、write()方法只适用用于适配器支持i2c算法的情况,如:

static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
            .master_xfer = s3c24xx_i2c_xfer,
            .functionality = s3c24xx_i2c_func,
        };

而不适合适配器只支持smbus算法的情况,如:
        static const struct i2c_algorithm smbus_algorithm = {
            .smbus_xfer = i801_access,
            .functionality = i801_func,
        };

基于上面几个原因,所以一般都不会使用i2c-dev.c的read()、write()方法。最常用的是ioctl()方法。ioctl()方法可以实现上面所有的情况(两种数据格式、以及I2C算法和smbus算法)。

针对i2c的算法,需要熟悉struct i2c_rdwr_ioctl_data 、struct i2c_msg。使用的命令是I2C_RDWR。

针对i2c的算法,需要熟悉struct i2c_rdwr_ioctl_data 、struct i2c_msg。使用的命令是I2C_RDWR。
        struct i2c_rdwr_ioctl_data {
            struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
            __u32 nmsgs; /* number of i2c_msgs */
        };
        struct i2c_msg {
            _ _u16 addr; /* slave address */
            _ _u16 flags; /* 标志(读、写) */
            _ _u16 len; /* msg length */
            _ _u8 *buf; /* pointer to msg data */
        };

针对smbus算法,需要熟悉struct i2c_smbus_ioctl_data。使用的命令是I2C_SMBUS。对于smbus算法,不需要考虑“多开始信号时序”问题。
        struct i2c_smbus_ioctl_data {
            __u8 read_write; //读、写
            __u8 command; //命令
            __u32 size; //数据长度标识
            union i2c_smbus_data __user *data; //数据
        };

实例代码片段:

e2prom_data.nmsgs=1;
   (e2prom_data.msgs[0]).len=2; //1个 e2prom 写入目标的地址和1个数据
    (e2prom_data.msgs[0]).addr=0x50;//e2prom 设备地址
    (e2prom_data.msgs[0]).flags=0; //write
    (e2prom_data.msgs[0]).buf=(unsigned char*)malloc(2);
    (e2prom_data.msgs[0]).buf[0]=0x10;// e2prom 写入目标的地址
    (e2prom_data.msgs[0]).buf[1]=0x58;//the data to write

    ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);

参考链接:

http://blog.chinaunix.net/uid-21977330-id-3755767.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值