i.MX6ULL 有 4 路 I2C 外设:I2C1~I2C4,硬件为 I2C‑master,裸机无 Linux I2C 驱动,直接操作寄存器,支持标准模式 100K、快速模式 400K。最快典型模式3.4M
硬件引脚(复用为 I2C 功能,开漏输出,必须外部上拉)
- I2C1:UART4_TX(SCL)、UART4_RX(SDA)
- I2C2:EPDC_SDCE0(SCL)、EPDC_GDSP(SDA)
- I2C3:GPIO1_IO06(SCL)、GPIO1_IO07(SDA)
- I2C4:CSI_DATA00(SCL)、CSI_DATA01(SDA)
- I2C 硬件特性:片上 I2C 控制器是开漏,引脚必须配置为 I2C 复用功能,不能配置 GPIO 输出模拟 I2C(硬件控制器自动产生 SCL/SDA 时序),外部必须 4.7K 上拉电阻。
寄存器列表如下:
| 寄存器 | 作用 |
|---|---|
| I2Cx_IADR | 从机地址寄存器,master 模式不用 |
| I2Cx_IFDR | 分频寄存器,设置 I2C 波特率 |
| I2Cx_I2CR | I2C 控制寄存器:使能、主机模式、发送 / 接收、应答 |
| I2Cx_I2SR | 状态寄存器:中断、总线忙、仲裁丢失、应答 ACK、传输完成 |
| I2Cx_I2DR | 数据收发寄存器,写 = 发送,读 = 接收 |
主机向从机发数据流程:
- 等待 IBB=0,总线空闲,保证总线没有其它通信
- 配置 I2CR 寄存器,发起起始信号
- 写从机地址 + 写位到 I2DR
- 等待 IIF 置位,字节传输完成;软件清零 IIF;检查 ACK
- 写寄存器地址
0x01到 I2DR - 等待 IIF 置位,字节传输完成;软件清零 IIF;检查 ACK
- 写要发送的数据
150到 I2DR - 等待 IIF 置位,字节传输完成;软件清零 IIF;检查 ACK
- 配置 I2CR 产生停止信号
- 等待 IBB=0,等待停止条件完成,总线回到空闲状态
写时序的大致流程

主机从|从机读取数据流程:
- 等待 IBB=0,确认总线空闲
- I2CR 配置,发起起始信号
- I2DR 写入从机写地址和写为
- 等待 IIF=1,传输完成;清 IIF;检查 ACK
- I2DR 写入寄存器地址
0x01 - 等待 IIF=1,传输完成;清 IIF;检查 ACK
- I2CR 配置发起重复起始 Restart
- I2DR 写入从机地址
|1读操作标志位 - 等待 IIF=1,传输完成;清 IIF;检查 ACK
- 读取 I2DR 寄存器得到从机返回数据;配置主机输出 NACK
- 等待 IIF=1;清 IIF
- I2CR 配置产生停止信号
- 等待 IBB=0,等待总线空闲,本次读事务结束
读从机的大致流程

起始信号与停止信号

1. 起始信号 S(Start Condition)
总线空闲状态:SDA = 高,SCL = 高,IBB=0(总线空闲)
- SCL 保持高电平;
- SDA 由高电平 → 低电平跳变(下降沿);
- 起始条件生成后,硬件自动置 IBB=1(总线忙);
- 随后主机拉低 SCL,开始输出字节(从机地址字节)。
2. 停止信号 P(Stop Condition)
字节 + ACK 传输全部完成之后,生成停止
- SCL 先拉高到高电平;
- SDA 由低电平 → 高电平跳变(上升沿);
- Stop 条件完成,硬件自动清除 IBB=0(总线释放,回到空闲)
3. 重复起始信号 Sr(Repeated Start,读寄存器流程要用)
⚠️ 重点:不发送 Stop,IBB 保持 = 1,总线一直处于忙状态!
- 当前字节 + ACK 传输完成,SCL 回到高;
- SDA 高→低跳变(和普通 Start 电平变化完全一样);
- 全程不置 Stop,IBB 保持 1,不会释放总线;
- 之后直接发送读地址字节。
- 用途:寄存器读操作,写完寄存器地址后用 Restart 切换读写方向,不释放总线
Restart 阶段不能等待 IBB 清零,一旦 IBB 变成 0,就等于产生了 Stop,本次事务直接结束。