记录一下IIC,好记性不如烂笔头。
文章目录
一.I2C 简介
I2C 是很常见的一种总线协议, I2C是NXP公司设计的,I2C 使用两条线在主控制器和从机之间进行数据通信。一条是 SCL(串行时钟线),另外一条是 SDA(串行数据线),因为I2C这两条数据线是开漏输出的,所以需要接上拉电阻,总线空闲的时候 SCL 和 SDA 处于高电平。 I2C 总线标准模式下速度可以达到 100 Kb/s,快速模式下可以达到 400 Kb/s,在高速模式下可达到3.4 Mbit/s。一般通过I2C总线接口可编程时钟来实现传输速率的调整。
感兴趣的可以读《I2C总线规范和用户手册》
I2C 硬件框架
I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个从设备都会对应一个唯一的地址(可以从I2C器件的数据手册得知)。主从设备之间就通过这个地址来确定与哪个器件进行通信,在通常的应用中,我们把CPU带I2C总线接口的模块作为主设备,把挂接在总线上的其他设备都作为从设备。
⚫ 在一个芯片(SoC)内部,有一个或多个 I2C 控制器
⚫ 在一个 I2C 控制器上,可以连接一个或多个 I2C 设备。
I2C总线上可挂接的设备数量受总线的最大电容400pF限制,如果所挂接的是相同型号的器件,则还受器件地址的限制。一般I2C设备地址是7位地址(也有10位),地址分成两部分:芯片固化地址(生产芯片时候哪些接地,哪些接电源,已经固定),可编程地址(引出IO口,由硬件设备决定)。例如:某一个器件是7 位地址,其中1010xxx 高4位出厂时候固定了,低3位可以由设计者决定。则一条I2C总线上只能挂该种器件最少8个。如果7位地址都可以编程,那理论上就可以达到128个器件,但实际中不会挂载这么多。
⚫ I2C 总线只需要 2 条线:时钟线 SCL、数据线 SDA
⚫ 在 I2C 总线的 SCL、SDA 线上,都有上拉电阻
⚫ 总线数据长度:I2C总线上的主设备与从设备之间以字节(8位)为单位进行双向的数据传输。
如果玩过单片机,肯定对模拟I2C时序这个操作并不陌生(如果对IIC时序不清楚,可以自行补充I2C时序基础知识)。在Linux上,cpu会自带I2C控制器,有了这个I2C控制器之后,就不用模拟时序了,只需要关注怎么把数据写到寄存器和怎么从寄存器读数据即可,具体的时序都是由I2C控制器来自动完成。
I2C 软件框架
以 I2C 接口的存储设备 AT24C02 为例:
⚫ APP:
◼ 提出要求:把字符串"abcde"写入 AT24C02 地址 16 开始的地方
◼ 不关心底层实现的细节
◼ 只需要调用设备驱动程序提供的接口
⚫ AT24C02 驱动:
◼ 知道 AT24C02 要求的地址、数据格式
◼ 知道发出什么信号才能让 AT24C02 执行擦除、烧写工作
◼ 知道怎么判断数据是否烧写成功
◼ 构造好一系列的数据,发给 I2C 控制器
⚫ I2C 控制器驱动
◼ 根据 I2C 协议发出各类信号:I2C 设备地址、I2C 存储地址、数据
◼ 根据 I2C 协议判断
IIC 传输数据的格式
I2C基本时序信号
I2C 协议中数据传输的单位是字节,也就是 8 位。但是要用到 9 个时钟:前面 8 个时钟用来传输 8 数据,第 9 个时钟用来传输回应信号。传输时,先传输最高位(MSB)。注意:起始和结束信号总是由主设备产生。
⚫ 空闲状态:SCL和SDA都保持着高电平。
⚫ 开始信号(S):SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。在起始条件产生后,总线处于忙状态,由本次数据传输的主从设备独占,其他I2C器件无法访问总线。
⚫ 结束信号(P):SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据
⚫ 响应信号(ACK):接收器在接收到 8 位数据后,在第 9 个时钟周期,拉低SDA。每个字节传输完成后的下一个时钟信号,在SCL高电平期间,SDA为低,则表示一个应答信号。
⚫ SDA 上传输的数据必须在 SCL 为高电平期间保持稳定,SDA 上的数据只能在SCL 为低电平期间变化
写操作流程
⚫ 主芯片要发出一个 start 信号
⚫ 然后发出一个设备地址(用来确定是往哪一个芯片写数据),方向(读/写,0表示写,1 表示读)
⚫ 从设备回应(用来确定这个设备是否存在),然后就可以传输数据
⚫ 主设备发送一个字节数据给从设备,并等待回应
⚫ 每传输一字节数据,接收方要有一个回应信号(确定数据是否接受完成),然后再传输下一个数据
⚫ 数据发送完之后,主芯片就会发送一个停止信号
⚫ 下图:白色背景表示"主→从",灰色背景表示"从→主"
读操作流程
⚫ 主芯片要发出一个 start 信号
⚫ 然后发出一个设备地址(用来确定是往哪一个芯片写数据),方向(读/写,0表示写,1 表示读)
⚫ 从设备回应(用来确定这个设备是否存在),然后就可以传输数据
⚫ 从设备发送一个字节数据给主设备,并等待回应
⚫ 每传输一字节数据,接收方要有一个回应信号(确定数据是否接受完成),然后再传输下一个数据。
⚫ 数据发送完之后,主芯片就会发送一个停止信号
⚫ 下图:白色背景表示"主→从",灰色背景表示"从→主"
二. Linux下IIC读写
APP 可以通过两类驱动程序访问设备, 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)
Linux把I2C控制器抽象成了一个i2c_adapter,我们只要来分配这个i2c_adapter,就可以得到一个I2C控制器。
先来看一下我们的系统里面都有哪些I2C的节点。如下所示:
(base