I2C控制器框架
APP 访问硬件肯定是需要驱动程序的,对于 I2C 设备,linux内核提供了默认的驱动程序 drivers/i2c/i2c-dev.c,通过它可以直接使用下面的 I2C 控制器驱动程序来 访问 I2C 设备。
1.重要结构体
1.1 i2c_adapter
i2c_adapter 表示一个 I2C BUS,或称为 I2C Controller,里面有 2 个重要的成员:
a) nr:第几个 I2C BUS(I2C Controller)
b) i2c_algorithm,里面有该 I2C BUS 的传输函数,用来收发 I2C 数据
怎么表示 I2C Controller , 一个芯片里可能有多个 I2C Controller,比如第 0 个、第 1 个、……
1.2 i2c_algorithm
1.3 I2C Device/I2C Client
一个 I2C Device,一定有设备地址, 那它连接在哪个 I2C Controller 上,即对应的 i2c_adapter 是什么。
使用 i2c_client 来表示一个 I2C Device。
1.4 i2c_msg
在上面的i2c_algorithm结构体中可以看到要传输的数据被称为:i2c_msg.
flags: 用来表示传输方向:bit 0 等于 I2C_M_RD 表示 读,bit 0 等于 0 表示写。一个 i2c_msg 要么是读,要么是写
举例:设备地址为 0x50 的 EEPROM,要读取它里面存储地址为 0x10 的一个字节, 应该构造几个 i2c_msg?
要构造 2 个 i2c_msg :
第一个 i2c_msg 表示写操作,把要访问的存储地址 0x10 发给设备
第二个 i2c_msg 表示读操作,并且返回读出的数据
如:
u8 data_addr = 0x10; i8 data; struct i2c_msg msgs[2]; msgs[0].addr = 0x50; msgs[0].flags = 0; msgs[0].len = 1; msgs[0].buf = &data_addr; msgs[1].addr = 0x50; msgs[1].flags = I2C_M_RD; msgs[1].len = 1; msgs[1].buf = &data;
2. I2C-Tools移植
源代码地址:https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/
2.1 工具链配置
export ARCH=arm export CROSS_COMPILE=arm-buildroot-linux-gnueabihf- export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueab ihf_sdk-buildroot/bin
2.2.编译
修改 I2C-Tools 的 Makefile 指定交叉编译工具链
CC ?= gcc AR ?= ar STRIP ?= strip
改为(指定交叉编译工具链前缀, 去掉问号):
CC = $(CROSS_COMPILE)gcc AR = $(CROSS_COMPILE)ar STRIP = $(CROSS_COMPILE)strip
在 Makefile 中,“?=”在第一次设置变量时才会起效果,如果之前设置过该变量,则不会起效果。
执行 make 时,是动态链接,需要把 libi2c.so 也放到单板上。 想静态链接的话,执行:make USE_STATIC_LIB=1
2.3.用法
2.3.1 i2cdetect:I2C 检测
// 列出当前的 I2C Adapter(或称为 I2C Bus、I2C Controller)
i2cdetect -l
// 打印某个 I2C Adapter 的 Functionalities, I2CBUS 为 0、1、2 等整数 i2cdetect -F I2CBUS
// 看看有哪些 I2C 设备, I2CBUS 为 0、1、2 等整数
i2cdetect -y -a I2CBUS
效果如下
2.3.2 i2cget:I2C 读(SMBus协议)
使用示例:
2.3.3 i2cset:I2C 写 (SMBus协议)
使用示例:
2.3.4 i2ctransfer:I2C 传输(不是基于 SMBus)
使用示例:
从i2c总线0,往0x1e设备地址,写2个字节,第一个字节写入寄存器地址0,第二个字节表示往寄存器0地址写入0x4
从i2c总线0,往0x1e设备地址,写2个字节,第一个字节写入寄存器地址0,第二个字节表示往寄存器0地址写入0x3
从i2c总线0,往0x1e设备地址,写1个字节,写入寄存器地址0xc表示要读0xc里面的值,再从0xc读2个字节
2.4 I2C-Tools 访问 I2C 设备的方式
I2C-Tools 可以通过 SMBus 来访问 I2C 设备,也可以使用一般的 I2C 协议 来访问 I2C 设备。 使用一句话概括 I2C 传输:APP 通过 I2C Controller 与 I2C Device 传 输数据.
Open("dev/i2c-0");
ioctl(file, I2C_SLAVE, address) ;
如果该设备已经有了对应的设备驱动程序,则返回失败。
ioctl(file, I2C_SLAVE_FORCE, address)
如果该设备已经有了对应的设备驱动程序但是还是想通过 i2c-dev 驱 动来访问它,则使用这个 ioctl 来指定 I2C 设备地址。
数据传输:
①ioctl(file, I2C_RDWR, &rdwr);(使用I2C方式)
该结构体表示一个或者多个i2c_msg。
示例代码:i2ctransfer.c
以i2ctransfer -f -y 0 w1@0x1e 0xe r2为例:
流程如下:
构造i2c_rdwr_ioctl_data结构,要用2个i2c_msg结构,第一个表示写入0xe寄存器地址给设备,第二个表示要从0xe寄存器读出2个字节
②ioctl(file, I2C_SMBUS, &args) ;(使用SMBus方式)
示例代码:i2cget.c i2cset.c
③直接使用read()/write();
int gc2053_read_register(VI_PIPE ViPipe, int addr) { int ret, data; CVI_U8 buf[8]; CVI_U8 idx = 0; if (g_fd[ViPipe] < 0) return CVI_FAILURE; if (gc2053_addr_byte == 2) buf[idx++] = (addr >> 8) & 0xff; // add address byte 0 buf[idx++] = addr & 0xff; ret = write(g_fd[ViPipe], buf, gc2053_addr_byte); if (ret < 0) { CVI_TRACE_SNS(CVI_DBG_ERR, "I2C_WRITE error!\n"); return ret; } buf[0] = 0; buf[1] = 0; ret = read(g_fd[ViPipe], buf, gc2053_data_byte); if (ret < 0) { CVI_TRACE_SNS(CVI_DBG_ERR, "I2C_READ error!\n"); return ret; } // pack read back data data = 0; if (gc2053_data_byte == 2) { data = buf[0] << 8; data += buf[1]; } else { data = buf[0]; } syslog(LOG_DEBUG, "i2c r 0x%x = 0x%x\n", addr, data); return data; } int gc2053_write_register(VI_PIPE ViPipe, int addr, int data) { CVI_U8 idx = 0; int ret; CVI_U8 buf[8]; if (g_fd[ViPipe] < 0) return CVI_SUCCESS; if (gc2053_addr_byte == 1) { buf[idx] = addr & 0xff; idx++; } if (gc2053_data_byte == 1) { buf[idx] = data & 0xff; idx++; } ret = write(g_fd[ViPipe], buf, gc2053_addr_byte + gc2053_data_byte); if (ret < 0) { CVI_TRACE_SNS(CVI_DBG_ERR, "I2C_WRITE error!\n"); return CVI_FAILURE; } ret = read(g_fd[ViPipe], buf, gc2053_addr_byte + gc2053_data_byte); //syslog(LOG_DEBUG, "i2c w 0x%x 0x%x\n", addr, data); return CVI_SUCCESS; }
使用示例:
标签:i2c,data,地址,msg,i2cTools,I2C,buf From: https://www.cnblogs.com/fuzidage/p/17001328.html