I2C设备的无驱访问

做中间件,最首要的原则就是内聚,由于驱动程序的特殊性,不可避免的要开源,这对知识产权与中间件的可移植性都有负面的影响。但很多情况下,Kernel对于通用设备都提供了User Space的访问接口,可以在应用程序中直接访问设备,例如,本文将要提到的i2c-dev,就避免的在中间件发布时,提供驱动程序的问题。
i2c-dev提供了i2c设备的/dev接口,该用户层接口基于i2c adapter访问连接的i2c设备。要使用i2c的/dev接口,要在kernel中的打开i2c device interface的支持:driver->I2C support->I2C device interface,加载新的kernel后,可以在/dev目录下找到i2c的adapter,命名方式采用i2c-%d(i2c-0, i2c-1, etc.)
User Space程序编写:

打开设备:

  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);
  }

设置i2c设备地址:

采用SMBus方式访问的i2c设备,要单独设置i2c设备的地址:

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);
  }

通过SMBus方式访问i2c设备:

__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 */
}

上面代码中用到的smbus系列接口在标准kernel中未提供,原型在i2c-tools这个工具里面。
同时,i2c device interface还支持i2c协议直接操作,例程如下:

bool I2cReadBlock( int fd, uint8_t reg, uint8_t * data, int16_t len )
{
    struct i2c_rdwr_ioctl_data _data;
    struct i2c_msg _msg[2];
    int _retry  =   0, _len;

    _data.nmsgs =   2;
    _data.msgs  =   &_msg;

    _data.msgs[0].addr  =   I2C_DEV_ADDR;
    _data.msgs[0].flags =   0;
    _data.msgs[0].len   =   1;
    _data.msgs[0].buf   =   ®
    _data.msgs[1].addr  =   I2C_DEV_ADDR;
    _data.msgs[1].flags =   I2C_M_RD;
    _data.msgs[1].len   =   len;
    _data.msgs[1].buf   =   data;

    ioctl( fd, I2C_RDWR, ( unsigned long )&_data );

    return TRUE;
}

bool I2cWriteBlock( int fd, uint8_t reg, uint8_t * data, int16_t len )
{
    struct i2c_rdwr_ioctl_data _data;
    struct i2c_msg _msg;
    uint8_t _buf[ 1 + len ];
    int _retry  =   0;

    _data.nmsgs =   1;
    _data.msgs  =   &_msg;

    _buf[0] =   reg;
    memcpy( _buf + 1, data, len );

    _data.msgs[0].addr  =   I2C_DEV_ADDR;
    _data.msgs[0].flags =   0;
    _data.msgs[0].len   =   1 + len;
    _data.msgs[0].buf   =   _buf;

    ioctl( fd, I2C_RDWR, ( unsigned long )&_data );

    return TRUE;
}

你可能感兴趣的:(driver-中间件)