新闻详情

新闻详情

首页 / 资讯中心 / 详情

Tiva™ I2C从机编程实战:数据寄存器、中断与FIFO机制详解

发布时间:2026/7/23 2:04:19
Tiva™ I2C从机编程实战:数据寄存器、中断与FIFO机制详解
1. 从机数据寄存器I2CSDR数据交换的核心门户在I2C从机通信中数据寄存器I2C Slave Data Register简称I2CSDR扮演着数据收发“前哨站”的角色。它的地址偏移是0x808是一个可读可写RW的32位寄存器但实际有效的数据位是低8位位7:0高24位是保留位。这个寄存器的工作模式非常直接当从机处于发送状态Slave Transmit时你写入这个寄存器的值就是下一个要发送给主机的字节当从机处于接收状态Slave Receive时主机发来的数据字节会被硬件自动填充到这个寄存器里你读取它就能拿到数据。这里有一个至关重要的细节也是很多新手容易栽跟头的地方这个寄存器是“读敏感”的。手册里那句“Important: This register is read-sensitive.”可不是随便写写的。什么叫读敏感以接收数据为例假设主机发送了一个字节0x55到从机这个数据会被硬件暂存。当你第一次读取I2CSDR时你拿到的是0x55。但关键在于这个读取操作本身会被硬件视为“数据已被从机取走”的确认信号。在某些实现中这可能会触发内部状态机的变化或者为接收下一个字节做准备。如果你在中断服务程序里不小心连续读了两次这个寄存器第二次读到的很可能就不是0x55了可能是未定义的旧数据甚至可能引发通信错误。所以最佳实践是在数据接收中断里只读取一次I2CSDR然后立刻处理读到的数据。另一个需要厘清的概念是I2CSDR与FIFO的关系。在Tiva™系列微控制器中I2C模块配备了硬件FIFO缓冲区。当你在控制寄存器I2CSCSR中使能了RXFIFO接收FIFO或TXFIFO发送FIFO功能后I2CSDR寄存器就会被“绕过”。这意味着在接收时数据会直接进入RX FIFO你需要去读I2CFIFODATA寄存器来获取数据在发送时你需要把要发送的数据写入I2CFIFODATA寄存器它会进入TX FIFO排队等待发送此时写I2CSDR是无效的。手册里特别用Note强调“最佳实践建议应用程序不应在连续的传输事务中在I2CSDR寄存器和TX FIFO之间切换反之亦然。” 这是因为硬件内部的数据通路和状态机可能针对一种模式进行了优化频繁切换会增加状态不一致的风险可能导致数据丢失或通信超时。我的经验是在项目初始化阶段就根据数据量的大小和实时性要求决定使用寄存器直通模式还是FIFO模式然后在整个运行周期内保持模式不变。从编程的角度看操作I2CSDR非常简单。假设我们使用寄存器直通模式并且从机地址已配置好。当主机发送数据写从机时从机会进入接收状态并触发数据中断如果已使能。在中断服务程序中你可以这样安全地读取数据// 假设 I2C0 模块的基址已定义为 I2C0_BASE uint8_t receivedData HWREG(I2C0_BASE I2C_O_SDR) 0xFF; // 只取低8位 // 立即处理 receivedData...当主机请求数据读从机时从机会进入发送状态。你需要在主机发起读操作之前或者在一个特定的“数据请求”中断通常与DATARIS相关里提前把要发送的数据写入I2CSDRuint8_t dataToSend 0xA5; HWREG(I2C0_BASE I2C_O_SDR) dataToSend; // 硬件会在适当的时钟周期将数据放到SDA线上记住写入操作也需要谨慎。特别是在主机连续读取多个字节时你需要根据主机的时钟节奏及时准备好下一个要发送的字节并写入寄存器否则可能会发送错误数据或产生NACK。2. 中断控制三剑客IMR、RIS与ICR高效的中断处理是解放CPU、实现实时响应的关键。Tiva™的I2C从机模块提供了一套完整且精细的中断管理机制由三个寄存器协同工作中断掩码寄存器I2CSIMR、原始中断状态寄存器I2CSRIS和中断清除寄存器I2CSICR。理解它们之间的关系和操作流程是从机编程的核心。2.1 中断掩码寄存器I2CSIMR决定谁可以“敲门”I2CSIMR偏移0x80C是一个可读可写的寄存器它的作用就像一个“门卫”或者“过滤器”。当中断事件发生时比如收到一个字节硬件会首先在原始中断状态寄存器I2CSRIS的对应位上置1表示“有事情发生了”。但是这个“事情”要不要最终上报给CPU引发中断服务程序的执行就由I2CSIMR来决定。I2CSIMR的每一个位对应着I2CSRIS中的一个中断源。当IMR的某个位被设置为1时表示允许该中断源产生控制器中断即上报给CPU设置为0则表示屏蔽该中断即使RIS位被置1也不会触发CPU中断。这种设计给了开发者极大的灵活性。例如在一个以接收数据为主的应用中你可能只关心“接收FIFO请求中断”RXIM和“接收完成中断”DATARIS注意DATARIS涵盖多种情况那么你就可以只使能这两个位而屏蔽掉“发送FIFO空”TXFEIM等无关的中断避免不必要的打断。常见的可屏蔽中断源包括DATAIM (位0)数据中断。这是一个比较“宽泛”的中断根据手册描述它涵盖了从机事务接收、从机事务请求、下一个字节传输请求等多种情况。在简单的轮询或中断驱动程序中这个中断非常有用。STARTIM (位1)START条件中断。当总线上检测到START或Repeated START条件时触发。STOPIM (位2)STOP条件中断。当检测到STOP条件时触发。START/STOP中断常用于帧边界的判断。DMARXIM/DMATXIM (位3/4)DMA接收/发送完成中断。当使用DMA进行数据搬运时DMA传输完成会触发此中断。TXIM/RXIM (位5/6)发送/接收FIFO请求中断。当TX或RX FIFO中的数据量达到你在I2CFIFOCTL寄存器中设置的触发水平Trigger Level时触发非常适合配合DMA进行批量数据传输。TXFEIM/RXFFIM (位7/8)发送FIFO空/接收FIFO满中断。当TX FIFO完全为空或RX FIFO完全为满时触发。配置示例如果我们希望使能数据接收中断和接收FIFO请求中断假设使用FIFO且触发水平设为4字节可以这样配置// 清除可能存在的旧中断标志操作ICR寄存器后文详述 HWREG(I2C0_BASE I2C_O_SICR) 0x1FF; // 写入1清除所有可能的中断标志 // 配置中断掩码使能数据中断(DATAIM)和接收FIFO请求中断(RXIM) HWREG(I2C0_BASE I2C_O_SIMR) (1 0) | (1 6);2.2 原始中断状态寄存器I2CSRIS与屏蔽中断状态寄存器I2CSMIS看清“谁在敲门”中断事件发生后我们需要知道具体是哪个事件触发的。这里有两个状态寄存器I2CSRIS (偏移0x810)原始中断状态寄存器。这是一个只读寄存器。只要硬件检测到对应的事件发生无论I2CSIMR是否使能了该中断对应的RIS位都会被自动置1。它反映了最底层的、未经任何过滤的中断状态。你可以把它想象成所有传感器的原始信号。I2CSMIS (偏移0x814)屏蔽中断状态寄存器。这也是一个只读寄存器。它显示的状态是“原始中断状态RIS与中断掩码IMR进行逻辑与之后的结果”。也就是说MIS RIS IMR。只有当某个中断事件发生RIS1并且该中断被使能IMR1时对应的MIS位才会是1。通常在中断服务程序ISR中我们通过读取I2CSMIS寄存器来判断究竟是哪个被使能的中断源触发了本次进入ISR。为什么要两个状态寄存器RIS用于最全面的状态查询和调试比如你想知道总线上是否发生过STOP条件即使你没有使能STOP中断也可以通过查询RIS寄存器来得知。而MIS则是为中断服务程序量身定做的它直接告诉你“当前需要处理的是哪个已使能的中断”避免了在ISR中再去用软件做一次“RIS IMR”的运算。在中断服务程序里典型的处理流程是这样的void I2C0_Slave_IRQHandler(void) { uint32_t misStatus HWREG(I2C0_BASE I2C_O_SMIS); // 读取屏蔽中断状态 if (misStatus I2C_SMIS_RXMIS) { // 处理接收FIFO请求中断 // 从 I2CFIFODATA 读取多个字节直到FIFO为空或达到所需数量 while (!(HWREG(I2C0_BASE I2C_O_FIFOSTATUS) I2C_FIFOSTATUS_RXFE)) { uint8_t data HWREG(I2C0_BASE I2C_O_FIFODATA) 0xFF; // 处理数据 data... } // 清除此中断标志 HWREG(I2C0_BASE I2C_O_SICR) I2C_SICR_RXIC; } if (misStatus I2C_SMIS_DATAMIS) { // 处理数据中断例如在非FIFO模式下 // 判断是发送还是接收状态然后操作 I2CSDR // ... HWREG(I2C0_BASE I2C_O_SICR) I2C_SICR_DATAIC; } // ... 检查其他MIS位 }2.3 中断清除寄存器I2CSICR送走“客人”中断处理完毕后必须清除中断标志否则CPU会认为中断一直存在导致连续进入中断服务程序或者无法响应后续的中断。I2CSICR偏移0x818是一个只写WO寄存器读取它没有意义手册明确写着“A read of this register returns no meaningful data”。清除中断标志的机制是“写1清零”。ICR寄存器的每个位与RIS/MIS寄存器中的中断源一一对应。当你向ICR的某个位写入1时硬件会同时清除RIS寄存器和MIS寄存器中对应的位。例如要清除接收FIFO请求中断就向RXIC位位6写1HWREG(I2C0_BASE I2C_O_SICR) I2C_SICR_RXIC; // 宏定义 (1 6)这里有两点极其重要针对性清除在中断服务程序中应该根据读取到的MIS状态有针对性地清除那些被处理过的中断标志。像上面示例代码中那样用if判断后分别清除。避免使用HWREG(I2C0_BASE I2C_O_SICR) 0x1FF;这样的语句一次性清除所有标志除非你非常确定所有可能的中断都已得到妥善处理否则可能会掩盖尚未处理的中断事件。清除顺序通常建议先读取MIS/RIS再处理事务最后清除标志。这个顺序不能乱。如果你先清标志再读MISMIS的值可能已经变了因为标志被清了导致你无法正确判断中断源。一个特殊的注意事项是关于TXFEIC发送FIFO空中断清除。手册在描述TXFERIS位时有一个Note“Note that if the TXFERIS interrupt is cleared (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本来就是空的你清除了TXFE中断标志那么即使FIFO继续保持为空该中断也不会再次产生。这通常不是问题因为TXFE中断的目的是通知你“FIFO已空请尽快填充数据”。你清除标志并填充数据后FIFO就不为空了。只有当再次变空时才会产生新的中断。3. FIFO机制深度解析数据流的缓冲与调度对于需要传输大量数据或追求高效率的应用直接操作数据寄存器I2CSDR会导致CPU频繁被中断效率低下。Tiva™的I2C模块内置的硬件FIFOFirst In, First Out缓冲区就是为了解决这个问题。它允许数据在硬件层面进行缓冲从而减少中断频率并能与DMA控制器配合实现“零CPU干预”的数据搬运。与FIFO相关的寄存器主要有四个I2CFIFODATA、I2CFIFOCTL、I2CFIFOSTATUS以及控制FIFO功能开关的I2CSCSR中的相关位。3.1 FIFO数据寄存器I2CFIFODATA与模式切换I2CFIFODATA寄存器偏移0xF00是访问FIFO缓冲区的门户。它有一个非常独特的设计同一个物理地址根据你是读操作还是写操作分别映射到RX FIFO和TX FIFO。当你读取这个地址时你访问的是RX FIFO的栈顶即最早进入FIFO、待读取的数据当你向这个地址写入时数据会被压入TX FIFO的栈顶等待发送。这种设计节省了地址空间也简化了编程模型。使用FIFO的前提是在从机控制/状态寄存器I2CSCSR中使能RXFIFO和/或TXFIFO位。一旦使能数据通路就会从I2CSDR切换到I2CFIFODATA。正如之前提到的手册强烈建议不要在单次通信会话或连续的传输中混合使用I2CSDR和FIFO模式因为这可能导致硬件状态机混乱。操作FIFO时数据的进出是顺序的。例如主机发送了字节序列0x11, 0x22, 0x33到从机。如果从机使能了RX FIFO且深度足够这三个字节会依次进入RX FIFO。当你第一次读取I2CFIFODATA时得到的是0x11第二次读取得到0x22第三次得到0x33。你需要依靠I2CFIFOSTATUS寄存器来判断FIFO的当前状态避免读空或写满。3.2 FIFO控制寄存器I2CFIFOCTL配置缓冲策略I2CFIFOCTL偏移0xF04是FIFO功能的总控制台它的配置直接决定了FIFO的行为和性能。FIFO分配RXASGNMT/TXASGNMT, 位31/15这个功能在多个I2C模块如同时做主从共享FIFO资源时有用。它决定FIFO是分配给主控制器Master使用还是从控制器Slave使用。在我们的从机场景下通常需要将RX和TX FIFO都分配给从机设置为1。复位后这两个位通常默认为0分配给Master所以从机应用中必须记得将它们设置为1。// 将RX和TX FIFO分配给Slave使用 uint32_t fifoctrl HWREG(I2C0_BASE I2C_O_FIFOCTL); fifoctrl | (1 31) | (1 15); // 设置RXASGNMT和TXASGNMT位 HWREG(I2C0_BASE I2C_O_FIFOCTL) fifoctrl;触发水平RXTRIG/TXTRIG, 位[18:16]/[2:0]这是FIFO中断驱动编程的核心参数。它定义了在什么条件下触发RXIM或TXIM中断。RXTRIG接收触发水平。当RX FIFO中存储的数据字节数达到或超过这个设定值时RXRIS位被置1如果RXIM使能则产生中断。例如设置RXTRIG4则当RX FIFO中有了4个、5个...直到8个假设FIFO深度为8数据时都会满足触发条件。手册特别警告将RXTRIG设置为0x0是无效的因为空FIFO没有数据可传输。通常设置为4半满或1每收到一个字节就中断适用于低延迟但高CPU负载的场景。TXTRIG发送触发水平。当TX FIFO中剩余空间即空闲位置数量达到或超过这个设定值时TXRIS位被置1如果TXIM使能则产生中断。注意这里的逻辑与RX相反。例如设置TXTRIG4意味着当TX FIFO中已使用的空间小于等于4个即空闲空间大于等于4个时触发中断通知CPU可以填充更多数据。设置为0表示当TX FIFO完全空时触发TXFE中断的另一种形式。合理设置触发水平是平衡中断频率和响应延迟的关键。对于批量数据传输通常将触发水平设置为FIFO深度的一半如4这样每次中断可以处理多个数据减少了中断次数。DMA使能DMARXENA/DMATXENA, 位29/13当设置为1时使能对应方向的DMA通道。当FIFO的触发条件满足时由RXTRIG/TXTRIG定义硬件会自动向DMA控制器发出请求由DMA在后台搬运数据完全不需要CPU与。这是实现高效大数据量传输的终极武器。FIFO刷新RXFLUSH/TXFLUSH, 位30/14向这些位写1会立即清空对应的FIFO缓冲区。这个操作是“自清除”的硬件完成刷新后会自动将该位清零。在通信初始化、错误恢复或协议重启时刷新FIFO是一个好习惯可以确保从一个干净的状态开始。3.3 FIFO状态寄存器I2CFIFOSTATUS实时监控缓冲区I2CFIFOSTATUS偏移0xF08是一个只读寄存器提供了FIFO的实时快照。空/满标志RXFE/RXFF, TXFE/TXFF这些是最直观的状态位。RXFE1表示接收FIFO为空无数据可读RXFF1表示接收FIFO已满新数据无法写入如果主机继续发送可能导致数据丢失或NACK。发送FIFO的TXFE和TXFF意义类似。在编程时在读取数据前检查RXFE在写入数据前检查TXFF是避免操作错误的基本功。触发水平状态RXABVTRIG/TXBLWTRIG这两个位直接反映了当前FIFO状态相对于触发水平的比较结果。RXABVTRIG1RX FIFO中的数据量高于RXTRIG设定的水平。TXBLWTRIG1TX FIFO中的数据量低于TXTRIG设定的水平即空闲空间高于触发水平。 这两个位在中断服务程序中非常有用可以辅助判断中断原因。例如即使你使能了RXIM中断中断也可能因为FIFO被读空而退出。当再次进入中断时可以通过检查RXABVTRIG来判断FIFO是否再次达到了触发水平。一个结合了FIFO和中断的典型数据接收流程如下初始化使能RX FIFO设置RXTRIG4分配FIFO给从机使能RXIM中断。主机开始发送数据。当RX FIFO中数据达到4个时触发RXIM中断。在中断服务程序中循环读取I2CFIFODATA直到RXFE变为1FIFO空或处理完所需数量的数据。清除RXIC中断标志。如果主机发送的数据很多当FIFO再次被填充到4个以上时会再次触发中断重复步骤4-5。4. 从机地址与应答控制身份识别与流控除了数据传输和中断从机还需要正确识别主机对自己的寻址并在必要时控制总线应答。这涉及到I2CSOAR2和I2CSACKCTL两个寄存器。4.1 从机自身地址寄存器2I2CSOAR2大多数I2C从机设备支持一个7位或10位的首要地址。Tiva™的I2C模块通过I2CSOAR从机自身地址寄存器文档未提供但必然存在来配置这个首要地址。I2CSOAR2偏移0x81C则提供了一个备用地址。这在两种情况下特别有用地址冲突总线上有两个设备出厂设置了相同的固定地址你可以通过软件将其中一个配置为使用备用地址。多功能设备一个物理设备如一个传感器集成了多种功能可以响应两个不同的地址模拟成两个逻辑设备。I2CSOAR2的低7位OAR2字段存储备用地址值最高位OAR2EN是使能位。只有当OAR2EN设置为1时硬件才会在总线上同时监听首要地址和这个备用地址。如果主机发送的地址与两者之一匹配从机都会做出响应。配置示例假设设备首要地址是0x48我们希望它也能响应备用地址0x50。// 配置首要地址 (假设通过I2CSOAR寄存器地址偏移可能不同需查手册) HWREG(I2C0_BASE I2C_O_SOAR) 0x48; // 设置7位地址注意实际寄存器可能需移位 // 配置并启用备用地址 HWREG(I2C0_BASE I2C_O_SOAR2) (1 7) | (0x50 0x7F); // 设置OAR2EN1, OAR20x504.2 从机应答控制寄存器I2CSACKCTL在标准的I2C协议中从机在接收到每个字节包括地址字节和数据字节后都需要在第九个时钟周期发出一个应答ACK或非应答NACK信号。通常硬件会自动在地址匹配且无错误时发出ACK。I2CSACKCTL寄存器偏移0x820提供了手动覆盖这一自动行为的能力实现软件控制的应答。ACKOVAL位1应答覆盖值。设置为0表示强制发送ACK设置为1表示强制发送NACK。ACKOEN位0应答覆盖使能。设置为1时使能ACKOVAL的控制设置为0时由硬件自动管理应答。这个功能的应用场景包括流控制当从机的RX FIFO已满无法接收更多数据时可以在中断服务程序中设置ACKOEN1和ACKOVAL1让从机对后续的数据字节发出NACK提示主机停止发送。协议处理在某些自定义的I2C协议中从机可能需要根据接收到的命令或数据内容决定是否确认。例如收到一个无法识别的命令码可以回复NACK。从机忙状态如果从机正在处理一个耗时操作如EEPROM写入暂时无法响应可以在处理期间对主机发送的地址或数据回NACK直到准备好后再恢复正常。重要警告手册中提到“The I2C clock is pulled low after the last data bit until this register is written.” 这意味着当你使能了应答覆盖ACKOEN1后在每字节传输的第9个时钟周期SCL线会被硬件拉低时钟延展直到你写入了I2CSACKCTL寄存器来决定发出ACK还是NACK。这给了软件反应时间但也要求你的中断服务程序必须足够快在SCL被拉低的时间内完成判断并写入I2CSACKCTL否则总线会因时钟被无限拉低而挂起。通常这需要在一个高优先级的、快速的中断中处理。使用示例在RX FIFO满中断中强制NACK下一个数据字节。void I2C0_Slave_IRQHandler(void) { uint32_t misStatus HWREG(I2C0_BASE I2C_O_SMIS); if (misStatus I2C_SMIS_RXFFMIS) { // 接收FIFO满中断 // 1. 立即读取FIFO数据以腾出空间如果可能 // 2. 如果无法立即处理强制NACK后续数据 HWREG(I2C0_BASE I2C_O_SACKCTL) (1 1) | (1 0); // ACKOVAL1 (NACK), ACKOEN1 // 注意在下一个字节开始传输前可能需要根据情况恢复自动ACK } // ... 清除中断标志 }5. 实战配置与调试技巧理解了各个寄存器的功能后如何将它们组合起来配置一个稳定可靠的I2C从机呢下面以一个典型的传感器从机例如模拟一个温度传感器地址0x48使用FIFO和中断接收数据为例展示初始化流程和关键代码片段。5.1 从机初始化步骤使能外设时钟首先需要使能I2C模块所在的系统时钟域。SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0); while(!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C0)); // 等待外设就绪GPIO配置将对应的SCL和SDA引脚配置为I2C功能。GPIOPinConfigure(GPIO_PA6_I2C0SCL); GPIOPinConfigure(GPIO_PA7_I2C0SDA); GPIOPinTypeI2CSCL(GPIO_PORTA_BASE, GPIO_PIN_6); GPIOPinTypeI2C(GPIO_PORTA_BASE, GPIO_PIN_7);初始化I2C主控制器模块可选但推荐TI的驱动库通常需要先初始化主控模式再切换为从机。这确保了内部状态机的正确。I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false); // 先以主机模式初始化false表示不启用高速模式配置从机地址// 设置从机自身地址 (7位地址需左移一位注意库函数和直接寄存器操作的区别) // 使用TI驱动库 I2CSlaveEnable(I2C0_BASE); I2CSlaveInit(I2C0_BASE, 0x48); // 0x48 是7位地址函数内部可能会处理 // 或者直接操作寄存器 (假设SOAR寄存器偏移已知) // HWREG(I2C0_BASE I2C_O_SOAR) 0x48; // 注意实际位域可能需调整配置FIFO// 1. 刷新FIFO HWREG(I2C0_BASE I2C_O_FIFOCTL) | (I2C_FIFOCTL_RXFLUSH | I2C_FIFOCTL_TXFLUSH); // 等待刷新完成FLUSH位会自动清零 while(HWREG(I2C0_BASE I2C_O_FIFOCTL) (I2C_FIFOCTL_RXFLUSH | I2C_FIFOCTL_TXFLUSH)); // 2. 分配FIFO给从机 uint32_t fifoctrl HWREG(I2C0_BASE I2C_O_FIFOCTL); fifoctrl | I2C_FIFOCTL_RXASGNMT | I2C_FIFOCTL_TXASGNMT; // 分配给Slave // 3. 设置触发水平RX FIFO有4个数据时触发中断TX FIFO剩余4个空位时触发中断 fifoctrl ~(I2C_FIFOCTL_RXTRIG_M | I2C_FIFOCTL_TXTRIG_M); // 清除旧值 fifoctrl | (4 I2C_FIFOCTL_RXTRIG_S) | (4 I2C_FIFOCTL_TXTRIG_S); HWREG(I2C0_BASE I2C_O_FIFOCTL) fifoctrl;配置中断// 1. 清除所有可能的中断标志 HWREG(I2C0_BASE I2C_O_SICR) 0x1FF; // 2. 使能所需的中断数据中断、接收请求中断 HWREG(I2C0_BASE I2C_O_SIMR) I2C_SIMR_DATAIM | I2C_SIMR_RXIM; // 3. 在NVIC中使能I2C从机中断 IntEnable(INT_I2C0); I2CSlaveIntEnable(I2C0_BASE); // 使能模块内部中断输出使能从机I2CSlaveEnable(I2C0_BASE);5.2 调试技巧与常见问题排查即使配置正确在实际调试中也可能遇到各种问题。以下是一些常见问题的排查思路问题1从机无响应主机收不到ACK。检查地址用逻辑分析仪或示波器抓取总线波形确认主机发送的地址与从机配置的地址I2CSOAR和I2CSOAR2是否匹配。注意7位地址在总线上是左对齐的即实际发送的字节是(addr 1) | R/W。检查时钟和引脚确认SCL和SDA引脚配置正确上拉电阻已连接通常4.7kΩ。用示波器检查总线是否有正确的START条件、时钟脉冲和数据变化。检查从机使能确认I2CSlaveEnable已调用或相应的控制位已设置。检查总线冲突总线上是否有其他设备在干扰尝试断开其他从机。问题2能收到地址ACK但数据通信失败。检查FIFO状态如果使用了FIFO确保RXASGNMT/TXASGNMT已正确分配给从机。在中断中打印或检查I2CFIFOSTATUS寄存器看FIFO是否已满RXFF或为空RXFE/TXFE。检查中断处理中断服务程序是否及时清除了中断标志是否因为处理太慢导致FIFO溢出或下溢可以在ISR入口和出口加GPIO翻转来测量执行时间。检查数据寄存器在非FIFO模式下是否在正确的时间点主机时钟的相应阶段读写I2CSDR在FIFO模式下是否误读了I2CSDR而应该读I2CFIFODATA问题3中断不触发或触发异常频繁。检查中断掩码IMR确认你期望的中断源如RXIM已经使能。检查触发水平TRIGRXTRIG和TXTRIG的设置是否合理设置成0会导致RX中断无效设置成1会导致每个字节都中断CPU负载高。检查原始状态RIS在中断服务程序中除了读MIS也读一下RIS寄存器。看看是不是有其他未使能但已发生的中断事件占用了状态位虽然这通常不会阻止其他中断但有助于理解总线活动。中断标志清除问题是否在ISR中清除了所有已处理中断的标志没有清除的标志会一直保持导致中断持续触发。特别注意清除标志是向I2CSICR的对应位写1而不是写0。问题4使用DMA时数据不完整或错位。检查DMA使能DMARXENA/DMATXENA位是否已置1检查DMA通道配置DMA的源地址/目标地址、传输数据量、地址递增模式是否正确配置I2C的FIFO数据寄存器地址是否作为DMA的端点检查FIFO触发与DMA请求DMA请求是由FIFO的触发条件产生的。确保RXTRIG/TXTRIG的设置与DMA传输的数据块大小相匹配。例如如果设置RXTRIG4那么DMA会在RX FIFO中有4个字节时被触发每次传输最好设置为4字节的倍数以避免FIFO中残留数据。仲裁DMA与CPU访问确保在DMA传输期间CPU不会同时去读写I2CFIFODATA寄存器以免造成数据混乱。调试利器状态寄存器轮询。在开发初期可以暂时禁用中断采用轮询方式读取I2CSRIS或I2CFIFOSTATUS寄存器配合简单的打印语句来观察通信过程中每个步骤的状态变化。这能帮你最直观地理解硬件的行为验证你的配置是否正确。例如在主机发送数据后轮询检查RXRIS位是否置位RXFF或RXFE状态如何然后再去读取数据。这种方式虽然效率低但对于排除配置错误非常有效。
网站建设 高端定制 企业官网