Linux-I2C驱动

序言

I2C 具体通信协议本文不涉及,本文主要介绍在 Linux 中 I2C 的驱动框架。

I2C 有两条信号线:SCL 和 SDA。

  • SCL:时钟线,数据收发同步
  • SDA:数据线,传输具体数据

I2C 驱动框架

Linux I2C 驱动由三部分组成:I2C 核心、I2C 总线驱动、I2C 设备驱动。

  • I2C 核心层驱动作为顶层驱动,管理整个I2C子系统,并提供了基本的I2C操作接口。
  • I2C 适配器驱动负责与底层硬件的 I2C 控制器进行交互,通过适配器驱动,I2C总线核心驱动能够与硬件进行通信。
  • I2C 设备驱动则针对具体的 I2C 设备编写,实现了对设备的初始化、读写数据等操作。

I2C 核心(I2C Core Driver)

I2C 核心负责管理 I2C 总线适配器和设备,提供 I2C 总线驱动和设备驱动和注册、注销方法,完成 I2C 设备和 I2C 驱动匹配过程。这一部分不涉及硬件的操作,一般由系统厂编写

I2C 核心中主要函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 1.i2c_adapter 注册/注销函数
int i2c_add_adapter(struct i2c_adapter *adapter)
void i2c_del_adapter(struct i2c_adapter * adap)

// 2.i2c_driver 注册/注销函数
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
int i2c_add_driver (struct i2c_driver *driver)
void i2c_del_driver(struct i2c_driver *driver)

// 3.创建并注册一个I2C设备
struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)

// 4.I2C 传输、发送、接收
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
int i2c_master_recv(const struct i2c_client *client, char *buf, int count)

i2c_transfer 函数可以进行复杂的多消息传输,而 i2c_master_sendi2c_master_recv 函数用于单个数据消息的发送和接收。i2c_transfer 由于其灵活性,通常被优先使用。

I2C 总线驱动

I2C 总线驱动重点是 I2C 适配器驱动(I2C Adapter Driver),I2C 适配器驱动负责与硬件的 I2C 控制器进行交互,完成硬件层面的初始化、配置和操作。它将底层硬件的特定接口与 I2C 总线核心驱动进行连接,使得核心驱动能够通过适配器驱动来访问硬件。这一部分一般由芯片厂提供,例如 IMX6ULL 的 I2C 适配器驱动已经由 NXP 公司编写好了。

I2C 适配器驱动主要涉及两个结构体:i2c_adapteri2c_algorithm

i2c_adapter 结构体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// include/linux/i2c.h

struct i2c_adapter {
struct module *owner;
unsigned int class; /* classes to allow probing for */
const struct i2c_algorithm *algo; /* the algorithm to access the bus */
void *algo_data;

/* data fields that are valid for all devices */
const struct i2c_lock_operations *lock_ops;
struct rt_mutex bus_lock;
struct rt_mutex mux_lock;

int timeout; /* in jiffies */
int retries;
struct device dev; /* the adapter device */

int nr;
char name[48];
struct completion dev_released;

struct mutex userspace_clients_lock;
struct list_head userspace_clients;

struct i2c_bus_recovery_info *bus_recovery_info;
const struct i2c_adapter_quirks *quirks;
};

i2c_algprithm 结构体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// include/linux/i2c.h

struct i2c_algorithm {
/* If an adapter algorithm can't do I2C-level access, set master_xfer
to NULL. If an adapter algorithm can do SMBus access, set
smbus_xfer. If set to NULL, the SMBus protocol is simulated
using common I2C messages */
/* master_xfer should return the number of messages successfully
processed, or a negative value on error */
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num);
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data);

/* To determine what the adapter supports */
u32 (*functionality) (struct i2c_adapter *);

#if IS_ENABLED(CONFIG_I2C_SLAVE)
int (*reg_slave)(struct i2c_client *client);
int (*unreg_slave)(struct i2c_client *client);
#endif
};
  • master_xfer 就是 I2C 适配器的传输函数,可以通过此函数来完成与 I2C 设备之间的通信。
  • smbus_xfer 就是 SMBUS 总线的传输函数。

