Linux i2c通信

i2c通信的协议原理:

可参考博客:https://blog.csdn.net/pengliang528/article/details/79522644

I2C通信内核中操作方法

#define  I2C_BUS_ID    (2)     //设备挂载在i2c总线的ID
#define I2C_SLAVE_ADDR  (0x68) //high 7bits   从设备地址,第一个字节的高7位,后一位是读写位

/*
		addr  需要操作的从设备 寄存器,16位
		value  写入的值,32位
*/
int i2c_write_a16_d32(unsigned short addr,unsigned long value)
{

	struct i2c_msg msg;
	unsigned char data[6];
	int ret;
	struct i2c_adapter *adap;
	adap = i2c_get_adapter(I2C_BUS_ID);

	data[0] = (addr & 0xff00) >> 8;
	data[1] = (addr & 0x00ff);
	data[2] = (value & 0x000000ff);
	data[3] = (value & 0x0000ff00) >> 8;
	data[4] = (value & 0x00ff0000) >> 16;
	data[5] = (value & 0xff000000) >> 24;

	msg.addr = I2C_SLAVE_ADDR;
	msg.flags = 0;
	msg.len = 6;
	msg.buf = data;

	ret = i2c_transfer(adap, &msg, 1);
	printk("%s %s[%d] addr :%x value :%x ret :%x \n",__FILE__,__FUNCTION__,__LINE__,addr,value,ret);
	if (ret >= 0)
	{
		ret = 0;
	} else
	{
	}
	return ret;
}

/*
		addr  需要操作的从设备 寄存器,16位
		value  读出的值,32位
*/
int i2c_read_a16_d32(unsigned short addr,unsigned long *value)
{
	unsigned char data[6];
	struct i2c_msg msg[2];
	int ret;
	
	data[0] = (addr & 0xff00) >> 8;
	data[1] = (addr & 0x00ff);
	data[2] = 0xee;
	data[3] = 0xee;
	data[4] = 0xee;
	data[5] = 0xee;

	struct i2c_adapter *adap;
	adap = i2c_get_adapter(I2C_BUS_ID);

	/*
	 * Send out the register address...
	 */
	msg[0].addr = I2C_SLAVE_ADDR;
	msg[0].flags = 0;  //写标志
	msg[0].len = 2;    //字节数
	msg[0].buf = &data[0];
	/*
	 * ...then read back the result.
	 */
	msg[1].addr = I2C_SLAVE_ADDR;   
	msg[1].flags = I2C_M_RD;  
	msg[1].len = 4;
	msg[1].buf = &data[2];   

	ret = i2c_transfer(adap, msg, 2);    //2表示要操作的i2c_msg 个数,一般都是先告诉从设备要读的寄存器,然后再去读
	if (ret >= 0)
	{			printk("%s %s[%d] addr :%x  value 0x%x,0x%x,0x%x,0x%x,\n",__FILE__,__FUNCTION__,__LINE__,addr,data[2], data[3], data[4], data[5]);
		ret = 0;
	} else
	{
		printk("%s error! slave = 0x%x, addr = 0x%4x\n ", __func__, msg[0].addr, addr);
	}
	return ret;
}

不过实际过程中,一般读取从设备8位寄存器的较多,写入8位的值也较多,稍微改下就可以了
int    i2c_write_a8_d8(u8 addr,u8 value){
	struct i2c_msg msg;
	unsigned char data[2];
	int ret;
	struct i2c_adapter *adap;
	adap = i2c_get_adapter(I2C_BUS_ID);

	data[0] = addr;
	data[1] = value;

	msg.addr = I2C_SLAVE_ADDR;
	msg.flags = 0;
	msg.len = 2;
	msg.buf = data;

	ret = i2c_transfer(adap, &msg, 1);
	printk("%s %s[%d] addr :%x value :%x ret :%x \n",__FILE__,__FUNCTION__,__LINE__,addr,value,ret);
	if (ret >= 0)
	{
		ret = 0;
	} else
	{
	}
	return ret;
}

int  i2c_read_a8_d8(u8 addr,u8 *value){
	unsigned char data[2];
	struct i2c_msg msg[2];
	int ret;

	data[0] = addr;
	data[1] = 0xee;

	struct i2c_adapter *adap;
	adap = i2c_get_adapter(I2C_BUS_ID);

	/*
	 * Send out the register address...
	 */
	msg[0].addr = I2C_SLAVE_ADDR;
	msg[0].flags = 0;
	msg[0].len = 1;
	msg[0].buf = &data[0];

	msg[1].addr = I2C_SLAVE_ADDR;
	msg[1].flags = I2C_M_RD;
	msg[1].len = 1;
	msg[1].buf = &data[1];

	ret = i2c_transfer(adap, msg, 2);
	    
	if (ret >= 0)
	{   
		*value = data[1];
		ret = 0;
	} else
	{
		printk("%s error! slave = 0x%x, addr = 0x%4x \n ", __func__, msg[0].addr, addr);
	}
	return ret;
}

