参考内核源码里的dev-interface文档.
在linux内核里i2c控制器驱动好后, i2c设备驱动方式通常由设备驱动通过控制器读写i2c设备数据、再提供应用程序调用和访问的接口.
除此设备驱动方工外,驱动好的i2c控制器也可提供应用程序直接调用控制器收发i2c设备数据的接口(dev-interface).这接口适用于一些没涉及到中断的简单设备,如dht12, eeprom等设备.
内核配置里的dev-interface选项:
make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
Device Drivers --->
<*> I2C support --->
<*> I2C device interface
选上此项,更新内核镜像重启系统后,应就可以在/dev目录下发生i2c-*的设备文件,应用程序就是通过这些设备文件调用控制器的.
设备文件的命名方式, 如序号为0的控制器,对应的设备文件应为/dev/i2c-0.
依照内核文档dev-interface的说明, i2c_smbus_xxxx_xxxx的操作函数无法实现操作, 只有ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)的方式测试成功.
操作步骤:
1 打开要调用的控制器设备文件
int fd = open("/dev/i2c-0", O_RDWR);
2 设置超时和传输失败时的重试次数(非必须作)
ioctl(fd, I2C_TIMEOUT, 10);
ioctl(fd, I2C_RETRIES, 2);
3 准备好需要传输的数据.
struct i2c_msg {
__u16 addr; /* slave address */
__u16 flags; //写为0, 读为I2C_M_RD
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; /* ptr to array of simple messages */
int nmsgs; /* number of messages to exchange */
};
ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset);
//调用此ioctl函数类似设备驱动里调用i2c_transfer函数。调用一次,只会在完成时发出一个停止信号,不管发出了多少个i2c_msg。 而且每一个i2c_msg都会有一个开始信号.
获取dht12温湿度传感器的例子:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#define DHT12_ADDR 0x5c
int main(void)
{
int fd, i;
char addr = 0, data[5];
fd = open("/dev/i2c-0", O_RDWR);
if (fd < 0)
return 1;
ioctl(fd, I2C_TIMEOUT, 10);
ioctl(fd, I2C_RETRIES, 2);
struct i2c_msg msgs[2] = {
{DHT12_ADDR, 0, 1, &addr},
{DHT12_ADDR, I2C_M_RD, 5, data},
};
struct i2c_rdwr_ioctl_data idata = {
.msgs = msgs,
.nmsgs = 2,
};
if (ioctl(fd, I2C_RDWR, &idata) < 0)
{
perror("ioctl");
return 2;
}
for (i = 0; i < 5; i++)
printf("%d ", data[5]);
close(fd);
return 0;
}