I2C 总线驱动,或者说 I2C 适配器驱动的主要工作就是初始化 i2c_adapter 结构体变量,里面由个成员变量:algorithm 中存在一系列函数指针,这些函数指针指向真正硬件操作代码。

I2C 设备驱动(I2C Device Driver)

I2C 设备驱动是针对特定类型的 I2C 设备编写的驱动程序。它包含了对具体设备的操作和控制逻辑,通过调用I2C 总线核心驱动提供的 API 函数与设备进行通信。设备驱动的主要任务包括初始化设备、读写数据、配置设备参数等。这一部分由开发者编写

I2C 设备驱动主要是填充两个重要的结构体:i2c_clienti2c_driveri2c_client 是描述设备信息的,i2c_driver 是描述驱动内容的,类似于平台总线驱动中的 platform_deviceplatform_driver,如果采用设备树的话,则只需要编写 i2c_driver 结构体的内容即可,因为设备树中的 I2C 节点会转换为 i2c_client 的内容。

i2c_client 结构体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// include/linux/i2c.h

struct i2c_client {
unsigned short flags; /* div., see below */
unsigned short addr; /* chip address - NOTE: 7bit */
/* addresses are stored in the */
/* _LOWER_ 7 bits */
char name[I2C_NAME_SIZE];
struct i2c_adapter *adapter; /* the adapter we sit on */
struct device dev; /* the device structure */
int irq; /* irq issued by device */
struct list_head detected;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
i2c_slave_cb_t slave_cb; /* callback for slave mode */
#endif
};

i2c_driver 结构体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// include/linux/i2c.h

struct i2c_driver {
unsigned int class;

/* Notifies the driver that a new bus has appeared. You should avoid
* using this, it will be removed in a near future.
*/
int (*attach_adapter)(struct i2c_adapter *) __deprecated;

/* Standard driver model interfaces */
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);

/* driver model interfaces that don't relate to enumeration */
void (*shutdown)(struct i2c_client *);

/* Alert callback, for example for the SMBus alert protocol.
* The format and meaning of the data value depends on the protocol.
* For the SMBus alert protocol, there is a single bit of data passed
* as the alert response's low bit ("event flag").
* For the SMBus Host Notify protocol, the data corresponds to the
* 16-bit payload data reported by the slave device acting as master.
*/
void (*alert)(struct i2c_client *, enum i2c_alert_protocol protocol,
unsigned int data);

/* a ioctl like command that can be used to perform specific functions
* with the device.
*/
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

struct device_driver driver;
const struct i2c_device_id *id_table;

/* Device detection callback for automatic device creation */
int (*detect)(struct i2c_client *, struct i2c_board_info *);
const unsigned short *address_list;
struct list_head clients;
};

I2C 设备驱动编写过程

首先是 I2C 设备的信息,有两种方法:未使用设备树和使用设备树。

I2C 设备驱动信息描述

未使用设备树

未使用设备树的话,则需要在新建一个文件例如 xxx_i2c_client.c 文件(命名无要求)。

  • 在该文件下使用 i2c_borad_info 结构体描述 I2C 设备的信息——设备名字和设备地址,
  • 接着将该设备挂载在相对应的 I2C 总线上

i2c_borad_info 结构体如下:

1
2
3
4
5
6
7
8
9
10
11
12
// include/linux/i2c.h

struct i2c_board_info {
char type[I2C_NAME_SIZE]; /* I2C 设备名字*/
unsigned short flags; /* 标志*/
unsigned short addr; /* I2C 器件地址*/
void *platform_data;
struct dev_archdata *archdata;
struct device_node *of_node;
struct fwnode_handle *fwnode;
int irq;
};

其中 type 和 addr 这两个成员变量必须要设置,使用如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>

// 分配一个i2c适配器指针
static struct i2c_adapter *i2c_adap;
// 分配一个i2c_client指针
static struct i2c_client *i2c_client;

