一.I2C 硬件框架
IIC就是master/slave模式,通过数据线和时钟线两根线实现主从设备通信,其传输熟虑标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s。其主要由两根线组成是SDA、SCL、上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。
- VCC:提供电源
- GND:接地
- SDA:串联数据线,传输数据
- SCL:串联时钟线,起控制作用
二.I2C读写示例
ioctl函数的使用:
原型:struct ioctl(struct file *file,unsigned int cmd,unsigned long arg);
cmd有I2C_SLAVE,I2C_SLAVE_FORCE,I2C_TENBIT,I2C_SET_SPEED几个选项;
I2C_SLAVE:对应的arg取值为I2C从机地址,用来设定I2C从机地址;
I2C_SLAVE_FORCE:对应的arg取值为I2C从机地址,用来修改I2C从机地址;
I2C_TENBIT:对应的arg取值为0:从机地址为7 bit;对应的arg取值为1:从机地址为10bit。用来指定I2C从机地址的位数;
I2C_SET_SPEED:对应的arg取值为I2C总线控制器分频值。用来设置I2C总线控制器时钟频率;
读写示例:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include "Log.h"
#include "i2c.h"
static int cam_fd[FD_NUMBER];
static int bus_cnt[FD_NUMBER];
pthread_mutex_t mutex[FD_NUMBER];
int i2c_init(int bus)
{
int ret = 0;
char str[12] = {0};
if (bus < 0 || bus >= FD_NUMBER)
{
pr_err("Invalid bus num %d", bus);
return -1;
}
if (cam_fd[bus] <= 0)
{
snprintf(str, sizeof(str), "/dev/i2c-%d", bus);
cam_fd[bus] = open(str, O_RDWR);
if (cam_fd[bus] < 0)
{
pr_err("open i2c-%d fail\n", bus);
return -1;
}
if (pthread_mutex_init(&mutex[bus], NULL) != 0)
{
pr_err("Init metux error.");
close(cam_fd[bus]);
cam_fd[bus] = -1;
return -1;
}
}
bus_cnt[bus]++;
pr_info("bus %d bus_cnt[bus] %d cam_fd[bus] %d\n",
bus, bus_cnt[bus], cam_fd[bus]);
return ret;
}
int i2c_deinit(int bus)
{
int ret = 0;
if (bus < 0 || bus >= FD_NUMBER)
{
pr_err("Invalid bus num %d", bus);
return -1;
}
bus_cnt[bus]--;
if (bus_cnt[bus] == 0 && cam_fd[bus] > 0)
{
close(cam_fd[bus]);
cam_fd[bus] = -1;
pthread_mutex_destroy(&mutex[bus]);
}
pr_info("bus %d bus_cnt[bus] %d cam_fd[bus] %d\n",
bus, bus_cnt[bus], cam_fd[bus]);
return ret;
}
int i2c_read_reg16_data16(int bus, uint8_t i2c_addr, uint16_t reg_addr)
{
int ret = 0, value = 0;
unsigned char wr_data[2];
unsigned char rdata[2] = {0};
int val = 0;
wr_data[0] = (reg_addr >> 8) & 0x00ff;
wr_data[1] = reg_addr & 0x00ff;
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
ret = ioctl(cam_fd[bus], I2C_SLAVE_FORCE, i2c_addr);
if (ret < 0)
{
pr_err("unable open camera with addr 0x%02x ioctl I2C_SLAVE_FORCE error\n", i2c_addr);
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
ret = write(cam_fd[bus], wr_data, 2);
if (ret != 2)
{
pr_err("write reg16_data16 fail\n");
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
ret = read(cam_fd[bus], &rdata, 2);
if (ret != 2)
{
pr_err("read reg16_data16 fail\n");
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
value = (rdata[0] << 8) | rdata[1];
pr_info("success with value 0x%04x \n", value);
pthread_mutex_unlock(&mutex[bus]);
return value;
}
int i2c_read_reg16_data8(int bus, uint8_t i2c_addr, uint16_t reg_addr)
{
int ret = 0, value = 0;
unsigned char wr_data[2];
unsigned char rdata = 0;
int val = 0;
wr_data[0] = (reg_addr >> 8) & 0x00ff;
wr_data[1] = reg_addr & 0x00ff;
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
ret = ioctl(cam_fd[bus], I2C_SLAVE_FORCE, i2c_addr);
if (ret < 0)
{
pr_err("unable open camera with addr 0x%02x ioctl I2C_SLAVE_FORCE error\n", i2c_addr);
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
ret = write(cam_fd[bus], wr_data, 2);
if (ret != 2)
{
pr_err("write reg16_data8 fail\n");
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
ret = read(cam_fd[bus], &rdata, 1);
if (ret != 1)
{
pr_err("read reg16_data8 fail\n");
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
value = rdata;
pthread_mutex_unlock(&mutex[bus]);
return value;
}
int i2c_read_reg8_data8(int bus, uint8_t i2c_addr, uint16_t reg_addr)
{
int ret = 0, value = 0;
unsigned char wr_data;
unsigned char rdata = 0;
int val = 0;
wr_data = reg_addr;
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
ret = ioctl(cam_fd[bus], I2C_SLAVE_FORCE, i2c_addr);
if (ret < 0)
{
pr_err("unable open camera with addr 0x%02x ioctl I2C_SLAVE_FORCE error\n", i2c_addr);
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
ret = write(cam_fd[bus], &wr_data, 1);
if (ret != 1)
{
pr_err("write reg8_data8 fail\n");
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
ret = read(cam_fd[bus], &rdata, 1);
if (ret != 1)
{
pr_err("read reg8_data8 fail\n");
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
value = rdata;
pthread_mutex_unlock(&mutex[bus]);
return value;
}
int i2c_read_reg8_data16(int bus, uint8_t i2c_addr, uint16_t reg_addr)
{
int ret = 0, value = 0;
unsigned char wr_data;
unsigned char rdata[2] = {0};
int val = 0;
wr_data = reg_addr;
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
ret = ioctl(cam_fd[bus], I2C_SLAVE_FORCE, i2c_addr);
if (ret < 0)
{
pr_err("unable open camera with addr 0x%02x ioctl I2C_SLAVE_FORCE error\n", i2c_addr);
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
ret = write(cam_fd[bus], &wr_data, 1);
if (ret != 1)
{
pr_err("write reg8_data16 fail\n");
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
ret = read(cam_fd[bus], &rdata, 2);
if (ret != 2)
{
pr_err("read reg8_data16 fail\n");
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
value = (rdata[0] << 8) | rdata[1];
pthread_mutex_unlock(&mutex[bus]);
return value;
}
int i2c_write_reg16_data16(int bus, uint8_t i2c_addr,
uint16_t reg_addr, uint16_t value)
{
int ret = 0;
unsigned char wr_data[4];
int val = 0;
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
ret = ioctl(cam_fd[bus], I2C_SLAVE_FORCE, i2c_addr);
if (ret < 0)
{
pr_err("unable open camera with addr 0x%02x ioctl I2C_SLAVE_FORCE error\n", i2c_addr);
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
wr_data[0] = (reg_addr >> 8) & 0x00ff;
wr_data[1] = reg_addr & 0x00ff;
wr_data[2] = (value >> 8) & 0x00ff;
wr_data[3] = (value)&0x00ff;
// pr_debug("0x%x camera reg(0x%04x) with value 0x%02x\n", i2c_addr , reg_addr, wr_data[2]);
ret = write(cam_fd[bus], wr_data, 4);
if (ret != 4)
{
// pr_err("write_reg16_data16 fail\n");
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
pthread_mutex_unlock(&mutex[bus]);
return 0;
}
int i2c_write_reg16_data8(int bus, uint8_t i2c_addr,
uint16_t reg_addr, uint8_t value)
{
int ret = 0;
unsigned char wr_data[3];
int val = 0;
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
ret = ioctl(cam_fd[bus], I2C_SLAVE_FORCE, i2c_addr);
if (ret < 0)
{
printf("unable open camera with addr 0x%02x ioctl I2C_SLAVE_FORCE error\n", i2c_addr);
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
wr_data[0] = (reg_addr >> 8) & 0x00ff;
wr_data[1] = reg_addr & 0x00ff;
wr_data[2] = value;
// pr_debug("camera reg(0x%04x) with value 0x%02x ", reg_addr, wr_data[2]);
ret = write(cam_fd[bus], wr_data, 3);
if (ret != 3)
{
// pr_err("write_reg16_data8 fail\n");
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
pthread_mutex_unlock(&mutex[bus]);
return 0;
}
int i2c_write_reg8_data16(int bus, uint8_t i2c_addr,
uint16_t reg_addr, uint16_t value)
{
int ret = 0;
unsigned char wr_data[3];
int val = 0;
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
ret = ioctl(cam_fd[bus], I2C_SLAVE_FORCE, i2c_addr);
if (ret < 0)
{
pr_err("unable open camera with addr 0x%02x ioctl I2C_SLAVE_FORCE error\n", i2c_addr);
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
wr_data[0] = reg_addr;
wr_data[1] = (value >> 8) & 0x00ff;
wr_data[2] = (value)&0x00ff;
ret = write(cam_fd[bus], wr_data, 3);
if (ret != 3)
{
// pr_err("write_reg8_data16 fail\n");
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
pthread_mutex_unlock(&mutex[bus]);
return 0;
}
int i2c_write_reg8_data8(int bus, uint8_t i2c_addr,
uint16_t reg_addr, uint8_t value)
{
int ret = 0;
unsigned char wr_data[2];
int val = 0;
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
ret = ioctl(cam_fd[bus], I2C_SLAVE_FORCE, i2c_addr);
if (ret < 0)
{
pr_err("unable open camera with addr 0x%02x ioctl I2C_SLAVE_FORCE error\n", i2c_addr);
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
wr_data[0] = reg_addr;
wr_data[1] = value;
// pr_debug("bus %d i2c_addr 0x%x reg_addr 0x%x value 0x%x\n", bus,
// i2c_addr, reg_addr, value);
ret = write(cam_fd[bus], wr_data, 2);
if (ret != 2)
{
// pr_err("write_reg8_data8 fail ret %d 0x%x 0x%x\n", ret, reg_addr, value);
pthread_mutex_unlock(&mutex[bus]);
return -1;
}
pthread_mutex_unlock(&mutex[bus]);
return 0;
}
int i2c_write_block(int bus, uint8_t i2c_addr,
uint16_t reg_addr, uint32_t value, uint8_t cnt)
{
int ret = 0;
struct i2c_rdwr_ioctl_data data;
unsigned char sendbuf[12] = {0};
unsigned char *ptr;
int val = 0;
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
if (cnt > 4)
cnt = 4;
data.msgs = (struct i2c_msg *)calloc(4, sizeof(struct i2c_msg));
data.nmsgs = cnt;
ptr = sendbuf;
data.msgs[0].len = 3;
data.msgs[0].addr = i2c_addr;
data.msgs[0].flags = 0;
data.msgs[0].buf = ptr;
data.msgs[0].buf[0] = (reg_addr >> 8) & 0xff;
data.msgs[0].buf[1] = reg_addr & 0xff;
data.msgs[0].buf[2] = value & 0xff;
/*
printf("msg0: buf[0] %x, buf[1] %x, buf[2] %x\n",
data.msgs[0].buf[0], data.msgs[0].buf[1], data.msgs[0].buf[2]);
*/
ptr = sendbuf + 3;
data.msgs[1].len = 3;
data.msgs[1].addr = i2c_addr;
data.msgs[1].flags = 0;
data.msgs[1].buf = ptr;
data.msgs[1].buf[0] = ((reg_addr + 1) >> 8) & 0xff;
data.msgs[1].buf[1] = (reg_addr + 1) & 0xff;
data.msgs[1].buf[2] = (value >> 8) & 0xff;
ptr = sendbuf + 6;
data.msgs[2].len = 3;
data.msgs[2].addr = i2c_addr;
data.msgs[2].flags = 0;
data.msgs[2].buf = ptr;
data.msgs[2].buf[0] = ((reg_addr + 2) >> 8) & 0xff;
data.msgs[2].buf[1] = (reg_addr + 2) & 0xff;
data.msgs[2].buf[2] = (value >> 16) & 0xff;
ptr = sendbuf + 9;
data.msgs[3].len = 3;
data.msgs[3].addr = i2c_addr;
data.msgs[3].flags = 0;
data.msgs[3].buf = ptr;
data.msgs[3].buf[0] = ((reg_addr + 3) >> 8) & 0xff;
data.msgs[3].buf[1] = (reg_addr + 3) & 0xff;
data.msgs[3].buf[2] = (value >> 24) & 0xff;
ret = ioctl(cam_fd[bus], I2C_RDWR, (unsigned long)&data);
if (ret < 0)
pr_err("%s failed\n", __func__);
free(data.msgs);
pthread_mutex_unlock(&mutex[bus]);
return 0;
}
int i2c_read_block_reg16(int bus, uint8_t i2c_addr,
uint16_t reg_addr, char *buf, uint32_t count)
{
int ret = 0;
struct i2c_rdwr_ioctl_data data;
unsigned char sendbuf[12] = {0};
int val = 0;
// pr_info("read_block_reg16 reg_addr 0x%x count %d\n", reg_addr, count);
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
data.msgs = (struct i2c_msg *)calloc(2, sizeof(struct i2c_msg));
data.nmsgs = 2;
data.msgs[0].len = 2;
data.msgs[0].addr = i2c_addr;
data.msgs[0].flags = 0;
data.msgs[0].buf = sendbuf;
data.msgs[0].buf[0] = (reg_addr >> 8) & 0xff;
data.msgs[0].buf[1] = reg_addr & 0xff;
data.msgs[1].len = count;
data.msgs[1].addr = i2c_addr;
data.msgs[1].flags = 1;
data.msgs[1].buf = buf;
ret = ioctl(cam_fd[bus], I2C_RDWR, (unsigned long)&data);
if (ret < 0)
pr_err("%s failed\n", __func__);
free(data.msgs);
pthread_mutex_unlock(&mutex[bus]);
return 0;
}
int i2c_read_block_reg8(int bus, uint8_t i2c_addr,
uint16_t reg_addr, char *buf, uint32_t count)
{
int ret = 0;
struct i2c_rdwr_ioctl_data data;
unsigned char sendbuf[12] = {0};
int val = 0;
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
data.msgs = (struct i2c_msg *)calloc(2, sizeof(struct i2c_msg));
data.nmsgs = 2;
data.msgs[0].len = 2;
data.msgs[0].addr = i2c_addr;
data.msgs[0].flags = 0;
data.msgs[0].buf = sendbuf;
data.msgs[0].buf[0] = reg_addr & 0xff;
data.msgs[1].len = count;
data.msgs[1].addr = i2c_addr;
data.msgs[1].flags = 1;
data.msgs[1].buf = buf;
ret = ioctl(cam_fd[bus], I2C_RDWR, (unsigned long)&data);
if (ret < 0)
pr_err("%s failed\n", __func__);
free(data.msgs);
pthread_mutex_unlock(&mutex[bus]);
return 0;
}
int i2c_write_block_reg16(int bus, uint8_t i2c_addr,
uint16_t reg_addr, char *buf, uint32_t count)
{
int ret = 0;
struct i2c_rdwr_ioctl_data data;
char *sendbuf = NULL;
int val = 0;
// pr_info("write_block_reg16 reg_addr 0x%x count %d\n", reg_addr, count);
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
sendbuf = malloc(count + 2);
if (sendbuf == NULL)
{
pr_err("malloc error\n");
return -1;
}
data.msgs = (struct i2c_msg *)calloc(1, sizeof(struct i2c_msg));
data.nmsgs = 1;
data.msgs[0].len = 2 + count;
data.msgs[0].addr = i2c_addr;
data.msgs[0].flags = 0;
data.msgs[0].buf = sendbuf;
sendbuf[0] = (reg_addr >> 8) & 0xff;
sendbuf[1] = reg_addr & 0xff;
memcpy(sendbuf + 2, buf, count);
ret = ioctl(cam_fd[bus], I2C_RDWR, (unsigned long)&data);
if (ret < 0)
pr_err("%s failed\n", __func__);
free(data.msgs);
free(sendbuf);
pthread_mutex_unlock(&mutex[bus]);
return 0;
}
int i2c_write_block_reg8(int bus, uint8_t i2c_addr,
uint16_t reg_addr, char *buf, uint32_t count)
{
int ret = 0;
struct i2c_rdwr_ioctl_data data;
unsigned char sendbuf[12] = {0};
int val = 0;
val = pthread_mutex_lock(&mutex[bus]);
if (val != 0)
{
pr_err("mutex lock error val %d \n", val);
return -1;
}
data.msgs = (struct i2c_msg *)calloc(2, sizeof(struct i2c_msg));
data.nmsgs = 2;
data.msgs[0].len = 2;
data.msgs[0].addr = i2c_addr;
data.msgs[0].flags = 0;
data.msgs[0].buf = sendbuf;
data.msgs[0].buf[0] = reg_addr & 0xff;
data.msgs[1].len = count;
data.msgs[1].addr = i2c_addr;
data.msgs[1].flags = 0;
data.msgs[1].buf = buf;
ret = ioctl(cam_fd[bus], I2C_RDWR, (unsigned long)&data);
if (ret < 0)
pr_err("%s failed\n", __func__);
free(data.msgs);
pthread_mutex_unlock(&mutex[bus]);
return 0;
}