1. I2C 框架结构
1.1 I2C 硬件框架
I2C 总线拓扑图
⚫
在一个芯片
(SoC)
内部,有一个或多个
I2C
控制器
⚫
在一个
I2C
控制器上,可以连接一个或多个
I2C
设备
⚫
I2C
总线只需要
2
条线:时钟线
SCL
、数据线
SDA
⚫
在
I2C
总线的
SCL
、
SDA
线上,都有上拉电阻
1.2 I2C 软件框架
以 I2C 接口的存储设备 AT24C02 为例:
⚫
APP
:
◼ 提出要求:把字符串
"www.100ask.net"
写入
AT24C02
地址
16
开始的地方
◼ 它是大爷,不关心底层实现的细节
◼ 它只需要调用设备驱动程序提供的接口
⚫
AT24C02
驱动:
◼ 它知道
AT24C02
要求的地址、数据格式
◼ 它知道发出什么信号才能让
AT24C02
执行擦除、烧写工作
◼ 它知道怎么判断数据是否烧写成功
◼ 它构造好一系列的数据,发给 I2C
控制器
⚫
I2C
控制器驱动
◼ 它根据
I2C
协议发出各类信号:
I2C
设备地址、
I2C
存储地址、数据
◼ 它根据
I2C
协议判断
1.3 我们讲什么
1.3.1 对于 Linux I2C 结构
从上到下:
⚫
先讲
I2C
协议
⚫
APP
可以通过两类驱动程序访问设备
◼ I2C
设备自己的驱动程序
◼ 内核自带的
i2c-dev.c
驱动程序,它是
i2c
控制器驱动程序暴露给用户空间的驱动程序(i2c-dev.c)
⚫
I2C Device Driver
◼ I2C
设备自己的驱动程序
◼ 内核自带的
i2c-dev.c
驱动程序,它是
i2c
控制器驱动程序暴露给用户空间的驱动程序(i2c-dev.c)
⚫
I2C Controller Driver
◼ 芯片
I2C
控制器的驱动程序
(
称为
adapter)
◼ 使用
GPIO
模拟的
I2C
控制器驱动程序
(i2c-gpio.c)
1.3.2 对于单片机/裸机
从上到下:
⚫
先讲
I2C
协议
⚫
APP
⚫
I2C Device Driver
⚫
I2C Controller Driver(
也被称为
adapter)
2 I2C 协议
2.1 硬件连接
I2C 在硬件上的接法如下所示,主控芯片引出两条线
SCL,SDA
线,在一条 I2C 总线上可以接很多
I2C
设备,我们还会放一个上拉电阻(放一个上拉电阻的原因以后我们再说)。
2.2 传输数据类比
怎么通过 I2C
传输数据,我们需要把数据从主设备发送到从设备上去,也需要把数据从从设备传送到主设备上去,数据涉及到双向传输。
举个例子:
体育老师:可以把球发给学生,也可以把球从学生中接过来。
⚫
发球:
◼ 老师:开始了
(start)
◼ 老师:
A
!我要发球给你!
(
地址
/
方向
)
◼ 学生
A
:到!
(
回应
)
◼ 老师把球发出去(传输)
◼ A
收到球之后,应该告诉老师一声(回应)
◼ 老师:结束(停止)
⚫
接球:
◼ 老师:开始了
(start)
◼ 老师:
B
!把球发给我!
(
地址
/
方向
)
◼ 学生
B
:到!
◼ B
把球发给老师(传输)
◼ 老师收到球之后,给
B
说一声,表示收到球了(回应)
◼ 老师:结束(停止)
我们就使用这个简单的例子,来解释一下
IIC
的传输协议:
⚫
老师说开始了,表示开始信号
(start)
⚫
老师提醒某个学生要发球,表示发送地址和方向
(address/read/write)
⚫
老师发球
/
接球,表示数据的传输
⚫
收到球要回应:回应信号
(ACK)
⚫
老师说结束,表示
IIC
传输结束
(P)
2.3 IIC 传输数据的格式
2.3.1 写操作
⚫
主芯片要发出一个
start
信号
⚫
然后发出一个设备地址
(
用来确定是往哪一个芯片写数据
)
,方向
(
读
/
写,
0
表示写,1
表示读
)
⚫
从设备回应
(
用来确定这个设备是否存在
)
,然后就可以传输数据
⚫
主设备发送一个字节数据给从设备,并等待回应
⚫
每传输一字节数据,接收方要有一个回应信号(确定数据是否接受完成
)
,然后再传输下一个数据。
⚫
数据发送完之后,主芯片就会发送一个停止信号。
⚫
下图:白色背景表示
"
主
→
从
"
,灰色背景表示
"
从
→
主
"
2.3.2 读操作
流程如下:
⚫
主芯片要发出一个
start
信号
⚫
然后发出一个设备地址
(
用来确定是往哪一个芯片写数据
)
,方向
(
读
/
写,
0
表示写,1
表示读
)
⚫
从设备回应
(
用来确定这个设备是否存在
)
,然后就可以传输数据
⚫
从设备发送一个字节数据给主设备,并等待回应
⚫
每传输一字节数据,接收方要有一个回应信号(确定数据是否接受完成
)
,然后再传输下一个数据。
⚫
数据发送完之后,主芯片就会发送一个停止信号。
下图:白色背景表示
"
主
→
从
"
,灰色背景表示
"
从
→
主
"
3 I2C 信号
I2C 协议中数据传输的单位是字节,也就是
8
位。但是要用到
9
个时钟:前面 8
个时钟用来传输
8
数据,第
9
个时钟用来传输回应信号。传输时,先传输最高位(MSB)
。
⚫
开始信号(
S
):
SCL
为高电平时,
SDA 由
高电平向低电平跳变,开始传送数据。
⚫
结束信号(
P
):
SCL
为高电平时,
SDA
由低电平向高电平跳变,结束传送数据。
⚫
响应信号
(ACK)
:接收器在接收到
8
位数据后,在第
9
个时钟周期,(从设备)拉低
SDA
⚫
SDA
上传输的数据必须在
SCL
为高电平期间保持稳定,
SDA
上的数据只能在SCL 为低电平期间变化
I2C 协议信号如下(前半部分数据是发送地址位和方向,后半部分是数据,发送原理一样):
在 SCL 为高电平时,SDA 拉高,读取到 1;在SCL为高电平时,SDA拉低,读取到0。
4 协议细节
⚫
如何在
SDA
上实现双向传输?
◼ 主芯片通过一根
SDA
线既可以把数据发给从设备,也可以从
SDA
上读取数据,连接 SDA
线的引脚里面必然有两个引脚(发送引脚
/
接受引脚)。
⚫
主、从设备都可以通过
SDA
发送数据,肯定不能同时发送数据,怎么错开时间?在 9
个时钟里:
◼ 前
8
个时钟由主设备发送数据的话,第
9
个时钟就由从设备发送数据;
◼ 前
8
个时钟由从设备发送数据的话,第
9
个时钟就由主设备发送数据。
⚫
双方设备中,某个设备发送数据时,另一方怎样才能不影响
SDA
上的数据?
◼ 设备的
SDA
中有一个三极管,使用开极
/
开漏电路
(
三极管是开极,
CMOS 管是开漏,作用一样)
,如下图: