IIC协议——i2c-dev的使用
Posted Shemesz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IIC协议——i2c-dev的使用相关的知识,希望对你有一定的参考价值。
i2c-dev
在Linux内核代码文件/include/linux/i2c-dev.c中针对每个适配器生成一个主设备号为89的设备节点,实现了文件操作接口,用户空间可以通过i2c设备节点访问i2c适配器。适配器的编号从0开始,和适配器的设备节点的次设备号相同。
i2c适配器的设备节点是/dev/i2c-x,其中x是数字,代表适配器的编号。由于适配器编号是动态分配的(和注册次序有关),所以想了解哪一个适配器对应什么编号,可以查看/sys/class/i2c-dev/目录下的文件内容。
(1)前期准备
- 通过代码操控i2c适配器,必须包含以下头文件
#include<linux/i2c-dev.h>
#include<linux/i2c.h>
- 查看设备节点
因为适配器编号不固定,所以需要查看具体设备名称
pi@raspberrypi:~ $ cat /sys/class/i2c-dev/i2c-0/name
pi@raspberrypi:~ $ cat /sys/class/i2c-dev/i2c-1/name
pi@raspberrypi:~ $ cat /sys/class/i2c-dev/i2c-2/name
- 打开设备节点/dev/i2c-1
fd = open("/dev/i2c-1",O_RDWR) //可以打印fd的值,查看是否返回正确
(2)ioctl()控制
查看include/linux/i2c-dev.h文件,可以看到i2c-dev支持的IOCTL命令
i2c-dev 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*/
1. 设置重试次数
ioctl(fd, I2C_RETRIES,m);
设置适配器收不到ACK时重试的次数为m。默认的重试次数为1。
2. 设置超时
ioctl(fd, I2C_TIMEOUT,m);
设置SMBus的超时时间为m,单位为jiffies。
3. 设置从机地址
ioctl(fd, I2C_SLAVE,addr);
ioctl(fd, #defineI2C_SLAVE_FORCE, addr);
在调用read()和write()函数之前必须设置从机地址。
这两行都可以设置从机的地址,区别是:
第一行则只在该地址空闲的情况下成功。由于i2c-dev创建的i2c_client不加入i2c_adapter的client列表,所以不能防止其它线程使用同一地址,也不能防止驱动模块占用同一地址。
第二行无论内核中是否已有驱动在使用这个地址都会成功;
4. 设置地址模式
ioctl(fd,I2C_TENBIT,select)
如果select不等于0选择10比特地址模式,如果等于0选择7比特模式,默认7比特。只有适配器支持I2C_FUNC_10BIT_ADDR,这个请求才是有效的。
5. 获取适配器功能
ioctl(fd,I2C_FUNCS,(unsignedlong *)funcs)
获取的适配器功能保存在funcs中,如下:
/* include/linux/i2c.h */
#define I2C_FUNC_I2C 0x00000001
#define I2C_FUNC_10BIT_ADDR 0x00000002
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004/*I2C_M_{REV_DIR_ADDR,NOSTART,..}*/
#define I2C_FUNC_SMBUS_PEC 0x00000008
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_QUICK 0x00010000
#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000/* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */
6. I2C层通信
这一行代码可以使用I2C协议和设备进行通信。它进行连续的读写,中间没有间歇。只有当适配器支持I2C_FUNC_I2C此命令才有效。
ioctl(fd,I2C_RDWR,(struct i2c_rdwr_ioctl_data *)msgset);
参数:指向 struct i2c_rdwr_ioctl_data
类型的结构体指针
- i2c_rdwr_ioctl_data
msgs[] 数组成员包含了指向各自缓冲区的指针。这个函数会根据是否在消息中的flags置位I2C_M_RD来对缓冲区进行读写。从机的地址以及是否使用10比特地址模式记录在每个消息中,忽略之前ioctl设置的结果。
struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; /* 指向i2c_msgs数组 */
__u32 nmsgs; /* 消息的个数 */
};
- i2c_msgs
struct i2c_msg {
__u16 addr; // 从机地址
__u16 flags; // 读/写(1/0)标志
__u16 len; // 数据长度
__u8 *buf; // 数据指针
};
7. 设置SMBus PEC
ioctl(fd,I2C_PEC,(long )select);
-
如果select不等于0选择SMBus PEC (packet error checking),等于零则关闭这个功能,默认是关闭的。
-
这个命令只对SMBus传输有效。这个请求只在适配器支持I2C_FUNC_SMBUS_PEC时有效;如果不支持这个命令也是安全的,它不做任何工作。
8. SMBus通信
这个函数和I2C_RDWR类似,参数的指针指向i2c_smbus_ioctl_data类型的变量。
ioctl(fd, I2C_SMBUS, (i2c_smbus_ioctl_data*)msgset);
- i2c_smbus_ioctl_data
struct i2c_smbus_ioctl_data {
__u8 read_write;
__u8 command;
__u32 size;
union i2c_smbus_data *data;
};
更多例程请点击了解:《用户空间使用i2c-dev》
以上是关于IIC协议——i2c-dev的使用的主要内容,如果未能解决你的问题,请参考以下文章