前言
I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。本文主要介绍在linux系统通过i2c设备通过应用软件发送和接收i2c消息。
一、设备打开
linux下一切皆文件,I2C设备也是一个文件,I2C_DEV为系统I2C设备/dev/i2c-1,设备打开操作如下所示:
fd = open(I2C_DEV, O_RDWR);
二、数据读写
数据写入用的不是write函数,数据读取也不是用read函数,而是统一用ioctl,用法如下:
ioctl的第一个参数传入已经打开的I2C设备的文件描述符,第二个参数传入I2C_RDWR,表示进行数据读写,第三个参数传入一个struct i2c_rdwr_ioctl_data类型的指针,struct i2c_rdwr_ioctl_data类型定义在linux/i2c-dev.h中,其结构定义如下:
struct i2c_rdwr_ioctl_data {
struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
一个该结构表示一次传输,一次传输可以包含若干个消息,nmsgs用于指定消息数量。一般来说一次写数据包含一个消息,一次读数据包含2个消息,因此写数据时nmsgs的值为1,msgs指向一个消息,读数据时nmsgs为2,msgs指向一个包含2个消息的数组。
struct i2c_msg结构定义如下:
struct i2c_msg {
__u16 addr; /* slave address */
__u16 flags;
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RD 0x0001 /* read data, from slave to master */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
1.I2C写数据
int i2c_write(int fd, unsigned char dev_addr, unsigned char reg_addr, unsigned char * data_buf, int len)
{
int ret = 0;
unsigned char msg_buf[9];
struct i2c_rdwr_ioctl_data data;
struct i2c_msg messages;
msg_buf[0] = reg_addr;
if(len < 9)
{
memcpy((void *) &msg_buf[1], data_buf, len);
}
else
{
printf("This function supports up to 8 bytes");
return -1;
}
messages.addr = dev_addr;
messages.flags = 0;
messages.len = len + 1;
messages.buf = msg_buf;
data.msgs = &messages;
data.nmsgs = 1;
if(ioctl(fd, I2C_RDWR, &data) < 0)
{
printf("I2C_RDWR err\n");
return -1;
}
usleep(50);
return 0;
}
2.I2C读数据
int i2c_read(int fd, unsigned char dev_addr, unsigned char reg_addr, unsigned char *data_buf, int len)
{
int ret = 0;
unsigned char msg_buf[9];
struct i2c_rdwr_ioctl_data data;
struct i2c_msg messages[2];
messages[0].addr = dev_addr;
messages[0].flags = 0;
messages[0].len = 1;
messages[0].buf = ®_addr;
messages[1].addr=dev_addr;
messages[1].flags = I2C_M_RD;
messages[1].len = len;
messages[1].buf = data_buf;
data.msgs = messages;
data.nmsgs = 2;
if(ioctl(fd, I2C_RDWR, &data) < 0)
{
printf("I2C_RDWR err\n");
return -1;
}
usleep(50);
return 0;
}
3.SMbus传输
如果I2C适配器支持SMbus协议,那么就可以使用SMbus协议与设备进行通信。查看I2C适配器关于SMbus支持情况,可以通过ioctl的I2C_FUNCS命令查询。
使用SMbus进行数据传输,需要将数据封装到i2c_smbus_ioctl_data中
struct i2c_smbus_ioctl_data {
__u8 read_write;
__u8 command;
__u32 size;
union i2c_smbus_data __user *data;
};
#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
union i2c_smbus_data {
__u8 byte;
__u16 word;
__u8 block[I2C_SMBUS_BLOCK_MAX + 2];
/* block[0] is used for length */
/* and one more for user-space compatibility */
};
/* i2c_smbus_xfer read or write markers */
#define I2C_SMBUS_READ 1
#define I2C_SMBUS_WRITE 0
i2c_smbus_access接口
int i2c_smbus_access(int file, char read_write, __u8 command,
int size, union i2c_smbus_data *data)
{
struct i2c_smbus_ioctl_data args;
int err;
args.read_write = read_write;
args.command = command;
args.size = size;
args.data = data;
err = ioctl(file, I2C_SMBUS, &args);
if (err == -1)
err = -errno;
return err;
}
总结
在linux下使用i2c应用程序操作i2c设备,读者不需要熟悉i2c接口时序,不用我们去定义时序,读者能够更简单的去操作i2c接口设备。i2c接口模块可以在下面链接下载: