I2C总线(基于IMX6ULL介绍)

I2C(Inter-Integrated Circuit BUS)是I2C BUS简称,中文为集成电路总线,是目前应用最广泛的总线之一,和IMX6ULL有些相关的是,恰巧该总线是NXP前身的PHILIPS设计。当前仍然是应用最广泛的总线协议之一。

1 通用I2C协议介绍

1)概述
I2C是一种串行通信总线,使用多主从架构,最初设计师为了让主板、嵌入式系统或手机用以连接低速周边设备而发展而来。在小数据量场合使用,有传输距离短,任意时刻只能有一个主机等特性。严格意义上讲,I2C应该是软硬件结合体,所以我们将分物理层和协议层来介绍该总线。(总线结构如下图)
在这里插入图片描述
2)物理层
特性1:半双工(非全双工)
两条总线线路:
SDA(串行数据线): 主芯片通过一根SDA线既可以把数据发给从设备,也可以从SDA上读取数据,连接SDA线的引脚里面必然有两个引脚(发送引脚/接受引脚),具体可以参考下图device端I2Cn_SDA(output/input)。
SCL(串行时钟线):同SDA的引脚电路结构一致,引脚的输出驱动与输入缓冲连在一起。其中输出为漏极开路的场效应管、输入缓冲为一只高输入阻抗的同相器。这样结构有如下特性:
 由于 SDA、SCL 为漏极开路结构,借助于外部的上拉电阻实现了信号的“线与”逻辑;
 引脚在输出信号的同时还将引脚上的电平进行检测,检测是否与刚才输出一致。为 “时钟同步”和“总线仲裁”提供硬件基础。
SDA和CLK连接线上连有两个上拉电阻,当总线空闲时,两根线均为高电平。连到总线上的任一器件输出的低电平,都将使总线的信号变低。(物理层结构如下图所示)
在这里插入图片描述

特性2:地址和角色可配置
每个连接到总线的器件都可以通过唯一的地址和其它器件通信,主机/从机角色和地址可配置,主机可以作为主机发送器和主机接收器。

特性3:多主机
IIC是真正的多主机总线,( IIC可以在通讯过程中,改变主机),如果两个或更多的主机同时请求总线,可以通过冲突检测和仲裁防止总线数据被破坏。

特性4:传输速率
传输速率在标准模式下可以达到100kb/s,快速模式下可以达到400kb/s。

特性5:负载和距离
节点的最大数量受限于地址空间以及总线电容决定。另外总电容也限制了实际通信距离只有几米。

3)协议层
a.数据有效性
I2C协议的数据有效性是靠时钟来保证的,在时钟的高电平周期内,SDA线上的数据必须保持稳定。数据线仅可以在时钟SCL为低电平时改变。
在这里插入图片描述
b.起始和结束条件
起始条件:当SCL为高电平的时候,SDA线上由高到低的跳变被定义为起始条件。
结束条件:当SCL为高电平的时候,SDA线上由低到高的跳变被定义为停止条件,要注意起始和终止信号都是由主机发出的,连接到I2C总线上的器件,若具有I2C总线的硬件接口,则很容易检测到起始和终止信号。
在这里插入图片描述
总线在起始条件之后,视为忙状态,在停止条件之后被视为空闲状态。
c.应答
每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据,从机应答主机所需要的时钟仍是主机提供的,应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答
d.数据帧格式
SDA线上每个字节必须是8位长,传输几个字节每个transfer是不限制的,每个字节后面必须跟一个ACK。数据首先用最高有效位(MSB)传输。
在这里插入图片描述

2. IMX6ULL的I2C控制器操作与寄存器介绍

IMX6ULL的I2C提供了标准I2C从服务器和主服务器的功能,I2C是设计与标准的NXP I2C总线协议兼容,所以上面的通用知识完全可以应用在IMX6ULL I2C的编程和控制。
故我们只要熟悉IMX6ULL I2C重点寄存器即可。
(1)I2C Memory Map
I2C包含5个16-bit 的寄存器
注意:寄存器在偏移量0x0002/0x0006/0x000A/0x000E作为保留位。
可以看到I2C1的入口地址为21A_0000,这个我们重点关注,后面做实验,编程会使用到。
在这里插入图片描述
(2)Register
 I2C Address Register (I2Cx_IADR)
在这里插入图片描述
地址寄存器,偏移量为0h。
 bit15-8为保留位即只读为0。
 bit7-1(ADR)位是I2C作为从机时的地址。从属模式是I2C的默认模式,这个地址是作为从机的相应地址,不能被软件复位。
 I2C Frequency Divider Register (I2Cx_IFDR)
在这里插入图片描述
分频寄存器,偏移量为4h。
 bit15-6位为保留位即只读为0。
 bit5-1 位为I2C时钟频率
注意:该值在传输过程中不应该改变,但是可以在之前改变。
I2C_IFDR提供了一个可编程的预分频器,用于时钟配置以进行比特率选择,寄存器不会被软件重置。
寄存器IC位设置计算方法如下:

