目录

命令的基本应用

查询 系统中I2C总线(控制器)

i2cdetect -l

查询总线1上的地址信息

读取控制器支持的功能

读取slave的寄存器

 读写eeprom

 写i2c switch开关

工具接口使用

读写接口

协议规范

代码走读


命令的基本应用

查询 系统中I2C总线(控制器)

i2cdetect -l

i2c-3   unknown         Synopsys DesignWare I2C adapter         N/A

i2c-10  unknown         Synopsys DesignWare I2C adapter         N/A

i2c-1   unknown         Synopsys DesignWare I2C adapter         N/A

i2c-8   unknown         Synopsys DesignWare I2C adapter         N/A

i2c-6   unknown         Synopsys DesignWare I2C adapter         N/A

i2c-13  unknown         Synopsys DesignWare I2C adapter         N/A

i2c-4   unknown         Synopsys DesignWare I2C adapter         N/A

i2c-11  unknown         Synopsys DesignWare I2C adapter         N/A

i2c-2   unknown         Synopsys DesignWare I2C adapter         N/A

i2c-0   unknown         Synopsys DesignWare I2C adapter         N/A

i2c-9   unknown         Synopsys DesignWare I2C adapter         N/A

i2c-7   unknown         Synopsys DesignWare I2C adapter         N/A

i2c-5   unknown         Synopsys DesignWare I2C adapter         N/A

i2c-12  unknown         Synopsys DesignWare I2C adapter         N/A

查询总线1上的地址信息

i2cdetect -a 1

Warning: Can't use SMBus Quick Write command, will skip some addresses

WARNING! This program can confuse your I2C bus, cause data loss and worse!

I will probe file /dev/i2c-1.

I will probe address range 0x00-0x7f.

Continue? [Y/n] y

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f

00:                                                

10:                                                

20:                                                

30: -- -- -- -- -- -- -- --                         

40:                                                

50: -- 51 -- -- -- -- -- -- -- -- -- -- -- -- -- --

60:                                                

70:                                                

i2cdetect 1(总线号)

Warning: Can't use SMBus Quick Write command, will skip some addresses

WARNING! This program can confuse your I2C bus, cause data loss and worse!

I will probe file /dev/i2c-1.

I will probe address range 0x03-0x77.

Continue? [Y/n] y

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f

00:                                                

10:                                                

20:                                                

30: -- -- -- -- -- -- -- --                         

40:                                                

50: -- UU -- -- -- -- -- -- -- -- -- -- -- -- -- --

60:                                                

70: 

 i2cdetect -r 1

WARNING! This program can confuse your I2C bus, cause data loss and worse!

I will probe file /dev/i2c-1 using receive byte commands.

I will probe address range 0x03-0x77.

Continue? [Y/n] y

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f

00:          -- -- -- -- -- -- -- -- -- -- -- -- --

10: -- -- -- -- -- -- -- -- 18 -- -- -- -- -- -- --

20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

50: -- 51 -- -- -- -- -- -- -- -- -- -- -- -- -- --

60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

读取控制器支持的功能

i2cdetect -F 1

Functionalities implemented by /dev/i2c-1:

I2C                              yes

SMBus Quick Command              no

SMBus Send Byte                  yes

SMBus Receive Byte               yes

SMBus Write Byte                 yes

SMBus Read Byte                  yes

SMBus Write Word                 yes

SMBus Read Word                  yes

SMBus Process Call               no

SMBus Block Write                yes

SMBus Block Read                 yes

SMBus Block Process Call         no

SMBus PEC                        no

I2C Block Write                  yes

I2C Block Read                   yes

读取slave的寄存器

i2cdump -a 1(总线编号) 0x51 (地址)

i2cdump -a 1 0x51

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

root@zh-D2000:/sys/bus/i2c#

No size specified (using byte-data access)

WARNING! This program can confuse your I2C bus, cause data loss and worse!

I will probe file /dev/i2c-1, address 0x51, mode byte

Continue? [Y/n] y

i2cdump -y -a 1 0x51 i

WARNING! This program can confuse your I2C bus, cause data loss and worse!

I will probe file /dev/i2c-1, address 0x51, mode i2c block

Continue? [Y/n] y

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef

00: 00 00 24 46 13 11 03 05 22 00 00 00 00 00 03 00    ..$F????".....?.

10: 00 00 24 46 13 11 03 05 22 00 00 00 00 00 03 00    ..$F????".....?.

20: 00 00 24 46 13 11 03 05 22 00 00 00 00 00 03 00    ..$F????".....?.

30: 00 00 24 46 13 11 03 05 22 00 00 00 00 00 03 00    ..$F????".....?.

40: 00 00 24 46 13 11 03 05 22 00 00 00 00 00 03 00   

 读写eeprom

  1) i2cset -y -f 0 0x50 0 0x33  向I2C控制器0 下挂的设备0x50,偏移量0 写入 0x33

2) i2cget -y -f 0 0x50 0   

0x33

 写i2c switch开关

i2ctransfer -f -y 1 w1@0x72 0x2

其中: 

1  标识 i2c控制器编号

w  表示写入

1 表示写入的字节数目。

@0x72  标识slave addr设备地址为0x72

0x2  为写入的数据。

此命令比较灵活,也可以读写eeprom,例如偏移量 0的一个字节

i2ctransfer -f -y 1  w2@0x50 0 0x33

工具接口使用

 

Index of /pub/software/utils/i2c-tools/ (kernel.org)

Implementing I2C device drivers in userspace — The Linux Kernel documentation

Kernel driver lm63 — The Linux Kernel documentation

