1. I2C接口寄存器全景解析:从数据收发到中断管理的核心逻辑
搞嵌入式开发,I2C总线绝对是绕不开的坎。它只有两根线,SDA数据线和SCL时钟线,结构简单,但真要把通信调稳定、调高效,里面的门道可不少。很多人调I2C,要么卡在时钟配置上,通信速率死活不对;要么就是中断处理没弄明白,数据丢得莫名其妙。我这些年踩过的坑,不少都跟没吃透芯片手册里那些寄存器有关。今天,我就以TI的TM4C1292NCZAD这款MCU的I2C模块为例,把几个最核心的寄存器掰开揉碎了讲清楚,特别是数据寄存器、时钟配置寄存器和中断管理那一套。你理解了这套逻辑,再去看其他厂家的芯片,基本都能触类旁通。
I2C通信的本质,是主设备通过控制SCL时钟线,在SDA数据线上与从设备进行有序的“问答”。这个过程完全由主控制器内部的寄存器状态机驱动。作为开发者,我们的工作就是通过配置这些寄存器,告诉控制器:“以多快的速度(时钟)去和谁(地址)通信,传什么数据(数据),通信过程中出了什么状况(状态)要及时通知我(中断)”。听起来简单,但每个寄存器位背后的设计意图和联动关系,才是写出稳定驱动代码的关键。这篇文章适合已经了解I2C基础协议,但在实际寄存器操作和驱动编写中遇到瓶颈的嵌入式工程师或爱好者,我会结合手册说明和实际调试经验,带你深入寄存器层面,掌握高效、可靠的I2C驱动开发方法。
2. 数据收发核心:I2C主控数据寄存器(I2CMDR)深度剖析
数据寄存器是I2C通信的“出入口”,所有要发送和接收的字节都经过这里。在TM4C1292NCZAD中,这个寄存器是I2CMDR,偏移地址为0x008。手册里有一句特别重要的提示:“This register is read-sensitive.”,这句话可不能轻易放过。
2.1 寄存器位域与“读敏感”特性
I2CMDR寄存器只有低8位(Bit 7:0)是有效的DATA域,用于读写数据。高24位是保留位(Reserved)。所谓“读敏感”,指的是在某些特定的操作模式下,读取这个寄存器的行为本身会触发硬件状态机的动作。最常见的情况是在单次字节传输模式下(即BURST位未启用),当主控制器处于接收状态(Master Receive)时,读取I2CMDR寄存器的操作,除了会返回接收到的数据,还可能作为硬件确认“软件已取走数据”的信号,进而推动状态机进入下一个状态(例如准备接收下一个字节或结束传输)。
这就引出了一个关键的操作禁忌:不要在非接收状态下,或者在不清楚当前状态机位置时,随意读取I2CMDR寄存器。错误的读取可能会干扰状态机,导致通信异常。正确的做法是,通过查询主控状态寄存器(例如I2CMCS,虽然输入资料未提供,但它是实际编程中必不可少的)来确认“数据已就绪”(例如BUSY位为0且ERROR位为0),然后再进行读取操作。
2.2 突发(BURST)模式下的数据流切换
手册明确指出:“If the BURST bit is enabled in the I2CMCS register, then the I2CFIFODATA register is used for the current data transmit or receive value and this register is ignored.” 这是理解高效数据传输的关键。
在单字节模式下,每个字节的收发都需要软件干预:写数据到I2CMDR启动发送,或从I2CMDR读取接收到的数据。这种方式在低速或零星数据传输时没问题,但效率低下。而突发模式(BURST)则是为连续数据传输设计的。一旦启用,数据流会自动切换到专用的FIFO数据寄存器I2CFIFODATA。此时,I2CMDR寄存器被旁路,软件的核心任务变成了管理FIFO:在发送时,确保FIFO不为空;在接收时,及时从FIFO中取走数据。
这里有一个重要的实操心得:启用BURST模式前,必须先正确配置突发长度寄存器I2CMBLEN。该寄存器(偏移0x030)的CNTL字段(低8位)必须设置为一个非零值,指明本次突发传输的总字节数。如果此值为零却启用BURST,硬件会报错。在传输过程中,你可以通过读取I2CMBCNT寄存器(偏移0x034)来查询剩余的字节数,这在调试传输意外中断(如从机发送NACK)时非常有用,它能告诉你成功传输了多少个字节。
2.3 数据收发的软件流程与注意事项
一个稳健的单字节发送流程通常如下:
- 检查总线是否空闲(通过状态寄存器)。
- 写入从机地址和读写位到相应寄存器(通常是
I2CMSA,地址寄存器)。 - 配置控制寄存器(
I2CMCS)发送起始(START)信号和地址。 - 等待操作完成(查询状态或等待中断)。
- 确认收到从机应答(ACK)后,将待发送数据写入
I2CMDR。 - 再次配置控制寄存器发送数据。
- 循环步骤4-6直至发送完毕,最后发送停止(STOP)信号。
对于接收流程,在发送完地址(读方向)后,需要将控制器切换为接收模式,然后通过读取I2CMDR来获取数据。这里有一个细节:最后一个字节的读取操作通常需要在发送“无应答(NACK)”和“停止信号”之前进行,具体的时序需要严格参照芯片手册对控制寄存器的操作序列。
注意:对保留位(Reserved)的操作原则是“读-修改-写”(Read-Modify-Write)。即先读取整个寄存器的值,只修改你需要操作的位域,然后再写回。这样可以确保不破坏保留位的未来定义,保持代码的向前兼容性。直接对整个寄存器进行赋值(如
I2CMDR = data;)在大多数情况下虽然可行,但不是一个好习惯。
3. 通信节奏掌控:I2C主控时钟周期寄存器(I2CMTPR)配置详解
I2C通信的稳定性,一半取决于时钟配置。SCL线的频率和波形直接决定了通信速率和抗干扰能力。I2CMTPR寄存器(偏移0x00C)就是用来精细控制SCL时钟周期的核心。
3.1 SCL时钟周期计算公式与参数解析
手册给出了核心公式:SCL_PERIOD = 2 × (1 + TPR) × (SCL_LP + SCL_HP) × CLK_PRD我们来拆解每个参数:
SCL_PERIOD:最终生成的I2C时钟(SCL)周期,单位是纳秒(ns)。其倒数就是通信频率(如100kHz对应周期10000ns)。TPR:这是我们需要在I2CMTPR寄存器的TPR字段(Bit 6:0)设置的值,范围是1-127。它是公式中的主要可调变量。SCL_LP和SCL_HP:分别是SCL低电平时间和高电平时间对应的系统时钟数。在TM4C系列中,这两个值是固定的,SCL_LP = 6,SCL_HP = 4。这意味着一个标准的SCL时钟周期(低+高)会消耗10个系统时钟周期。这个固定比例保证了SCL信号占空比的稳定性。CLK_PRD:系统时钟的周期(单位ns)。这是整个计算的基准。例如,如果MCU主频是80MHz,那么CLK_PRD = 1 / 80,000,000 Hz = 12.5 ns。
计算实例:假设系统时钟为50MHz(CLK_PRD = 20 ns),目标I2C频率为100kHz(标准模式,SCL_PERIOD = 10,000 ns)。 代入公式:10,000 = 2 × (1 + TPR) × (6 + 4) × 20简化后:10,000 = 2 × (1 + TPR) × 10 × 20 = 400 × (1 + TPR)解得:1 + TPR = 25=>TPR = 24因此,我们需要向I2CMTPR寄存器的TPR字段写入24。
3.2 高速模式(HS)与毛刺抑制(PULSEL)配置
I2CMTPR寄存器除了TPR,还有两个关键位:
- HS位(Bit 7):高速模式使能。当此位为0时,
TPR计算的时钟应用于标准模式(100kbps)、快速模式(400kbps)或快速模式+(1Mbps)。当此位为1时,则应用于高速模式(3.33 Mbps)。重要提示:并非所有从设备都支持高速模式,且高速模式对总线布线有更高要求。启用前需确认从机能力。 - PULSEL字段(Bit 18:16):毛刺抑制脉冲宽度选择。这是提升通信可靠性的重要手段。I2C总线是开漏结构,易受干扰,线上可能产生极短的尖峰脉冲(毛刺)。这个字段允许你设置一个滤波器,只有当SCL或SDA信号稳定持续了若干个系统时钟周期后,才被硬件确认为有效电平。选项从旁路(0x0)到31个时钟周期(0x7)。在电气环境嘈杂的场合(如长导线、电机附近),适当增加毛刺抑制宽度(如选择2或3个时钟)可以极大避免误触发,但代价是会对最高通信频率造成轻微限制。
3.3 时钟配置的常见陷阱与调试技巧
陷阱一:计算错误导致实际速率偏差。最容易出错的地方是单位换算和公式理解。务必确认CLK_PRD的单位是纳秒(ns),且系统时钟频率配置正确。我习惯在代码中用宏定义或常量来计算TPR值,并添加注释说明计算过程,方便后续复查和修改。
// 示例:计算TPR值的宏 #define SYSTEM_CLOCK_FREQ_HZ 50000000UL // 50 MHz #define SYSTEM_CLOCK_PERIOD_NS (1000000000UL / SYSTEM_CLOCK_FREQ_HZ) // 20 ns #define I2C_TARGET_FREQ_HZ 100000UL // 100 kHz #define SCL_PERIOD_NS (1000000000UL / I2C_TARGET_FREQ_HZ) // 10000 ns #define SCL_LP 6 #define SCL_HP 4 // 计算TPR,并确保在1-127范围内 #define I2C_TPR_VALUE (((SCL_PERIOD_NS) / (2 * (SCL_LP + SCL_HP) * SYSTEM_CLOCK_PERIOD_NS)) - 1)陷阱二:忽略毛刺抑制的影响。在低速总线上可能感觉不到,但在接近最高速率(如400kbps或1Mbps)时,过大的PULSEL值会“吃掉”一部分有效时间,可能导致时序违规,通信失败。我的经验是,在满足稳定性的前提下,选择最小的有效值。可以先从旁路(0x0)开始测试,如果通信有误,再逐步增加。
调试技巧:如果通信不稳定,可以尝试用逻辑分析仪或示波器抓取SCL和SDA波形。首先测量SCL的实际频率,看是否与计算值相符。其次,观察SDA数据线在SCL高电平期间的变化是否干净、无毛刺。如果发现毛刺,就可以考虑启用并调整PULSEL。
4. 中断管理机制:从屏蔽、状态到清除的完整闭环
中断是实现高效、非阻塞式I2C通信的关键。TM4C的I2C主控中断系统设计得非常典型,采用了“原始状态-屏蔽控制-屏蔽后状态-清除”的四寄存器协同机制。理解这套机制,才能写出正确的中断服务程序(ISR)。
4.1 中断状态寄存器(I2CMRIS)与屏蔽寄存器(I2CMIMR)的职责划分
首先必须分清I2CMRIS(Raw Interrupt Status)和I2CMMIS(Masked Interrupt Status)的区别。
I2CMRIS(偏移0x014):原始中断状态寄存器。只要某个中断条件触发(例如数据传输完成、收到NACK、FIFO达到触发水平),无论你是否关心这个中断,对应的位都会立刻被硬件置1。它反映的是硬件上“发生了什么事”。I2CMIMR(偏移0x010):中断屏蔽寄存器。你可以通过写这个寄存器,来选择哪些原始中断可以“晋级”成为能真正触发CPU中断的信号。某位置1表示允许(取消屏蔽)该中断;置0表示屏蔽(忽略)该中断。I2CMMIS(偏移0x018):被屏蔽后的中断状态寄存器。它反映的是“在当前的屏蔽设置下,有哪些中断是真正有效的、可以向CPU申请中断的”。简单来说,I2CMMIS = I2CMRIS & I2CMIMR(按位与)。
一个关键流程:当I2CMMIS寄存器中任何一个位为1时,就会向NVIC(嵌套向量中断控制器)发出中断请求。CPU跳转到ISR后,第一件事就是读取I2CMMIS(或I2CMRIS)来判断具体是哪个中断源触发了本次ISR调用。
4.2 关键中断源解析与应用场景
中断寄存器包含多个位,每个位对应一个特定事件:
RIS(Bit 0):主中断。这是一个“总括性”中断,表示主控事务完成或请求下一个字节传输。在简单轮询或单中断源处理中,可以主要处理这个标志。TXIM/RXIM(Bit 8/9):发送/接收FIFO请求中断。这是使用FIFO(突发)模式时的核心中断。例如,TXIM在TX FIFO达到预设的“空”阈值时触发,提醒软件需要填充更多数据;RXIM在RX FIFO达到预设的“满”阈值时触发,提醒软件需要取走数据。通过合理设置FIFO触发水平,可以优化数据传输的连续性,减少CPU干预次数。NACKIM(Bit 4):无应答中断。当从机未对地址或数据字节返回ACK时触发。这是错误处理的关键,一旦发生,通常意味着从机地址错误、从机忙或总线故障,需要软件执行恢复操作(如发送停止信号、重新初始化总线)。ARBLOSTIM(Bit 7):仲裁丢失中断。在多主系统中,当本机在发送地址或数据时,检测到总线上有其他主设备也在驱动,从而失去总线控制权时触发。处理方式通常是等待一段时间后重试。CLKIM(Bit 1):时钟超时中断。与I2CMCLKOCNT寄存器配合使用。当从机通过拉低SCL进行时钟展宽(Clock Stretching)的时间超过设定值时触发。用于防止从机故障导致主设备永远等待。
4.3 中断清除寄存器(I2CMICR)的正确操作与典型误区
I2CMICR(偏移0x01C)是一个只写寄存器,用于清除中断标志。它的操作非常特殊:向某一位写1,可以清除I2CMRIS和I2CMMIS中对应的位;读该寄存器无意义。
这里有一个极其重要的注意事项,手册在TXFEIC(Bit 10)的描述中明确警告:“Note that if we clear the TXFERIS interrupt (by setting the TXFEIC bit) when the TX FIFO is empty, the TXFERIS interrupt does not reassert even though the TX FIFO remains empty in this situation.”
这是什么意思?假设你启用了TX FIFO空中断(TXFEIM=1)。当TX FIFO变空时,硬件会置位TXFERIS(原始状态)和TXFEMIS(屏蔽后状态),触发中断。你在ISR中向TXFEIC位写1来清除这个中断标志。但是,如果在你清除中断的那一刻,TX FIFO仍然是空的,那么即使这个“空”的状态持续存在,硬件也不会再次自动置位TXFERIS来重新申请中断。这可能导致你的数据传输流程卡住,因为你在等待下一个“FIFO空”中断来填充数据,但它永远不会来了。
正确的做法:在清除TX FIFO空中断(TXFEIC)之前,确保你已经向TX FIFO写入了一些数据,使得FIFO不再处于“空”状态。或者,采用查询TXFE状态位(通常在I2CMCS或FIFO状态寄存器中)的方式来决定何时填充数据,而不是完全依赖中断。
一个典型的中断服务程序(ISR)处理流程如下:
- 读取
I2CMMIS寄存器,判断中断来源(使用switch或if-else语句)。 - 根据不同的中断源进行相应处理:
- 如果是
RXIM,则从I2CFIFODATA读取数据。 - 如果是
TXIM,则向I2CFIFODATA写入数据。 - 如果是
NACKIM或ARBLOSTIM,则进行错误处理和恢复。 - 如果是
RIS(主中断完成),则结束本次传输事务。
- 如果是
- 向
I2CMICR寄存器的对应位写1,清除该中断标志。务必注意���只能清除已处理的中断标志,不要一次性清除所有位。 - 必要时,清除NVIC中的中断 pending 位。
5. 高级功能与总线监控:突发传输、超时与诊断
除了基本的数据、时钟和中断,TM4C的I2C主控还提供了一些高级功能,用于处理���复杂的场景和进行总线诊断。
5.1 突发传输(Burst)的完整配置与流程控制
突发传输是提升大数据量传输效率的利器。其配置涉及多个寄存器的协同:
- 设置突发长度:向
I2CMBLEN寄存器(偏移0x030)的CNTL字段写入本次要传输的总字节数(N)。这是必须的第一步,且N必须大于0。 - 启用BURST模式:在控制状态寄存器(
I2CMCS,假设其包含BURST控制位)中设置BURST位。一旦启用,数据传输将自动通过I2CFIFODATA寄存器进行。 - 监控传输进度:在传输过程中,可以读取
I2CMBCNT寄存器(偏移0x034)。这是一个只读寄存器,硬件会将I2CMBLEN的值拷贝到这里,并在每个字节成功传输后递减。因此,它的值表示剩余待传输的字节数。 - 处理提前终止:如果突发传输因从机发送NACK而提前终止,
I2CMBCNT中的值就不会减到0。通过读取这个值,软件可以知道实际成功传输了多少字节(I2CMBLEN - I2CMBCNT),这对于错误诊断和数据同步非常有用。
5.2 时钟低超时(Clock Low Timeout)功能与配置
I2CMCLKOCNT寄存器(偏移0x024)用于配置一个12位的超时计数器(高8位CNTL可见,低4位固定为0)。它的作用是:当SCL线被从机持续拉低的时间超过这个计数器设定的时限时,触发时钟超时中断(CLKRIS)。
这个功能是为了防止一个故障或设计不良的从机通过无限期地拉低SCL(时钟展宽)来“挂起”整个I2C总线。超时后,主控制器可以采取恢复措施,例如复位I2C模块或重新初始化总线。
配置要点:
- 计数器值(
CNTL)必须大于1。 - 超时时间 =
CNTL× 16 × 系统时钟周期。因为这是一个12位计数器(CNTL是8位,但硬件是12位,低4位为0),所以实际计数值是CNTL << 4。 - 手册特别说明:只要SCL被释放(变高),这个计数器就会自动重载
CNTL值并重新开始递减计数。这意味着它监控的是SCL连续为低的时间,而不是累计时间。
5.3 总线监控寄存器(I2CMBMON)的调试应用
I2CMBMON(偏移0x02C)是一个简单的只读寄存器,仅包含两个位:SCL(Bit 0)和SDA(Bit 1)。它们直接反映了I2C物理引脚上的当前电平状态(1为高,0为低)。
这个寄存器在调试阶段价值巨大:
- 诊断总线死锁:当通信卡住时,读取此寄存器可以立即知道SCL和SDA线是被拉低(可能被某个设备占用)还是处于高电平空闲状态。
- 验证上拉电阻:在总线空闲时(无主机驱动),SCL和SDA都应通过上拉电阻表现为高电平(读回值为1)。如果读回0,可能意味着上拉电阻过大、电源问题,或者有设备故障拉低了总线。
- 辅助分析通信波形:在单步调试或低速查询中,通过连续读取这个寄存器,可以近似地“模拟”出一个简易的逻辑分析仪功能,观察起始、停止、应答等信号的变化。
例如,如果你怀疑从机没有应答,可以在主控发送完地址字节后,读取I2CMBMON并检查在第9个时钟周期(ACK位)时,SDA线是否被从机拉低。如果没有拉低,则证实了NACK的发生。
6. 从机模式基础:地址识别与状态控制
虽然输入资料主要围绕主控寄存器,但也提及了从机相关的几个关键寄存器。理解从机模式对于实现双向通信或多主系统很有帮助。
6.1 从机自身地址寄存器(I2CSOAR)
I2CSOAR(偏移0x800)的低7位(OAR字段)用于设置本设备作为I2C从机时的7位地址。I2C协议也支持10位地址,但TM4C此型号的该寄存器仅支持7位模式(10位地址模式可能需要其他寄存器配合或不同系列才支持)。上电复位后,该寄存器值为0,这意味着从机功能默认是无效的,必须由软件配置一个合法的非零地址(通常避开保留地址0x00和0x7F)。
6.2 从机控制/状态寄存器(I2CSCSR)的双重角色
I2CSCSR(偏移0x804)是一个特殊的“读-写不同功能”寄存器。
- 当读取时,它是一个状态寄存器(RO),反映从机当前的工作状态。关键状态位包括:
RREQ(Bit 0):接收请求。为1表示主设备已发送数据给本从机,数据在接收缓冲区(I2CSDR)中等待读取,且从机正通过时钟展宽来等待。TREQ(Bit 1):发送请求。为1表示主设备已向本从机请求数据,从机需要向I2CSDR写入数据以响应,同时正通过时钟展宽等待。FBR(Bit 2):首字节接收。仅在RREQ=1时有效,表示接收到的第一个字节(即地址字节之后的数据)已就绪。读取I2CSDR后此位自动清零。
- 当写入时,它是一个控制寄存器(WO),用于启用从机功能。关键控制位包括:
DA(Bit 0):设备激活。必须置1才能使能I2C从机功能。TXFIFO/RXFIFO(Bit 1/2):使能从机的发送/接收FIFO。使用FIFO可以缓冲数据,减少对实时响应的要求。
6.3 从机模式下的数据交换流程
一个典型的从机接收流程(主设备写数据到从机):
- 软件配置
I2CSOAR设置地址,并写I2CSCSR寄存器使能从机(DA=1)和接收FIFO(RXFIFO=1,可选)。 - 当主设备发起起始条件并发送匹配的从机地址(写方向)时,硬件自动响应ACK。
- 硬件接收到第一个数据字节后,会置位
RREQ和FBR状态位。如果使能了中断,可能会触发中断。 - 从机软件(在中断或轮询中)检测到
RREQ=1,便从数据寄存器I2CSDR中读取数据。读取操作会自动清除FBR位(如果是第一个字节)并释放时钟展宽,允许主设备发送下一个字节。 - 后续字节的接收,
RREQ会保持为1(如果FIFO未满),直到所有数据接收完毕,主设备发送停止条件。
从机发送流程类似,只是方向相反,从机软件需要在检测到TREQ=1时,及时向I2CSDR写入数据以供主设备读取。
7. 实战配置案例与常见问题排查
理论最终要服务于实践。下面我将结合一个具体的场景——使用TM4C1292作为主设备,以100kHz速率向一个EEPROM(从设备地址0x50)连续写入8字节数据——来演示关键寄存器的配置流程,并整理一份常见问题排查表。
7.1 完整的主控发送配置流程
假设系统时钟为50MHz,目标I2C频率100kHz。
- 使能外设时钟:首先需要使能I2C模块所在的外设时钟(通过系统控制模块的RCGC寄存器)。
- 配置GPIO:将对应的SDA和SCL引脚配置为I2C功能(AFSEL),并使能开漏输出和上拉。
- 初始化主控:
- 写
I2CMCR寄存器,确保主功能使能位MFE(Bit 4)为1,从功能SFE(Bit 5)为0(如果不需要)。 - 配置
I2CMTPR寄存器:- 根据前面计算,
TPR字段写入24。 HS位保持0(标准模式)。PULSEL根据环境噪声情况配置,假设环境较好,设为0(旁路)。- 代码:
I2C0->MTPR = (0x0 << 16) | (0x0 << 7) | (24 << 0);// 假设使用I2C0模块
- 根据前面计算,
- 写
- 配置从机地址:将要访问的EEPROM地址(0x50)和写方向位(0)组合后,写入主控从机地址寄存器(
I2CMSA,假设其偏移为0x000,资料未给出但实际存在)。 - 启动传输:
- 写控制状态寄存器
I2CMCS(假设偏移0x004),发送起始条件(START)和运行(RUN)命令。这会启动地址帧的发送。 - 轮询
I2CMCS的BUSY位或等待主中断(RIS)触发。
- 写控制状态寄存器
- 检查并发送数据:
- 检查状态,确认收到从机ACK(无错误)。
- 将第一个数据字节写入
I2CMDR。 - 再次写
I2CMCS寄��器发送数据(通常是一个不带START、带RUN的命令)。 - 重复此过程,发送剩余7个字节。
- 结束传输:发送完最后一个字节后,向
I2CMCS写入命令,发送停止条件(STOP)。
如果使用突发(BURST)模式,流程会有所不同:
- 在步骤3之后,设置
I2CMBLEN = 8。 - 在步骤5之前,配置
I2CMCS寄存器启用BURST模式。 - 启动传输(发送START和地址)后,数据将不再通过
I2CMDR,而是通过I2CFIFODATA寄存器发送。你需要确保在TX FIFO变空(触发TXIM中断或查询TXFE状态)前,及时将数据写入I2CFIFODATA。 - 硬件会自动管理字节计数,发送完8个字节后,你需要发送停止条件来结束传输。
7.2 I2C通信常见问题与排查指南
下表总结了I2C调试中最常遇到的问题、可能原因和排查思路:
| 问题现象 | 可能原因 | 排查步骤与解决方法 |
|---|---|---|
| 通信完全无响应 | 1. 硬件连接问题(线缆、虚焊) 2. 上拉电阻缺失或阻值过大 3. I2C模块时钟未使能 4. GPIO引脚功能未正确配置 | 1. 用万用表测量SCL/SDA对地电压,空闲时应为高电平(接近VCC)。 2. 检查系统控制模块中对应I2C和GPIO的RCGC位是否置1。 3. 确认GPIO的AFSEL(复用功能选择)位已设置,且ODR(开漏)和PUR(上拉)使能。 |
| 能发送起始信号,但无ACK(NACK) | 1. 从机地址错误 2. 从设备未上电或损坏 3. 从机忙或处于写保护状态 4. 总线竞争(多主) | 1. 用逻辑分析仪确认发送的地址字节是否正确(7位地址+1位读写)。 2. 检查从设备电源和复位信号。 3. 查询从设备数据手册,确认其是否要求特定解锁序列或处于忙状态。 4. 检查 I2CMRIS中的ARBLOSTRIS位是否被置位。 |
| 通信时好时坏,数据错误 | 1. 时钟频率配置错误 2. 总线电容过大,上升沿太慢 3. 毛刺干扰 4. 中断处理不当,丢失数据 | 1. 用示波器测量SCL实际频率,核对I2CMTPR计算值。2. 减小上拉电阻阻值(如从4.7kΩ减至2.2kΩ),但需注意驱动能力。 3. 启用并调整 I2CMTPR中的PULSEL毛刺抑制。4. 检查中断服务程序是否及时读取/写入FIFO数据,是否清除了正确的中断标志。 |
| 使用FIFO中断时传输卡住 | 1. FIFO空中断(TXFEIM)清除后未重新触发(见4.3节)2. 突发长度 I2CMBLEN配置为03. FIFO触发水平设置不合理 | 1. 确保在清除TXFEIC前,TX FIFO中已有数据,或改用查询TXFE状态的方式。2. 确认启用BURST前, I2CMBLEN已设置为正确定义的字节数。3. 调整FIFO触发水平,避免中断过于频繁或响应不及时。 |
| 从机模式下无法被寻址 | 1.I2CSOAR地址寄存器配置错误2. 从机功能未使能( I2CSCSR的DA位为0)3. 总线地址冲突 | 1. 确认写入I2CSOAR的地址是7位右对齐(即0x50直接写入)。2. 检查写 I2CSCSR寄存器时,DA位是否已置1。3. 确保总线上没有其他设备使用相同地址。 |
调试I2C,逻辑分析仪是必不可少的工具。它能直观地展示起始、停止、地址、数据、ACK/NACK位的完整波形,绝大多数问题都能通过分析波形找到根源。在软件层面,养成在关键操作后检查状态寄存器(BUSY,ERROR,ARBLOST等位)的习惯,并结合中断状态寄存器进行有效的错误处理,是写出健壮I2C驱动的基础。