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两根线拉高或拉低来传输数据。