I2C控制器
目录
I2C协议
起始信号
终止信号
应答信号
数据传输
单字节写时序
单字节读时序
I2C控制器
功能模式
引脚复用
时钟源
仲裁逻辑
仲裁方案
阶段一: 时钟同步(Clock Synchronization)
阶段二:数据仲裁(Data Arbitration)
中断
初始化顺序
生成起始信号
数据传输过程
生成终止信号
生成重启信号
I2C Memory Map
I2C寄存器
I2Cx_IADR寄存器
I2Cx_IFDR寄存器
I2Cx_I2CR寄存器
I2Cx_I2SR寄存器
I2Cx_I2DR寄存器
前言:
本文基于I.MX 6ULL处理器介绍I2C控制器,I2C控制器关键特征如下:
- 与 I2C 总线标准兼容;
- 多主机操作(支持多设备同时作为主机竞争总线);
- 可通过软件编程选择 64 种不同的串行时钟频率之一(灵活适配不同通信速率需求);
- 软件可配置的应答位(ACK/NACK 可按需设置);
- 中断驱动的逐字节数据传输(每传输 1 字节触发一次中断,便于软件处理);
- 仲裁丢失中断(多主机竞争总线失败时触发),并自动从主机模式切换为从机模式;
- 寻址识别中断(从机被寻址时触发);
- 启动(Start)和停止(Stop)信号的生成 / 检测;
- 重复启动(Repeated Start)信号的生成;
- 应答位(ACK)的生成 / 检测;
- 总线繁忙检测(判断 I2C 总线是否被占用);
I2C协议
I2C总线具有两根通信线,其中数据线SDA(Serial Data) 用于收发数据,时钟线SCL (Serial Clock) 用于通信双方时钟同步;
I2C总线为多主机总线,挂载于I2C总线的器件分为主机与从机,主机有权发起和结束一次通信,从机只能被主机呼叫;
结论:
1. 总线空闲时,SCL 与 SDA 皆为高电平;
2. 挂载于I2C总线的设备具有唯一的地址;
3. 任何时刻只能存在一个主机;
4. 起始信号只能由主机产生;5. 终止信号只能由主机产生;
线与逻辑:
- 总线电平为高电平,当且仅当所有设备都释放总线(输出高阻态,由上拉电阻拉至高电平);
- 只要有一个设备拉低总线(输出低电平),总线电平为低电平;
起始信号
起始信号:SCL高电平期间,SDA从高电平切换到低电平;
终止信号
终止信号:SCL高电平期间,SDA从低电平切换到高电平;
应答信号
应答信号(ACK) : 在单字节数据传输后的第9个时钟周期内,SCL保持低电平期间,SDA线被接收设备主动拉低;
数据传输
- 当时钟线SCL低电平期间,允许数据线SDA上的信号发生变化,此时发送方可向数据线SDA写入一位数据;
- 当时钟线SCL高电平期间,不允许数据线SDA上的信号发生变化,此时接收方从数据线SDA读取一位数据;
单字节写时序
1. 主机发送起始信号标志通信开始;
2. 主机发送 I2C 设备地址,由于 I2C 器件具有唯一的设备地址,通过发送具体的设备地址来决定访问具体的I2C设备,主机发送 I2C 设备地址, 8 位数据中高 7 位是设备地址,最后 1 位是读写位,1 表示读操作,0 表示写操作;
示例:假设从机地址为0x1E,二进制为
0001 1110
,写操作最低位为0,则写操作的地址字节为:(0x1E << 1) | 0 = 0x3C
,二进制为0011 1100
;
3. WRITE代表读写位, 0 表示写操作,1 表示读操作;
4. 从机发送应答信号ACK;
5. 发送重复启动信号,若直接发送寄存器地址,导致从机无法区分寄存器地址 与 新的从机地址,从机的逻辑是只要总线被占用,主机可能随时发送新的从机地址来切换目标设备;
例如:
- 主机可能先和从机 A 通信(发 A 的地址),然后不释放总线,直接发从机 B 的地址(切换到 B);
重复起始信号(Repeated Start) 的核心作用是 在不释放总线的前提下,切换到当前从机的下一个通信阶段,保证写操作的连续性与原子性;
6. 发送待写入数据的寄存器地址,从机如何区分寄存器地址与数据,从机内部通过状态切换,结合已完成的通信阶段来解析字节意义,关键分为两步:
一 从机地址(写) 被确认后,下一字节为寄存器地址
- 主机先发送从机地址 + 写位(R/W=0):表示 主机要向该从机写入数据;
- 从机若地址匹配,会返回ACK 应答,此时,从机内部状态机切换为 等待接收寄存器地址;
- 因此,从机明确:在从机地址 ACK之后,主机发送的第一个字节必然是寄存器地址( I2C 写操作的协议约定);
二 寄存器地址 被确认后,下一字节为待写入的数据
- 主机发送寄存器地址,从机解析后返回ACK 应答,此时,从机内部状态机切换为 等待接收写入数据;
- 因此,从机明确:在 寄存器地址 ACK之后,主机发送的下一个字节必然是要写入该寄存器的数据(I2C 写操作的协议约定);
7. 从机发送的 ACK 应答信号;
8. 发送要写入寄存器的数据;
9. 从机发送应答信号ACK ;
10. 主机发送停止信号;
单字节读时序
- 主机发送起始信号;
- 主机发送要读取的 I2C 从设备地址。
- 读写控制位,因为向 I2C 从设备发送待读取的寄存器地址,所以该位为写信号;
- 从机发送的 ACK 应答信号;
- 重新发送 START 信号;
- 主机发送要读取的寄存器地址;
- 从机发送的 ACK 应答信号;
- 重新发送 START 信号;
- 重新发送要读取的 I2C 从设备地址;
- 读写控制位,因为下阶段为从 I2C 从设备寄存器中读取数据,所以该位为读信号;
- 从机发送的 ACK 应答信号;
- 从 I2C 从设备寄存器中读取的数据;
- 主机发出NACK信号,表示读取完成,从机不再发送数据;
- 主机发出 STOP 信号,停止 I2C 通信;
若主机想读取从机某个特定寄存器的数据,必须先让从机知道 要读哪个寄存器, 但读操作的通信方向是 从机→主机,主机无法在 读请求 中直接传递寄存器地址,因此 I2C协议设计了先写后读 的流程:
- 主机先发送 从机地址 + 写位(R/W=0):这一步骤为 伪写操作,目的是向从机传递要读取的寄存器地址;
- 从机应答(ACK)后,主机发送目标寄存器地址,从机再次应答(ACK),此时从机已记录 主机要读 此寄存器;
- 主机发送重复起始信号(Sr)(不释放总线,保持通信连续性);
- 主机再次发送 从机地址 + 读位(R/W=1):这一步骤为实际的读请求,告诉从机现在要读取从机刚才记录的寄存器地址对应的数据;
- 从机应答(ACK)后,开始通过 SDA 线输出目标寄存器的数据,主机接收数据;
I2C控制器
功能模式
- 标准模式(Standard mode):最高速率 100 kbit/s,兼容性极佳(几乎所有 I2C 设备都支持),但速度较慢,适用于对吞吐量要求不高的场景;
- 快速模式(Fast mode):最高速率 400 kbit/s,适用于对速度敏感的场景(如高速传感器、短距离高吞吐量通信),但需注意:快速模式对SDA/SCL 引脚的驱动能力要求更高,且必须确保从机设备支持快速模式,否则可能通信失败;
引脚复用
UART4_TX_DATA引脚可以复用为I2C1_SCL,UART4_RX_DATA引脚可以复用为I2C1_SDA引脚,配置引脚复用寄存器如下:
IOMUXC_SW_MUX_CTL_PAD_UART4_TX_DATA寄存器
IOMUXC_SW_MUX_CTL_PAD_UART4_RX_DATA寄存器
时钟源
假定CSCMR寄存器PERCLK_PODF位配置为1分频,则IPG_CLK_ROOT=PERCLK_CLK_ROOT=66MHz
Peripheral clock:用于外设总线寄存器的读写,当 CPU 要访问 I2C 外设的寄存器时,需要此时钟来同步操作,确保寄存器读写的正确性;
Module clock:I2C 的功能时钟。I2C 的SCL 的频率诞生于模块时钟,模块时钟和外设时钟是同步的,对于快速模式(400kbps),模块时钟的最小频率应该是 12.8MHz,这样才能实现 400kbit/s 的操作;
仲裁逻辑
I2C 总线为共享资源,若多个主设备同时驱动总线,会导致数据传输出错,但是I2C 总线支持多个设备可作为主机发起通信,当多个主设备同时尝试控制总线时,仲裁(Arbitration) 是解决冲突的机制:通过硬件逻辑决定 哪个主设备继续控制总线,哪个主设备放弃控制总线;
仲裁方案
I2C 仲裁分为时钟同步和数据仲裁两个阶段,共同确保总线控制权的公平分配;
阶段一: 时钟同步(Clock Synchronization)
当多个主设备同时请求总线时,总线的 SCL 时钟由所有竞争设备的时钟协商生成:
- 低电平时段:取所有设备中最长的低电平时段(因为 I2C 是开漏 / 开集电极输出,只要有一个设备拉低 SCL,总线就保持低电平。因此,低电平持续时间由 “最慢” 的设备决定)。
- 高电平时段:取所有设备中最短的高电平时段(当所有设备释放 SCL,上拉电阻将总线拉至高。此时 “最快” 完成高电平计数的设备会先拉低 SCL,因此高电平持续时间由 “最快” 的设备决定)。
时钟同步的本质是:让所有主设备的 SCL 时序 “对齐”,为后续数据传输提供统一的时钟基准。
阶段二:数据仲裁(Data Arbitration)
时钟同步后,主设备开始通过 SDA 传输数据,数据仲裁是逐位进行,核心逻辑是线与逻辑(开漏输出+ 上拉电阻)
- 每个主设备在发送每一位时,会同时检测 SDA 的实际电平是否与自己发送的电平一致。
- 若主设备 A 发送高电平,但检测到 SDA 实际是低电平(说明有其他主设备 B 发送了低电平),则主设备 A 失去仲裁权。
- 失去仲裁的设备会:
- 立即切换为从机接收模式(停止主动驱动 SDA,改为被动接收);
- 硬件设置状态寄存器的仲裁丢失标志,供软件查询;
- 不生成停止条件(避免干扰总线,让胜利的主设备继续通信);
中断
I2C模块仅产生一个中断,可通过设置
I2C_I2CR
寄存器的[IIEN]
位(中断使能位)来使能该中断,在以下任意一种情况下会触发中断:
- 一个字节传输完成(中断在第 9 个时钟的下降沿被置位);
- 在从机接收模式下,接收到与自身特定地址匹配的地址;
- 失去仲裁权(Arbitration is lost);
初始化顺序
- 设置数据采样率(配置
I2C_IFDR
寄存器的[IC]
位),以从系统总线时钟生成 SCL 频率;- 更新
I2C_IADR
寄存器中的地址,定义其从机地址(地址范围为 0 到 0x7F);- 设置
I2C_I2CR
寄存器的[IEN]
位(I2C 使能位),以启用 I2C 总线接口系统;- 修改
I2C_I2CR
寄存器的位,选择主 / 从模式、发送 / 接收模式,以及是否使能中断;
生成起始信号
I2C 支持多主机共享总线,因此发送起始信号前必须检测总线状态:
I2C_I2SR[IBB]
(总线忙标志):IBB=1
表示总线正被占用(其他主机在通信),IBB=0
表示总线空闲;- 只有
IBB=0
时,当前主机才能发起始信号(Start), 否则强行发送会引发总线冲突,导致仲裁失败;- 终止信号(stop) 与下一个起始信号 (Start) 之间的空闲时间(Bus Free Time)由硬件自动生成,无需软件额外延时;
- 发送设备地址时,主机将发送的数据(从机地址 + 读写位)需先写入I2C_I2DR寄存器;
起始信号由硬件自动产生,触发条件是:
- 软件配置 I2C 为主机模式(通过
I2C_I2CR
的MSTA
位置位);- 总线空闲(
IBB = 0
);- 软件向
I2C_I2DR
写入第一个字节(从机地址 + 读写位);
数据传输过程
传输完成的双重标志(
ICF
+IIF
)
ICF
(数据传输位):单字节传输完成时硬件自动置位,表明一个字节的收发已完成,需通过读 / 写I2C_I2DR
清除(接收时读、发送时写);IIF
(中断状态位):单字节传输完成时硬件自动置位,若IIEN
使能则触发中断,需软件显式清除(写0
到I2C_I2SR[IIF]
),否则中断会持续触发;
主机发送模式→主机接收模式
当主机读取从机的寄存器中的数据时,若从机已经获得主机要读取的寄存器地址,流程如下:
- 先发送读地址:主机需先发送 从机地址 + 读位(LSB=1),告诉从机读取数据—— 这一步必须工作在发送模式(
MTX=1
);- 再接收从机数据:从机应答地址后,会开始向主机发送数据 —— 这一步主机必须切换到接收模式(
MTX=0
),接收模式仅通过输入电路采样 SDA 上的电平;当主机从发送模式切换到接收模式(
MTX=0
)后,硬件状态机处于 等待接收启动 的初始状态;此时:
- 若不执行 "虚拟读取",硬件不会启动 "采样 SDA→锁存数据"的流程,从机发送的数据会被忽略。
- 执行 "虚拟读取" 后,硬件会认为 "软件已准备好接收数据",从而激活采样逻辑,开始接收从机发送的第一个字节;
当主机发送完从机地址 + 读位,主机需切换为接收模式并且进行虚拟读取,方案如下:
- 清除
I2C_I2CR[MTX]
(改为接收模式);- 读取
I2C_I2DR
(虚拟读取,触发接收数据);
生成终止信号
主机接收模式终止信号生成方案:
假设主机需接收 3 个字节后终止传输,流程如下:
- 主机发送起始信号→发送从机地址 + 读位→从机 ACK→进入接收模式;
- 接收第 1 个字节→设置
I2C_I2CR[TXAK] = 0
(发送ACK)→从机继续发送第 2 个字节;- 接收第 2 个字节→设置
I2C_I2CR[TXAK] = 1
(发送 NACK)→从机发送第 3 个字节;- 接收第 3 个字节→硬件自动生成停止信号→从机检测到 NACK + 停止信号,终止发送;
注意: 主机接收第
N-1
字节时,需提前配置TXAK=1
(NACK),让从机在发送第N
字节后收到 NACK,从而停止发送;主机发送模式终止信号生成方案:
假设主机发送一个字节后终止传输,流程如下:
- 从机接收寄存器地址后,返回 ACK;
- 硬件置位
ICF
(地址传输完成),软件检测到ICF=1
后,向I2C_I2DR
写入单字节数据 0xAB(硬件自动清除ICF
);- 硬件逐位发送数据,从机接收后返回 ACK;
- 硬件再次置位
ICF
(数据传输完成);- 硬件检测到
ICF=1
(表示当前字节已发送完成且从机发送ACK)且I2C_I2DR
寄存器在ICF=1
后的一个 SCL 周期内未被软件写入新数据,硬件判定当前字节是最后一个字节;- 硬件自动生成停止信号(P);
生成重启信号
向I2C 控制寄存
I2C_CR
的RSTA
位写 1,触发硬件自动生成重启信号;
在设置
I2C_I2CR[RSTA]
位之后,且在写入I2C_I2DR
寄存器之前,至少有两个模块时钟周期的延迟,该模块时钟的最大可能时钟周期为 78 ns;
I2C Memory Map
I2C寄存器
I2Cx_IADR寄存器
bit[7:1]: 存储I2C设备作为从机时的的响应地址,当总线上的主机发送地址时,从机将总线地址与
ADR
字段比较,若匹配则触发从机模式;
I2Cx_IFDR寄存器
I2C_IFDR
(I2C Frequency Divider Register)是 I2C 时钟分频寄存器,通过配置其IC
字段选择分频系数,将PERCLK_ROOT
(外设根时钟)分频为 I2C 模块的工作时钟,最终决定 SCL 频率;
假设IPG_CLK_ROOT=PERCLK_ROOT=66MHz,选择通信速度为标准模式(100kbit/s),IC字段配置方案如下:
计算分频系数: 分频系数 =
PERCLK_ROOT
/ SCL 频率 =66MHz/100kHz=660;匹配分频系数与 IC 字段: 查阅
I2C_IFDR
分频表,找到最接近 660 的分频系数,表中IC=0x15
对应分频系数640
(最接近 660);验证实际 SCL 频率: 实际 SCL = 66MHz/640=103.125kHz,与 100kHz 的误差在 I2C 标准模式容差(±5%)范围内,可正常通信;
I2Cx_I2CR寄存器
bit7:IEN位,I2C 模块使能位 ,若配置为
1
表示使能 I2C 模块,同时控制模块的软件复位(写0
会触发内部复位);若配置为0
表示禁用 I2C 模块;bit6:IIEN(I2C Interrupt Enable),中断使能位,若配置为
1
表示使能 I2C 中断,当状态寄存器I2C_I2SR[IIF]
(中断标志)置1
时,触发中断;若配置为0
表示禁用中断,但I2C_I2SR[IIF]
仍会正常置1
(仅不触发中断);bit5:MSTA(Master/Slave Mode Select),主从模式选择位,
- 置 1:切换为主模式(Master Mode);
- 置
0
:切换为从模式(Slave Mode);bit4: MTX(Transmit/Receive Mode Select),收发模式选择位,决定主机 / 从机模式下的传输方向;
- 主机模式:
- 置
1
:发送模式(Transmit,主机向从机写数据);- 置
0
:接收模式(Receive,主机从从机读数据);- 从机模式:
SRW=1
(主机读从机):从机需发送数据,MTX=1
(发送模式);SRW=0
(主机写从机):从机需接收数据,MTX=0
(接收模式);bit3:TXAK(Transmit Acknowledge Enable),应答使能位,用于控制 I2C 总线在第 9 个时钟周期的 SDA 电平:
- 置
0
:发送应答(ACK)(SDA 拉低);- 置
1
:发送非应答(NACK)(SDA 保持高);bit2: RSTA(Repeat Start),用于生成重复起始信号:
- 置
1
:生成重复起始信号(Repeated Start);- 置
0
:无操作;
I2Cx_I2SR寄存器
bit7:ICF(Data Transferring Bit) ,数据传输完成标志
- 功能:指示一个字节的传输状态
0
:传输进行中(字节未发送 / 接收完成);1
:传输完成(最后一个字节的第 9 个时钟下降沿时置1
);
bit6:IAAS(I2C Addressed as Slave Bit),从机寻址标志
- 功能:指示 I2C 是否被寻址为从机
0
:未被寻址(总线无匹配自身地址的传输);1
:被寻址为从机(自身地址I2C_IADR
与主机发送的地址匹配);
bit5:IBB(I2C Bus Busy Bit),总线忙闲标志
- 功能:指示 I2C 总线的全局状态
0
:总线空闲(检测到 Stop 信号时清除);1
:总线忙(检测到 Start 信号时置1
);
bit4:IAL(Arbitration Lost),仲裁丢失标志
- 功能:指示 I2C 总线仲裁竞争失败
0
:未丢失仲裁(总线控制权正常)。1
:仲裁丢失(多主机竞争总线失败,需软件写0
清除)
bit2:SRW(Slave Read/Write), 从机读 / 写方向标志
- 功能:仅当
IAAS=1
(被寻址为从机)时有效,表示主机发送的地址中 R/W 位
0
:从机接收(主机写从机)。1
:从机发送(主机读从机)
bit1:IIF(I2C Interrupt),中断标志
- 功能:指示 I2C 中断请求状态:
0
:无挂起中断;1
:中断挂起(需软件写0
清除);
bit0:RXAK(Received Acknowledge), 接收应答标志
- 功能:反馈总线应答阶段的结果:
0
:收到 ACK ;1
:收到 NACK;