I2C接口电池和eeprom读写

I2C接口读写详解
本文详细介绍了内核中I2C接口的读写函数,包括SMBusReadByte、SMBusReadWord、SMBusWriteByte和SMBusWriteWord的使用方法及原理。通过具体实例展示了如何读写电池芯片和EEPROM,提供了丰富的代码示例。

内核中对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中
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值