/* I2C 设备信息:设备名字 设备地址 */
static struct i2c_board_info xxx_board_info[] = {
{I2C_BOARD_INFO("xxx@xx", 0x00)},
{},
};

/* 驱动入口函数 */
static int __init xxx_i2c_client_init(void)
{
// 调用i2c_get_adapter获得一个i2c总线 将xxx挂载到i2c(fd+1)总线上
// 这里的fd取决于你的设备挂载在哪根I2C总线上(看原理图)
// 接着看着根I2C总线在你开发板中的设备树或内核配置中的顺序编号(一般从0开始)
i2c_adap = i2c_get_adapter(fd);

// 把i2c client和i2c器件关联起来
i2c_client = i2c_new_device(i2c_adap, xxx_info);

// 释放i2c控制器
i2c_put_adapter(i2c_adap);

return 0;
}

/* 驱动出口函数 */
static void __exit xxx_i2c_client_exit(void)
{
// 将前面注册的i2c_driver 也从Linux 内核中注销掉
i2c_unregister_device(i2c_client);
}

module_init(xxx_i2c_client_init);
module_exit(xxx_i2c_client_exit);
MODULE_LICENSE("GPL");

使用设备树

使用设备树文件时,只需要在设备树文件中添加相应的 I2C 设备节点即可例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";

// 添加以下信息即可:设备名字和设备地址
ap3216c@1e {
compatible = "ap3216c";
reg = <0x1e>;
status = "okay";
};
};

I2C driver 驱动

driver 驱动文件

I2C driver 驱动文件通用结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h> /*注册设备节点的文件结构体*/
#include <linux/cdev.h> // 对字符设备结构cdev 以及一系列的操作函数的定义。包含了cdev 结构及相关函数的定义。
#include <linux/device.h> //包含了device、class 等结构的定义

static ssize_t xxx_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)
{

return 0;
}

static int xxx_open (struct inode *node, struct file *file)
{

return 0;
}
static int xxx_close (struct inode *node, struct file *file)
{

return 0;
}

static const struct file_operations xxx_fops = {
.owner = THIS_MODULE,
.open = xxx_open,
.release = xxx_close,
.read = xxx_read,
};


static int xxx_i2c_driver_probe(struct i2c_client *client, const struct i2c_device_id *id)
{

return 0;
}
static int xxx_i2c_driver_remove(struct i2c_client *client)
{

return 0;
}

/* 设备树compatible匹配表 */
static const struct of_device_id of_match_table[] = {
{.compatible = "xxx"},
{},
};

/* 无设备树的匹配ID表 */
static const struct i2c_device_id id_table[] = {
{"xxx"},
{},
};

/* 定义i2c总线设备结构体 */
static struct i2c_driver xxx_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "xxx",
.of_match_table = of_match_table,
},
.probe = xxx_i2c_driver_probe,
.remove = xxx_i2c_driver_remove,
.id_table = id_table,
};


/* 驱动入口函数 */
static int __init xxx_i2c_driver_init(void)
{
int ret;
// 注册 i2c 驱动
ret = i2c_add_driver(&xxx_i2c_driver);
return ret;
}

/* 驱动出口函数 */
static void __exit xxx_i2c_driver_exit(void)
{
// 将前面注册的i2c_driver也从Linux内核中注销掉
i2c_del_driver(&xxx_i2c_driver);
}

module_init(xxx_i2c_driver_init);
module_exit(xxx_i2c_driver_exit);
MODULE_LICENSE("GPL");

I2C 设备的数据收发和处理

定义一个 xxx_dev 结构体用来存放一些创建设备需要的变量和获取到的信息,读取和写入函数主要是填充 i2c_msg 结构体,然后使用 i2c_transfer 函数传输数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
struct xxx_dev {
/* 设备号这些添加进来是为了方便管理 */
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
struct device_node *nd; /* 设备节点 */
int major; /* 主设备号 */
void *private_data; /* 私有数据 一般转换为 struct i2c_client * */
/* 数据 */
};