I2C的时钟源来源于IPG_CLK_ROOT=66Mhz
PLL2 = 528 MHz
PLL2_PFD2 = 528 MHz
IPG_CLK_ROOT = (PLL2_PFD2 / ahb_podf )/ ipg_podf = (528 MHz/4)/2 = 66Mhz
PER_CLK_ROOT = IPG_CLK_ROOT/perclk_podf = 66 MHz/1 = 66 MHz
设置I2C的波特率为100K, 因此当分频值=66000000/100000=660.
参考Table 31-3. I2C_IFDR Register Field Values 中只有640对应的0x15最接近
在这里插入图片描述
即寄存器IFDR的IC位设置为0X15

 I2C Control Register (I2Cx_I2CR)
在这里插入图片描述
控制寄存器,偏移量为8h
 bit 15-8为保留位即只读为0。
 bit 7 为I2C使能位。(0 disable,1 enable)
 bit 6 为I2C中断使能位。(0 disable,1 enable)
 bit 5 为主/从模式选择位(0 slave mode,1 master mode )
 bit 4 为传输方向模式选择位 (0 receive mode,1 transmit mode)
 bit 3为应答使能位 (0 ACK , 1 NO ACK)
 bit 2 重复开始信号(0 no repeat start,1 Generates repeat start)
 bit 0 保留位

 I2C Status Register (I2Cx_I2SR)
在这里插入图片描述
状态寄存器,偏移量为Ch
 bit 15-8为保留位即只读为0。
 bit 7 数据传输状态位(0 传输中,1 传输完成)
 bit 6 I2C地址是否为从标识(0 不表示,1 是从机地址)
 bit 5 I2C总线忙状态标识位(0 空闲,1 忙 )
 bit 4 仲裁丢失位 (0 正常,1 仲裁丢失)
 bit 3 保留位
 bit 2从机读写标识位 (0 slave接收,主向从写 , 1 slave发送 主向从读)
 bit 1 I2C中断(0无中断等待, 1有中断等待)
 bit 0 应答信号标识位(0检测到ACK, 1检测到NO ACK)

 I2C Data I/O Register (I2Cx_I2DR)
在这里插入图片描述
数据寄存器,偏移量为10h
 bit 15-8为保留位即只读为0。
 bit 7-1 数据字节
注意:在主接收模式下,读取数据寄存器允许发生读取并初始化下一个字节被接收。在从模式下,相同功能需要编址后生效。
低8位为有效数据位,发送数据时将数据写到这个寄存器中,如果要接收时直接读取该寄存器中的数据。

3. I2C控制器编程_框架

之前的所有铺垫都是为了实现I2C通讯,所以怎么用代码实现也是尤为关键的一个问题。
 初始化
因为不使用中断服务函数模式,初始化代码非常简单,我们仅需要将I2CR(bit7) 置0后写入IFDR为0x15,设置波特率为100k。(具体计算方法参考 2. IMX6ULL的I2C控制器操作与寄存器介绍中关于分频寄存器),然后再使能I2C,将I2CR(bit7)置1 。
01 I2C_BASE->I2CR &= ~(1 << 7);
02 I2C_BASE->IFDR = 0x15;
03 I2C_BASE->I2CR |= (1<<7);
 读写操作
下面是是I2C的读写标准流程,可能实际使用时根据需求略有异同。
写寄存器的标准流程如下图:
在这里插入图片描述
 1.Master发起START
 2.Master发送I2C addr(7bit)和w操作0(1bit),等待ACK
 3.Slave发送ACK
 4.Master发送reg addr(8bit),等待ACK
 5.Slave发送ACK
 6.Master发送data(8bit),即要写入寄存器中的数据,等待ACK
 7.Slave发送ACK
 8.第6步和第7步可以重复多次,即顺序写多个寄存器
 9.Master发起STOP

读寄存器的标准流程如下图:
在这里插入图片描述

 1.Master发送I2C addr(7bit)和w操作1(1bit),等待ACK
 2.Slave发送ACK
 3.Master发送reg addr(8bit),等待ACK
 4.Slave发送ACK
 5.Master发起RESTART
 6.Master发送I2C addr(7bit)和r操作1(1bit),等待ACK
 7.Slave发送ACK
 8.Slave发送data(8bit),即寄存器里的值
 9.Master发送ACK
 10.第8步和第9步可以重复多次,即顺序读多个寄存器
 11. Master发送NO ACK表示读取完成,从机也不用发送ACK
 12. Master发送STOP

4. I2C控制器编程_中断

I2C控制器中和中断有关的寄存器如下: IIEN :I2C_I2CR(bit6)(0 disable I2C interrupt ,1 enable I2C interrupt) IIF:I2C_I2SR (bit1) (0 No I2C interrupt pending , 1 An interrupt is pending) 即中断使能位,中断状态位。 编码中在传送完1byte后可以通过判断IIF状态来确认ACK和传输完成。当然作为从机时,收到自己的地址后也可以进入中断。