1.前言
【 linux内核说明】
通常情况下,I2C设备由内核驱动控制,但是某些情况下I2C设备也可由用户空间控制。如果在用户空间控制I2C设备,需要访问/dev目录中所提供的接口,在使用I2C设备之前必须要载入i2c-dev设备。
每一个已经注册的IC设备都有一个编号,该编号从0开始计算。可以查看/sys/class/i2c-dev目录以获得I2C适配器的信息,或者使用i2cdetect工具查看I2C适配器。i2cdetect是一个简单易用的I2C工具包。
【 树莓派学习笔记——I2C Tools 学习笔记】
2.C语言的例子
让我们从一个简单的C语言的例子开始Linux I2C设备的使用。在开始之前需要包括 linux/i2c-dev.h。然后需要决定访问的I2C适配器,可以查看/sys/class/i2c-dev,或者使用i2cdetect - l命令。
接着便可打开文件,请看示例代码
int file;
int adapter_nr = 1; /* I2C适配器编号 */
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
file = open(filename, O_RDWR);
if (file < 0) {
/* 打开失败 */
exit(1);
}
打开设备时,必须确定I2C从机地址。
int addr = 0x40; /* I2C 从机地址 */
if (ioctl(file, I2C_SLAVE, addr) < 0) {
/* 打开失败 */
exit(1);
}
完成了基本设置,下面便可以使用SMBUS指令或纯I2C函数与芯片通信。
SMBUS函数形式是一个很不错的选择。
__u8 register = 0x10; /* I2C从机 寄存器地址 */
__s32 res;
char buf[10];
/* 使用SMBus函数 */
res = i2c_smbus_read_word_data(file, register);
if (res < 0) {
/* 错误 */
} else {
/* 成功读取到一个字 */
}
/* 使用I2C Write, 等价于i2c_smbus_write_word_data(file, register, 0x6543) */
buf[0] = register;
buf[1] = 0x43;
buf[2] = 0x65;
if (write(file, buf, 3) ! =3) {
/* 错误*/
}
/* 使用I2C Read, 等价于 i2c_smbus_read_byte(file) */
if (read(file, buf, 1) != 1) {
/* 错误 */
} else {
/* buf[0]为读取到的字节 */
}
3.SMBUS详细说明
【内核说明】
标记符
|
长度
|
说明
|
S
|
1 bit
|
I2C启动
|
P
|
1 bit
|
I2C停止
|
Rd/Wr
|
1 bit
|
控制字中的读写标志位,读操作为1,写操作为0
|
A, NA
|
1 bit
|
应答标志
|
Addr
|
7 bits
|
7位I2C地址
|
Data
|
8 bit
|
字节数据 |
Comm
|
8 bits
|
命令字节,可理解为I2C设备寄存器地址
|
[..]
|
N char
|
I2C设备返回的数据
|
【1】__s32 i2c_smbus_write_quick(int file, __u8 value);
发送一个写控制字,可用于测试I2C设备是否存在。
S Addr Rd [A] [Data] NA P
【2】__s32 i2c_smbus_read_byte(int file);
发送一个读控制字,并从I2C设备中读取一个字节。
S Addr Rd [A] [Data] NA P
【3】__s32 i2c_smbus_write_byte(int file, __u8 value);
发送一个写控制字,并向I2C设备中写入一个字节。
S Addr Wr [A] Data [A] P
【4】__s32 i2c_smbus_read_byte_data(int file, __u8 command);
向I2C设备发送一个写控制字+控制指令(寄存器地址),再发送一个读控制字,此时I2C从设备内部的读写指针转移到指定的位置,并返回一个字节,最后返回一个无应答NA。
S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P
【5】__s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value);
向I2C设备发送一个写控制字+控制指令(寄存器地址),紧接着发送指令内容(寄存器内容,单字节)。
S Addr Wr [A] Comm [A] Data [A] P
【6】__s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 *values);
向I2C设备发送一个写控制字+控制指令(寄存器地址),再发送一个读控制字,此时I2C从设备内部的读写指针转移到指定的位置,并连续返回多个字节,I2C主机读取到一定数量字节内容之后发送无应答NA。
S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
【7】__s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, __u8 *values);
向I2C设备发送一个写控制字+控制指令(寄存器地址),接着发送发送指令内容(寄存器内容,多字节)
S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P
【注意点1】
这些函数如果返回-1代表操作失败。在一些具有写功能的函数中,返回0代表操作成功,在具有读功能的函数中,返回读取的字节数(除i2c_smbus_read_block_data)。读块(block)操作时不应超过32个字节。
【注意点2】
树莓派不支持以下函数。
__s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);
__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, __u8 *values);
4.参考资料
【 i2c_smbus_write_block_data 和 i2c_smbus_write_i2c_block_data区别】
【 I2C操作笔记——以 AT24C04为例】