static struct xxx_dev xxx_dev_t; // 定义结构体

/*
* @description : 读取I2C 设备多个寄存器数据
* @param – dev : I2C 设备
* @param – reg : 要读取的寄存器首地址
* @param – val : 读取到的数据
* @param – len : 要读取的数据长度
* @return : 操作结果
*/
static int xxx_read_reg(struct xxx_dev *dev, uint8_t reg, uint8_t *val, uint16_t len)
{
int ret;
struct i2c_msg msg[2];
struct i2c_client *client = (struct i2c_client *)dev->private_data;

/* msg[0],第一条写消息,发送要读取的寄存器首地址*/
msg[0].addr = client->addr; // 设备地址
msg[0].flags = 0; // 写数据
msg[0].buf = &reg; // 寄存器地址
msg[0].len = 1; // msg长度:寄存器地址长度

/* msg[1],第二条读消息,读取寄存器数据*/
msg[1].addr = client->addr; // 设备地址
msg[1].flags = I2C_M_RD; // 读数据
msg[1].buf = data; // 读取的数据
msg[1].len = len; // msg长度:读取数据的长度

ret = i2c_transfer(client->adapter, msg, 2); // 2个msg
if(ret == 2)
ret = 0;
else
ret = -EREMOTEIO;

return ret;
}

/*
* @description : 向 I2C 设备多个寄存器写入数据
* @param – dev : 要写入的设备结构体
* @param – reg : 要写入的寄存器首地址
* @param – val : 要写入的数据缓冲区
* @param – len : 要写入的数据长度
* @return : 操作结果
*/
static int xxx_write_reg(struct xxx_dev *dev, uint8_t reg, uint8_t *buf, uint16_t len)
{
uint8_t tmp[256];
struct i2c_msg msg; // 存放待写入的寄存器地址和数据等信息
struct i2c_client *client = (struct i2c_client *)dev->private_data;

tmp[0] = reg; // 寄存器地址
memcpy(&tmp[1], buf, len); // 写入的数据

msg.addr = client->addr; // 设备地址
msg.flags = 0; // 写数据
msg.buf = tmp; // 发送的数据缓冲区
msg.len = len + 1; // msg长度:写入的数据长度 + 寄存器地址长度 (单位:字节)

return i2c_transfer(client->adapter, &msg, 1); // 1个msg
}

i2c-tools

i2c-tools 是一个专门调试 i2c 的开源工具,可以获取挂载的设备及设备地址,还可以读写 I2C 设备寄存器。

在调试新的 I2C 设备驱动时,需要多次修改寄存器看结果现象,正常做法是修改驱动代码寄存器值——编译烧录——运行看结果,费时费力,使用 i2c-tools 可以省去很多时间。

i2c-tools 官方说明:I2C Tools - Linux i2c Wiki (kernel.org)

i2c-tools 是通过操作 /dev 路径 i2c-× 设备文件完成,因此你的 kernel 必须开启 CONFIG_I2C_CHARDEV 宏控,否者会报找不到节点。

检测开发板是否有 i2c-tools 工具,检测相应工具是否存在即可。

1
i2cdetect -V

如果没有的话,则需要交叉工具链进行交叉编译,编译生成五个工具:i2cdetect、i2cset、i2cget、i2cdump、i2ctransfer,拷贝到开发板中就可以使用,也可以直接把 i2c-tools 源码包放到自己的源码中,直接编译进固件。

  • i2cdetect:用于扫描 i2c 总线上的设备,并显示地址
  • i2cset:设置 i2c 设备某个寄存器的值
  • i2cget:读取 i2c 设备某个寄存器的值
  • i2cdump:读取某个 i2c 设备所有寄存器的值
  • i2ctransfer:一次性读写多个字节

查看已经挂载的 i2c 设备

1
2
[root@100ask:~]# ls /sys/bus/i2c/devices/
1-001a 1-0039 1-005d i2c-0 i2c-1

使用示例

i2cdetect

