第二十九节、i2c总线
本节用于介绍i2c总线
一、I2C简介
I2C是很常见的一种总线协议,I2C是NXP公司设计的,I2C使用两条线在主控制器和从机之间进行数据通信。一条是SCL(串行时钟线),另外一条是SDA(串行数据线),因为I2C这两条数据线是开漏输出的,所以需要接上拉电阻,总线空闲的时候SCL和SDA处于高电平。I2C总线标准模式下速度可以达到100Kb/S,快速模式下可以达到400Kb/S。
如果大家之前玩过51单片机,肯定对模拟I2C时序这个操作并不陌生,但是在Linux上,还需要我们继续来模拟I2C的时序吗,答案是不需要的,cpu会自带I2C控制器,有了这个I2C控制器之后,我们就不用在来取模拟时序了,我们只需要关系怎么把数据写到寄存器和怎么从寄存器读数据即可,具体的时序都是由I2C控制器来帮我们自动完成。
Linux把I2C控制器抽象成了一个i2c_adapter,我们只要来分配这个i2c_adapter,就可以得到一个l2C控制器。
我们可以先来体验一下,在Linux上操作l2C是多么的容易,我们可以先来看一下我们的系统里面都有哪些l2C的节点,这里以终结者的开发板为例。如下所示:
root@localhost:~# ls /dev/i2c-*
/dev/i2c-0 /dev/i2c-1 /dev/i2c-2
Linux有一个非常重要的概念叫一切皆文件,那么我们能不能在应用层通过open这些节点来操作l2C来跟外设I2C通信的芯片进行一个数据交流呢?当然是可以的,我们来一起看一下,这里我们以操作时钟芯片RX8010为例。
那我们怎么在应用层操作l2C呢?应用层操作l2C是以数据包进行交流的,所有我们在应用层就要进行封包的操作。
数据包对应的结构体是i2c_rdwr_ioctl_data
文件位置路径:include/uapi/linux/i2c-dev.h
/* This is the structure as used in the I2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data {
struct i2c_msg __user *msgs; /* 我们要发送的数据包的指针 */
__u32 nmsgs; /* 我们要发送的数据包的个数 */
};
然后是i2c_msg结构体的定义
文件位置路径:include/uapi/linux/i2c.h
struct i2c_msg {
__u16 addr; /* 从设备的地址 */
__u16 flags; /* 读写标志位,如果是1,则为读,反之为0,则为写 */
#define I2C_M_RD 0x0001 /* read data, from slave to master */
/* I2C_M_RD is guaranteed to be 0x0001! */
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
__u16 len; /* 为buf的大小,单位是字节,当flags为1是,buf就是我们要接收的数据,当flags为0时,就是我们要发送的数据。 */
__u8 *buf; /* pointer to msg data */
};