l 要使用用户模式I2C,首先配置内核选项,选中
<*>I2C device inerface
l 首先通过一个简单的例子来了解如何通过/dev/i2c-N节点访问i2c设备
#include
#include
#include
#include
#include
#include
#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;
}
l 用户空间应用程序需要包含
#include
#include
才能访问i2c-N
注意,存在两个"i2c-dev.h"文件: 一个属于Linux kernel,用于内核驱动中;一个由i2c-tools发布,用于用户程序。显然,这里需要使用第二个i2c-dev.h文件。
首次可以通过/sys文件系统了解I2C-N,代表哪个设备
这里代表i2c-0代表2410-i2c设备
l 打开设备后,可以通过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 */
l 读写I2C寄存器有两种方法
例如向某个寄存器写入数据 0x6543
i2c_smbus_write_word_data(file, register, 0x6543)
等同于
buf[0] = reister;
buf[1] = 0x43;
buf[2] = 0x65;
write(file ,buf, 3)
注意,仅有I2C和SMBus协议的一部分子集功能可以通过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