i2cdetect 用于扫描 i2c 总线上的设备,并显示地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]
i2cdetect -F I2CBUS
i2cdetect -l
I2CBUS is an integer or an I2C bus name
If provided, FIRST and LAST limit the probing range.

I2CBUS:指定要扫描的I2C总线编号或者总线名称。
-y:在检测到设备时自动确认,不提示用户输入。
-a:扫描整个I2C总线地址空间,包括扩展的地址(7位地址)。
-q 或 -r:使用快速或慢速扫描模式。快速模式(-q)会更快地扫描地址空间,但可能漏掉一些慢响应的设备。慢速模式(-r)会等待更长的时间来检测每个地址,确保检测到所有设备。
-F:当与 I2CBUS 一起使用时,i2cdetect 将尝试检测总线上的每个设备的功能性。
-l:列出所有可用的I2C总线。
FIRST LAST:扫描的地址范围

i2cdetect -l 显示所有可用的 i2c 总线:

1
2
3
[root@100ask:~]# i2cdetect -l
i2c-1 i2c 21a4000.i2c I2C adapter
i2c-0 i2c 21a0000.i2c I2C adapter

i2cdetect -y 0 显示指定 i2c 总线挂载设备的情况:

image-20240628120005177

– 表示该地址被检测,但是无设备应答,UU 表示该地址被当前内核驱动使用,由上图可知 i2c-1 总线当前有三个被内核驱动使用的设备,设备地址为:0x1a、0x39、0x5d。另外还显示了两个设备的具体地址,表示硬件上连接了 i2c 总线,只是没有被内核驱动使用。

i2cset

i2cset:设置 i2c 设备某个寄存器的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Usage: i2cset [-f] [-y] [-m MASK] [-r] [-a] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]
I2CBUS is an integer or an I2C bus name
ADDRESS is an integer (0x03 - 0x77, or 0x00 - 0x7f if -a is given)
MODE is one of:
c (byte, no value)
b (byte data, default)
w (word data)
i (I2C block data)
s (SMBus block data)
Append p for SMBus PEC

-f:强制执行,即使在某些情况下可能不安全。
-y:自动应答,不提示用户确认。
-m MASK:对数据应用掩码。只有掩码中为1的位会被写入,其余位保持不变。
-r:如果设置了,并且指定了模式 c(即无值的字节命令),则在写入命令后立即读取一个字节的数据。
-a:允许10位地址的设备。默认情况下,i2cset 只处理7位地址的设备。
I2CBUS:指定I2C总线的编号或名称。
CHIP-ADDRESS:i2c设备地址。
DATA-ADDRESS:i2c寄存器地址
VALUE:要写入的数据值。具体需要根据后面指定的 MODE 来确定数据格式。
MODE:指定数据传输的模式,可以是以下几种之一:
c:发送一个无数据的字节命令。
b:发送一个字节的数据(默认模式)。
w:发送一个字(16位)的数据。
i:发送I2C块数据。
s:发送SMBus块数据。

设置 i2c-0 总线上 0x1E 设备的 0x00 寄存器值为 0x03:

1
i2cset -f -y 0 0x1e 0x00 0x03

i2cget

i2cget:读取 i2c 设备某个寄存器的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Usage: i2cget [-f] [-y] [-a] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]
I2CBUS is an integer or an I2C bus name
ADDRESS is an integer (0x03 - 0x77, or 0x00 - 0x7f if -a is given)
MODE is one of:
b (read byte data, default)
w (read word data)
c (write byte/read byte)
Append p for SMBus PEC
-f:强制执行,即使在某些情况下可能不安全。
-y:自动应答,不提示用户确认。
-a:允许10位地址的设备。默认情况下,i2cset 只处理7位地址的设备。
I2CBUS:指定I2C总线的编号或名称。
CHIP-ADDRESS:i2c设备地址。
DATA-ADDRESS:i2c寄存器地址
MODE:指定数据传输的模式,可以是以下几种之一:
c:发送一个无数据的字节命令。
b:发送一个字节的数据(默认模式)。
w:发送一个字(16位)的数据。
i:发送I2C块数据。
s:发送SMBus块数据。

