im6x板Linux应用层I2C通信

驱动给应用层提供了open、read、write、ioctl等函数来实现对底层硬件的控制,前三个参数相比其他设备比如uart、spi等使用方法都一样,主要的不同在ioctl里。

/* i2c_dev.h */

/* ioctl函数参数 */

#define I2C_SLAVE	0x0703	/* Use this slave address */
#define I2C_SLAVE_FORCE	0x0706	/* Use this slave address, even if it
				   is already in use by a driver! */
#define I2C_TENBIT	0x0704	/* 0 for 7 bit addrs, != 0 for 10 bit */

#define I2C_FUNCS	0x0705	/* Get the adapter functionality mask */

#define I2C_RDWR	0x0707	/* Combined R/W transfer (one STOP only) */

#define I2C_PEC		0x0708	/* != 0 to use PEC with SMBus */
#define I2C_SMBUS	0x0720	/* SMBus transfer */

从上面的参数可以看出来Linux应用层跟I2C通信需要知道1个参数:slave address,即从机地址;从机地址分为7bit和10bit,一般是7bit,具体看从设备的说明,首先需要明白什么是从机地址,下图是7bit的地址构成:

从上图可以看出bit1~bit7是从机地址,bit0是方向位,假设bit0写的时候为0,读的时候为1,bit7~bit1分别是11100010(具体值看从机设备的手册),合起来即:读0xE3,写0xE2;但是从机地址是7bit,因此从机地址是 0xE2 >> 1 = 0x71

由上得出:

从机地址:0x71

写地址:0xE2

读地址:0xE3

 

下面分析I2C的驱动,先看文件操作函数

/* i2c_dev.c */

/* I2C驱动函数调用顺序(局部) */
i2c_dev_init => register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops); //注册文件操作函数


/* I2C文件操作函数结构体 */
static const struct file_operations i2cdev_fops = {
	.owner		= THIS_MODULE,
	.llseek		= no_llseek,
	.read		= i2cdev_read,
	.write		= i2cdev_write,
	.unlocked_ioctl	= i2cdev_ioctl,
	.open		= i2cdev_open,
	.release	= i2cdev_release,
};

/* i2cdev_write函数调用顺序 */
i2cdev_write => i2c_master_send => i2c_transfer => i2c_imx_write

/* i2cdev_read函数调用顺序 */
i2cdev_read => i2c_master_recv => i2c_transfer => i2c_imx_read

从上面的分析可以得出read、write函数的底层实现是因板子不同而不同的,想要使用正确得看看驱动代码,下面以i2c_imx_write为例:

/* i2c消息结构体 */
struct i2c_msg {
	__u16 addr;	/* slave address			*/ =>在这里是0x71
	__u16 flags;                            =>写取0,读0 | I2C_M_RD
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_RD		0x0001	/* read data, from slave to master */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
	__u16 len;		/* msg length				*/    => 消息长度
	__u8 *buf;		/* pointer to msg data			*/ =>消息内容
};


static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
{
	int i, result;

	dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n",
		__func__, msgs->addr << 1);

	/* write slave address */ =>先发送写地址
	writeb(msgs->addr << 1, i2c_imx->base + IMX_I2C_I2DR);  =>写地址 = 从机地址 << 1 => 0x71 << 1 = 0xE2
	result = i2c_imx_trx_complete(i2c_imx);
	if (result)
		return result;
	result = i2c_imx_acked(i2c_imx);
	if (result)
		return result;
	dev_dbg(&i2c_imx->adapter.dev, "<%s> write data\n", __func__);

	/* write data */ => 再发送数据
	for (i = 0; i < msgs->len; i++) {
		dev_dbg(&i2c_imx->adapter.dev,
			"<%s> write byte: B%d=0x%X\n",
			__func__, i, msgs->buf[i]);
		writeb(msgs->buf[i], i2c_imx->base + IMX_I2C_I2DR);
		result = i2c_imx_trx_complete(i2c_imx);
		if (result)
			return result;
		result = i2c_imx_acked(i2c_imx);
		if (result)
			return result;
	}
	return 0;
}

由上面分析可以看出,imx6的write/read 驱动函数已经把读写地址发送过了,不需要我们再单独发送了。

使用举例:

#include <stdio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>

const char *i2c_dev = "/dev/i2c-0";

int main()
{
    int fd = 0;
    unsigned char slave_add = 0xe2;
    char i2c_tmp[5] = {0x03,0x00,0x00,0x30,0x33};
	char rbuf[20];
	int i;
    /* 打开设备文件 */
	fd = open(i2c_dev,O_RDWR);
	if (fd < 0)
	{
		perror("open i2c device error\n");
	}
    /* 设置为7bit地址 */
	if(ioctl(fd, I2C_TENBIT, 0) < 0)
	{
		perror("Unable to set I2C_TENBIT");
		return 1;
    }
    /* 设置从机地址 */
	if(ioctl(fd, I2C_SLAVE, slave_add >> 1) < 0)
	{
		perror("Unable to set I2C_SLAVE");
		return 1;
    }
    /* 发送数据 */
	write(fd, i2c_tmp, 5);
	usleep(12000);
    /* 读取数据 */
	read(fd,rbuf,20);
	for(i = 0; i < 20; i++)
	{
		printf("----i2c_read-buff:%02x-----\n",rbuf[i]);
	}

    close(fd);

    return 0;
}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值