The SMBus Protocol — The Linux Kernel documentation

通过上述链接可以下载源码,解压,编译:

make USE_STATIC_LIB=1

生成库文件libi2c.a

包括如下接口,对i2c smbus外设进行访问

nm -g --defined-only libi2c.a

smbus.ao:

0000000000000000 T i2c_smbus_access

0000000000000580 T i2c_smbus_block_process_call

0000000000000270 T i2c_smbus_process_call

00000000000002e0 T i2c_smbus_read_block_data

0000000000000088 T i2c_smbus_read_byte

0000000000000100 T i2c_smbus_read_byte_data

0000000000000418 T i2c_smbus_read_i2c_block_data

00000000000001b8 T i2c_smbus_read_word_data

0000000000000378 T i2c_smbus_write_block_data

00000000000000e8 T i2c_smbus_write_byte

0000000000000160 T i2c_smbus_write_byte_data

00000000000004e0 T i2c_smbus_write_i2c_block_data

0000000000000078 T i2c_smbus_write_quick

0000000000000218 T i2c_smbus_write_word_data

使用-L选项指明静态库的包含路径,使用-l(小写字母L)选项指明静态库的名字。

gcc  i2ctest.c  -I ./ -L  ./ -l i2c  -o  i2ctest

读写接口

协议规范

(24条消息) smbus协议规范命令格式-Linux文档类资源-CSDN文库

       在了解libi2c.a中库的功能前,我们需要先学习上面连接中smbus规范,总体而言,规范定义了读、写单字节、字、块的时序,而库中的接口则是对这些时序基于i2c的软件实现,明白了此点再看这些接口就更加命令。

     此外,这些接口中都有有个参数command,这个字段主要包括两个作用:

    1) 当从设备作为一个能处理命令报文的设备,例如单片机时,则command可以定义为 主从双方约定的协议命令字,例如主设备发送command  0xa表示从 从设备 获取温度。

    2) 当从设备不处理命令报文,作为一个简单设备,例如eeprom,则此字段作为访问寄存器的偏移量。此时如果command 填写0xa,则表示访问eeprom  偏移量为0xa的寄存器的值。

代码走读

根据连接 Implementing I2C device drivers in userspace — The Linux Kernel documentation

用户态通过i2c实现读写,可以通过两个ioctl功能  

I2C_RDWR 和I2C_SMBUS  ,对应的代码入口位于:   drivers\i2c\i2c-dev.c  
 

static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	struct i2c_client *client = file->private_data;
	unsigned long funcs;

	dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
		cmd, arg);

	switch (cmd) {
	case I2C_SLAVE:
	case I2C_SLAVE_FORCE:
		if ((arg > 0x3ff) ||
		    (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
			return -EINVAL;
		if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
			return -EBUSY;
		/* REVISIT: address could become busy later */
		client->addr = arg;
		return 0;
	case I2C_TENBIT:
		if (arg)
			client->flags |= I2C_M_TEN;
		else
			client->flags &= ~I2C_M_TEN;
		return 0;
	case I2C_PEC:
		/*
		 * Setting the PEC flag here won't affect kernel drivers,
		 * which will be using the i2c_client node registered with
		 * the driver model core.  Likewise, when that client has
		 * the PEC flag already set, the i2c-dev driver won't see
		 * (or use) this setting.
		 */
		if (arg)
			client->flags |= I2C_CLIENT_PEC;
		else
			client->flags &= ~I2C_CLIENT_PEC;
		return 0;
	case I2C_FUNCS:
		funcs = i2c_get_functionality(client->adapter);
		return put_user(funcs, (unsigned long __user *)arg);

	case I2C_RDWR: { // 读写接口
		struct i2c_rdwr_ioctl_data rdwr_arg;
		struct i2c_msg *rdwr_pa;

		if (copy_from_user(&rdwr_arg,
				   (struct i2c_rdwr_ioctl_data __user *)arg,
				   sizeof(rdwr_arg)))
			return -EFAULT;

		if (!rdwr_arg.msgs || rdwr_arg.nmsgs == 0)
			return -EINVAL;

		/*
		 * Put an arbitrary limit on the number of messages that can
		 * be sent at once
		 */
		if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
			return -EINVAL;

		rdwr_pa = memdup_user(rdwr_arg.msgs,
				      rdwr_arg.nmsgs * sizeof(struct i2c_msg));
		if (IS_ERR(rdwr_pa))
			return PTR_ERR(rdwr_pa);

		return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa);
	}

	case I2C_SMBUS: { //smbus 协议读写接口
		struct i2c_smbus_ioctl_data data_arg;
		if (copy_from_user(&data_arg,
				   (struct i2c_smbus_ioctl_data __user *) arg,
				   sizeof(struct i2c_smbus_ioctl_data)))
			return -EFAULT;
		return i2cdev_ioctl_smbus(client, data_arg.read_write,
					  data_arg.command,
					  data_arg.size,
					  data_arg.data);
	}
	case I2C_RETRIES:
		if (arg > INT_MAX)
			return -EINVAL;

		client->adapter->retries = arg;
		break;
	case I2C_TIMEOUT:
		if (arg > INT_MAX)
			return -EINVAL;

		/* For historical reasons, user-space sets the timeout
		 * value in units of 10 ms.
		 */
		client->adapter->timeout = msecs_to_jiffies(arg * 10);
		break;
	default:
		/* NOTE:  returning a fault code here could cause trouble
		 * in buggy userspace code.  Some old kernel bugs returned
		 * zero in this case, and userspace code might accidentally
		 * have depended on that bug.
		 */
		return -ENOTTY;
	}
	return 0;
}

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