获取 i2c-0 总线上 0x1E 设备的 0x00 寄存器的值:

1
i2cget -f -y 0 0x1e 0x00

i2cdump

i2cdump:读取某个 i2c 设备所有寄存器的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Usage: i2cdump [-f] [-y] [-r first-last] [-a] I2CBUS ADDRESS [MODE [BANK [BANKREG]]]
I2CBUS is an integer or an I2C bus name
ADDRESS is an integer (0x03 - 0x77, or 0x00 - 0x7f if -a is given)
MODE is one of:
b (byte, default)
w (word)
W (word on even register addresses)
s (SMBus block)
i (I2C block)
c (consecutive byte)
Append p for SMBus PEC
-f:强制执行,即使可能存在风险的操作也会执行。
-y:自动应答,不提示用户确认。
-r first-last:指定要读取的寄存器地址范围。first 是起始地址,last 是结束地址。
-a:允许使用10位地址的设备。默认情况下,i2cdump 只处理7位地址的设备。
I2CBUS:指定要读取的I2C总线的编号或名称。
ADDRESS:i2c设备地址
MODE:指定读取数据的模式,可以是以下几种之一:
b:按字节读取(默认模式)。
w:按字(16位)读取。
W:按字(16位)读取,但只在偶数寄存器地址上读取。
s:SMBus块数据读取。
i:I2C块数据读取。
c:连续字节读取。
BANK:对于需要切换寄存器银行的设备,指定要读取的寄存器银行。
BANKREG:寄存器银行切换寄存器的地址。
PEC:如果模式以 p 结尾,表示启用SMBus数据包错误校正(PEC)。

获取 i2c-0 总线上 0x1E 设备所有寄存器的值

1
i2cdump -f -y 0 0x1e

i2ctransfer

i2ctransfer:一次性读写多个字节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Usage: i2ctransfer [-f] [-y] [-v] [-V] [-a] I2CBUS DESC [DATA] [DESC [DATA]]...
I2CBUS is an integer or an I2C bus name
DESC describes the transfer in the form: {r|w}LENGTH[@address]
1) read/write-flag 2) LENGTH (range 0-65535) 3) I2C address (use last one if omitted)
DATA are LENGTH bytes for a write message. They can be shortened by a suffix:
= (keep value constant until LENGTH)
+ (increase value by 1 until LENGTH)
- (decrease value by 1 until LENGTH)
p (use pseudo random generator until LENGTH with value as seed)

Example (bus 0, read 8 byte at offset 0x64 from EEPROM at 0x50):
# i2ctransfer 0 w1@0x50 0x64 r8
Example (same EEPROM, at offset 0x42 write 0xff 0xfe ... 0xf0):
# i2ctransfer 0 w17@0x50 0x42 0xff-

-f:强制执行,用于覆盖某些安全限制。
-y:自动应答,不提示用户确认。
-v:增加输出的详细程度,显示更多的信息。
-V:显示程序版本信息。
-a:允许使用10位地址的设备。默认情况下,i2ctransfer 只处理7位地址的设备。
I2CBUS:指定I2C总线的编号或名称。
DESC:描述传输操作,格式为 {r|w}LENGTH[@address],其中:
r 表示读取数据。
w 表示写入数据。
LENGTH 是要传输的数据长度,范围从0到65535。
@address 是I2C设备的寄存器地址,如果省略,将使用上一个操作的地址。
DATA:对于写操作,DATA 是要写入的数据,可以是一系列的字节、字或块数据。数据可以通过后缀进一步定义模式:
= 表示保持当前值不变,直到达到 LENGTH。
+ 表示从当前值开始递增,直到达到 LENGTH。
- 表示从当前值开始递减,直到达到 LENGTH。
p 表示使用伪随机生成器,使用当前值作为种子,直到达到 LENGTH。

参考资料

https://blog.csdn.net/qq_45172832/article/details/131221971

手把手教你使用 i2c-tools-i2c-tools使用 (51cto.com)