i2c 应用层操作方法

可参考博客: https://blog.csdn.net/u011479494/article/details/80812760

int i2c_open(int num)
{
	int fd;
	char str[20];
	sprintf(str,"/dev/i2c-%d",num);
	fd=open(str,O_RDWR);
	printf("i2c_open %d\n",fd);
	if(fd<0)
	{
		ALOGD("open(%s) : %s\n",str, strerror(errno));
		return -EIO;
	}
	return fd;
}

void i2c_close(int fd)
{
	close(fd);
}


int i2c_write(int fd,unsigned char slv_addr,unsigned char data_addr,int len, unsigned char* buf)
{
	int ret;
	struct i2c_rdwr_ioctl_data i2c_data;
	unsigned char* txf_data = (unsigned char*)malloc((len+1)*sizeof(unsigned char));
	if(!txf_data) {
		return -ENOMEM;
	}
	slv_addr >>= 1;
	txf_data[0] = data_addr;
	memcpy(&txf_data[1],buf,len*sizeof(unsigned char));
	i2c_data.nmsgs=1;
	i2c_data.msgs=(struct i2c_msg*)malloc(i2c_data.nmsgs*sizeof(struct i2c_msg));
	if(!i2c_data.msgs)
	{
		LOG("malloc error");
		printf("malloc error");		
		free(txf_data);
		return -ENOMEM;
	}
	/***write data to slave device**/
	i2c_data.nmsgs=1;
	(i2c_data.msgs[0]).len=(len + 1); 
	(i2c_data.msgs[0]).addr=slv_addr;
	(i2c_data.msgs[0]).flags=0; //write
	(i2c_data.msgs[0]).buf=(unsigned char*)txf_data;
	(i2c_data.msgs[0]).scl_rate=50000;
	ret=ioctl(fd, I2C_RDWR, (unsigned long)&i2c_data);
	if(ret<0)
	{
		ALOGD("i2c_write ioctl error:%s 0x%x\n", strerror(errno), slv_addr);
		printf("i2c_write ioctl error:%s 0x%x\n", strerror(errno), slv_addr);
		free(i2c_data.msgs);
		free(txf_data);
		return -EIO;
	}
	free(i2c_data.msgs);
	free(txf_data);
	return 0;
}

int i2c_read(int fd,unsigned char slv_addr,unsigned char data_addr,int len, unsigned char* buf)
{
	int ret;
	struct i2c_rdwr_ioctl_data i2c_data;
	slv_addr >>= 1;
	i2c_data.nmsgs=2;
	i2c_data.msgs=(struct i2c_msg*)malloc(i2c_data.nmsgs*sizeof(struct i2c_msg));
	if(!i2c_data.msgs)
	{
		perror("malloc error\n");
		return -ENOMEM;
	}
	i2c_data.nmsgs=1;
	(i2c_data.msgs[0]).len=1;
	(i2c_data.msgs[0]).addr=slv_addr;
	(i2c_data.msgs[0]).flags=0; //write
	(i2c_data.msgs[0]).buf=&data_addr; //data address
	(i2c_data.msgs[0]).scl_rate=40000;
	ret=ioctl(fd,I2C_RDWR,(unsigned long)&i2c_data);

	(i2c_data.msgs[0]).len=len;
	(i2c_data.msgs[0]).addr=slv_addr;
	(i2c_data.msgs[0]).flags=I2C_M_RD; //read
	(i2c_data.msgs[0]).buf=buf;
	(i2c_data.msgs[0]).scl_rate=40000;
	ret=ioctl(fd,I2C_RDWR,(unsigned long)&i2c_data);

	if(ret<0)
	{
		perror("i2c_read ioctl error1\n");
		free(i2c_data.msgs);
		return -EIO;
	}
	free(i2c_data.msgs);
	return 0;
}

以上都是基于有内核驱动的情况下操作,很多时候I2c通信并没有驱动,(例如主板在bootloader阶段时,需要和从设备进行i2c通信)这个时候一般都需要模拟I2c通信协议来进行,基本原理就是获得两个GPIO ,然后操作这两个GPIO来控制SCL和SDA两根线拉高或拉低来传输数据。

你可能感兴趣的:(Linux编程)