内核中对i2c读写函数有如下定义:
SMBus Read Byte: i2c_smbus_read_byte_data()
============================================
This reads a single byte from a device, from a designated register.
The register is specified through the Comm byte.
S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P
SMBus Read Word: i2c_smbus_read_word_data()
============================================
This operation is very like Read Byte; again, data is read from a
device, from a designated register that is specified through the Comm
byte. But this time, the data is a complete word (16 bits).
S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
Note the convenience function i2c_smbus_read_word_swapped is
available for reads where the two data bytes are the other way
around (not SMBus compliant, but very popular.)
SMBus Write Byte: i2c_smbus_write_byte_data()
==============================================
This writes a single byte to a device, to a designated register. The
register is specified through the Comm byte. This is the opposite of
the Read Byte operation.
S Addr Wr [A] Comm [A] Data [A] P
SMBus Write Word: i2c_smbus_write_word_data()
==============================================
This is the opposite of the Read Word operation. 16 bits
of data is written to a device, to the designated register that is
specified through the Comm byte.
S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
Note the convenience function i2c_smbus_write_word_swapped is
available for writes where the two data bytes are the other way
around (not SMBus compliant, but very popular.)
/
这四个函数的原型
/**
* i2c_smbus_read_byte_data - SMBus "read byte" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
*
* This executes the SMBus "read byte" protocol, returning negative errno
* else a data byte received from the device.
*/
s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command)
{
union i2c_smbus_data data;
int status;
status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
I2C_SMBUS_READ, command,
I2C_SMBUS_BYTE_DATA, &data);
return (status < 0) ? status : data.byte;
}
EXPORT_SYMBOL(i2c_smbus_read_byte_data);
/**
* i2c_smbus_write_byte_data - SMBus "write byte" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
* @value: Byte being written
*
* This executes the SMBus "write byte" protocol, returning negative errno
* else zero on success.
*/
s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command,
u8 value)
{
union i2c_smbus_data data;
data.byte = value;
return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
I2C_SMBUS_WRITE, command,
I2C_SMBUS_BYTE_DATA, &data);
}
/**
* i2c_smbus_read_word_data - SMBus "read word" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
*
* This executes the SMBus "read word" protocol, returning negative errno
* else a 16-bit unsigned "word" received from the device.
*/
s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command)
{
union i2c_smbus_data data;
int status;
status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
I2C_SMBUS_READ, command,
I2C_SMBUS_WORD_DATA, &data);
return (status < 0) ? status : data.word;
}
EXPORT_SYMBOL(i2c_smbus_read_word_data);
/**
* i2c_smbus_write_word_data - SMBus "write word" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
* @value: 16-bit "word" being written
*
* This executes the SMBus "write word" protocol, returning negative errno
* else zero on success.
*/
s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command,
u16 value)
{
union i2c_smbus_data data;
data.word = value;
return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
I2C_SMBUS_WRITE, command,
I2C_SMBUS_WORD_DATA, &data);
}
常用的i2c接口设备主要有eeprom,时钟,lcd,电池芯片等
1. 读写i2c从设备电池芯片
//i2c相关的头文件
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#define CHIP "/dev/i2c-1" //从设备连接到开发板的i2c的接口节点
//接下来就可以像读文件一样进行操作
int fd_i2c = -1;
int get_charge_info() //设置从设备的 i2c 接口,只需要调用一次
{
fd_i2c = open(CHIP,O_RDWR);
if(fd_i2c < 0)
{
printf("main -> %s open fail\r\n",CHIP);
return -1;
}
printf("main -> %s open done\r\n",CHIP);
ioctl(fd_i2c, I2C_SLAVE_FORCE, 0x70);//从设备地址
ioctl(fd_i2c, I2C_TIMEOUT, 3);//设置超时时间
ioctl(fd_i2c, I2C_RETRIES, 1);//设置重发次数
return 0;
}
int i2c_read(int fd_i2c) // 读取我们需要的信息, 可以添加到线程中,设置调用频率
{
short rd_value = 0;
float f_voltage = 0;
float f_status = 0;
rd_value = i2c_smbus_read_word_data(fd_i2c,0x0f); //剩余容量
f_voltage = (float)rd_value*0.001;
printf("RemainingCapacity %04x %.2f A\t",rd_value,f_voltage);
rd_value = i2c_smbus_read_word_data(fd_i2c,0x16); //电池状态
f_status = (float)rd_value*0.001;
printf("BatteryStatus %04x %.2f A\t",rd_value,f_status);
}
根据datasheet 设置i2c_smbus_read_word_data(client,command);
2. 读写i2c从设备(eeprom)
struct i2c_rdwr_ioctl_data i2c_data; /* I2C总线ioctl方法所使用的结构体 */
const char *i2c_dev = "/dev/i2c-0"; /*设备文件路径*/
unsigned char buftmp[32];
int fd = -1;
static int open_i2c_dev(void)
{
fd = open(i2c_dev, O_RDWR);
if(fd <0)
{
printf("open i2c device error \n");
return -1;
}
}
static void eeprom_init(int fd, unsigned char *buff)
{
ioctl(fd, I2C_TIMEOUT, 1); //设置超时时间
ioctl(fd, I2C_RETRIES, 2); //设置重发次数
memset(buff, 0, 32);
}
static int malloc_mem(int fd, int mode) /* 分配内存*/
{
if(mode == read ) /*读需要两个msg, 1个用来发读register的地址, 一个读数据*/
i2c_data.nmsgs = 2;
else if(mode == write) /*写的话只要一个msg即可*/
i2c_data.nmsgs = 1;
i2c_data.msgs = (struct i2c_msg *)malloc(i2c_data.nmsgs *sizeof(struct i2c_msg));
if (i2c_data.msgs == NULL)
{
printf("malloc error\n");
close(fd);
return -1;
}
}
static int read_write_ioctl(int fd)
{
int ret = ioctl(fd, I2C_RDWR, (unsigned long)&i2c_data);
if (ret < 0)
{
printf("read or write eeprom data error\n");
free(i2c_data.msgs);
return -1;
}
free(i2c_data.msgs);
close(fd);
}
static int print_data(int len, unsigned char *buff) /* print data */
{
for(int i = 0; i < len; i++)
{
printf(" 0x%02x",buff[i]);
}
printf("\n");
}
/*
* @ device_addr :从设备地址
* @ sub_addr : 寄存器地址
* @ buff :缓存区
* @ ByteNo: 读取长度
*/
unsigned char i2c_read(unsigned char device_addr, unsigned char sub_addr, unsigned char *buff, int b_len)
{
/*从设备地址是7bit,发送的时候必须右移1bit,以便和相邻的读写标志位组合成1Byte*/
device_addr >>= 1;
//读的nmsg为什么是两个,先写一次reg地址才能读数据
//xxxxxxxxxxxxxxxxxxx
//函数调用
//xxxxxxxxxxxxxxxxxxx
//write reg
memset(buftmp, 0, 32);
buftmp[0] = sub_addr;
i2c_data.msgs[0].len = 1;
i2c_data.msgs[0].addr = device_addr;
i2c_data.msgs[0].flags = 0; // 0: write 1:read
i2c_data.msgs[0].buf = buftmp;
//read data
i2c_data.msgs[1].len = b_len;
i2c_data.msgs[1].addr = device_addr;
i2c_data.msgs[1].flags = 1;
i2c_data.msgs[1].buf = buff;
}
/*
* @ device_addr :从设备地址
* @ sub_addr : 寄存器地址
* @ buff :缓存区
* @ ByteNo: 读取长度
*/
unsigned char _i2c_write(unsigned char device_addr, unsigned char sub_addr, unsigned char *buff, int b_len)
{
/*从设备地址是7bit,发送的时候必须右移1bit,以便和相邻的读写标志位组合成1Byte*/
device_addr >>= 1;
//xxxxxxxxxxxxxxxxxxx
//函数调用
//xxxxxxxxxxxxxxxxxxx
buftmp[0] = sub_addr; //写入寄存器的地址
memcpy(buftmp + 1, buff, ByteNo); //将需要写入的数据加上寄存器地址拷贝到buftmp
i2c_data.msgs[0].len = b_len+ 1; //写入的数据长度
i2c_data.msgs[0].addr = device_addr; // 设备地址
i2c_data.msgs[0].flags = 0; // 写
i2c_data.msgs[0].buf = buftmp; //将buftmp数据写入到buf中
}