This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] 使用中断/轮询进行 I2C NACK 检测

Guru**** 2487345 points
Other Parts Discussed in Thread: TCA9555, C2000WARE

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/799412/i2c-nack-detection-using-interrupts-polling

器件型号:TMS320F28377S
主题中讨论的其他器件:TCA9555C2000WARE

我已经为 TMS320F2837xS 系列控制器开发了一个用于多从系统的 I2C 通信驱动程序、我正在对用于28377S 的 LaunchPadXL 进行单元测试。

我遇到了一个用作从器件的评估模块(IO_EXPANDER_EVM、重新组装了 TCA9555)的硬件问题、即使正确解决、TCA9555也不会 ACK。 这是一个硬件设置问题、因为我重新组装了另一个 EVM、其中 TCA9555具有相同的地址引脚配置、工作正常。  

我能够检测这些 nack、因为我一直在使用协议分析器来监控 I2C 总线事务。 (在 Addr 列中附加了带有“*”的 snip,表示 nacks)。

我在驱动程序中包含了一个标志、用于指示是否根据 I2C 状态寄存器(I2CSTR)接收到 NACK。 但是、NACK 位似乎永远不会被置位。 我认为在轮询 NACK 位时缺少一些东西。 2837xS 控制器始终是主控制器、并在非重复模式下使用。

我的读取和写入事务中断源是 ACCESS_READY 和 STOP_Condition 检测到的。 我检查中断服务例程中的 NACK 位

每当发出停止条件时、状态寄存器中的 NACK 位是否都会被清除?

我是否必须显式启用 NACK 中断才能检测 NACK? 如果我这么做、正常读取结束时预期的 NACK (由主控制器生成)是否也会生成一个中断、我必须在 ISR 中对此进行说明?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Ruta、

    在您的多从硬件设置中、您说同一总线上有多个 TCA9555、其中一个正在工作、另一个不工作? 还是工作案例中的硬件完全不同?

    您能否共享正在轮询 NACK 位的 ISR 代码? 根据以下文档、当您在 ISR 中读取 I2CISRC 以获取中断代码时、I2CSTR.NACK 位可能会被清除。 但是、我不确定这是您遇到的行为。

    I2CISRC 寄存器说明:

    您不必启用 NACK 中断来轮询 I2CSTR.NACK 位、即可看到该位已设置。 TRM 中的位描述表示" CPU 可以轮询 NACK使用 NACK 中断请求。"

    NACK 中断仅在 C2000器件为发送器时适用、因此不会检测到主器件生成的 NACK。

    最棒的

    Kevin

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好、Kevin、感谢您的回复。 我看到我造成了一些模棱两可的情况,所以让我澄清一下(我的道歉)。

    1.我的驱动程序将扩展到多个从器件(并非所有 IO 扩展器、而是 RTC、DAC_EVM 和 IO 扩展器 EVM)。 多从站支持正在进行中。

    2.我的部门独立测试两个 IO 扩展器 EVM (使用 TCA 9555)(它们不是同时在同一 I2C 总线上、因为它们都具有相同的地址引脚配置)。 我运行的是相同的单元测试代码、它基本上会切换端口0上的 LED。

    3.其中一个 IO 扩展器工作正常、我可以看到 LED 切换操作。 由于所有地址引脚都为高电平、因此在0x27H 寻址。

    第二个 IO 扩展器具有相同的地址引脚配置。 当我将其交换到总线上(完全移除第一个)并运行相同的单元测试时、我会得到一系列的 nack (如图所示)。

    我需要能够在软件中检测这些 nack、因此在 ISR 触发时包含了对 nack 位的检查。

    但是、当触发 STOP_Condition_Detected 中断时、似乎 NACK 位从未设置。

    根据重新读取技术参考、并由于您在上面的第一张图片、我开始怀疑每次读取 I2CISRC 寄存器时 NACK 位都会被清除。

    我将在此线程上共享我的 ISR 处理逻辑。 我将修改单元测试以对故障 IO 扩展器 EVM 执行读取操作、并尽快发布结果。

    **请注意:该函数名为 InterruptHandler,但根据设计采用一个参数,它由实际映射到 Hwi n BIOS cfg 的 void 参数函数调用。

    void i2cInterruptHandler (uint32_DTC baseAddress)
    {
    I2C_InterruptSource i2cInterruptSrc;
    uint16_DTC I;
    
    i2cInterruptSrc = I2C_getInterruptSource (baseAddress);
    
    IF (I2C_INTSRC_STOP_Condition = i2cInterruptSrc)
    {
    //如果在 NACK 后的写入结束时检测到 STOP,则重置消息状态
    //如果在正常写入结束时检测到停止条件,则重置消息状态
    if (MSGSTAT_WRITE_BUSY =currMsgPTR->messageStatus)
    {
    if (I2C_getStatus (baseAddress)& I2C_STS_NO_ACK)
    {
    currMsgPtr->messageStatus = MSGSTAT_nack_recd;
    }
    其他
    {
    currMsgPtr ->messageStatus = MSGSTAT_INACTIVE;
    }
    }
    //else、如果在成功读取结束时检测到停止条件、则将数据复制到消息缓冲器中
    否则(MSGSTAT_READ_BUSY =currMsgPTR->messageStatus)
    {
    对于(i = 0;i <(currMsgPtr -> dataByteCount);i++)
    {
    currMsgPtr ->dataByteBuffer[i]= I2C_getData (baseAddress);
    }
    
    currMsgPtr ->messageStatus = MSGSTAT_INACTIVE;
    }
    }
    
    否则、如果(I2C_INTSRC_REG_ACCESS_RDY = i2cInterruptSrc)
    {
    
    //如果主器件发出一个带有停止条件的写入操作,则不会触发该中断
    //如果从接收器接收到地址设置请求,则更新消息状态并发出 STOP
    在正常读取结束时应显示//NACK。
    
    
    //检查状态寄存器中的 NACK 位
    IF (I2C_getStatus (baseAddress)& I2C_STS_NO_ACK)
    {
    //发送停止条件并清除 NACK 位
    I2C_sendStopCondition (baseAddress);
    I2C_clearStatus (baseAddress、I2C_STS_NO_ACK);
    
    if (MSGSTAT_SEND_NOSTOP_BUSY =currMsgPTR->messageStatus)
    {
    currMsgPtr->messageStatus = MSGSTAT_nack_recd;
    }
    }
    
    //主设备需要在结束时将自身置于接收器模式
    //地址设置。
    如果(MSGSTAT_SEND_NOSTOP_BUSY =MscurrgtPtr ->messageStatus)则为其他地址
    {
    //现在发送一个新的起始条件作为主接收器
    currMsgPtr ->messageStatus = MSGSTAT_RESTART;
    
    //设置从机地址
    I2C_setSlaveAddress (baseAddress、currMsgPtr -> slaveChipAddress);
    //设置要读取的字节数
    I2C_setDataCount (baseAddress、currMsgPtr -> dataByteCount);
    //I2C_MDR_MST = 1、I2C_MDR_TX = 0
    I2C_setConfig (baseAddress、I2C_MASTER_Receive_mode);
    //I2C_MDR_STT = 1、I2C_MDR_STP = 1
    I2C_sendStartCondition (baseAddress);
    当数据字节计数器递减计数时、//停止条件将在总线上发送
    I2C_sendStopCondition (baseAddress);
    
    currMsgPtr ->messageStatus = MSGSTAT_READ_BUSY;
    }
    }
    
    对于与 I2C 相对应的 PIE 通道上的伪中断、则为 ELSE //纠正措施
    {
    I2C_clearInterruptStatus (baseAddress、i2cInterruptSrc);
    }
    //为组8中断发送 PIE ACK
    interrupt_clearACKGroup (interrupt_ack_group8);
    } 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    更新到上述帖子:我修改了器件测试、仅读取故障(Nack-ing) EVM 上的端口状态。 ISR 中 ACCESS_READY 部分内的逻辑执行并改变消息状态以反映 NACK、然后生成停止条件。 NACK 位保持为0、或在 STOP_Condition_Detected 的中断触发后读取 I2CISRC 寄存器后被清除。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Ruta、

    好的。 为了澄清您的最新测试、当 I2C_INTSRC_REG_ACCESS_RDY 中断触发时、NACK 状态标志被正确设置。 状态位按预期工作、对吧?

    对于 I2C_INTSRC_STOP_Condition 中断情况、如果您执行的测试注释掉以下行、以便在读取状态寄存器之前不读取中断源、该怎么办? 那么 NACK 位是否已设置?

    i2cInterruptSrc = I2C_getInterruptSource (baseAddress); 

    这将测试当 I2C_INTSRC_ARB_Lost、I2C_INTSRC_NO_ACK 或 I2C_INTSRC_STOP_Condition 中断发生时、读取中断源是否清除 NACK 标志。

    最棒的

    Kevin

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Kevin:

    感谢您的回复。

    1.我使用 NACKing IO 扩展器运行测试、只需读取端口状态。 当 I2C_INTSRC_REG_ACCESS_RDY 中断触发时、我的读取消息标志(请参阅上面的第52行)更改为 MSGSTAT_nack_recd。 因此、当中断触发时、NACK 位必须被置位。
    在地址设置期间、在接收到 NACK 时采取的操作是将 NACK 位清零并发送一个停止条件。
    之后我观察到寄存器状态、此时 NACK 位为0。

    2.我注释掉了您提到的那一行内容、并直接检查了 I2C_getInterruptSource (baseAddress)返回的值。 行为是相同的。

    那么这是否意味着在一个停止条件而不是 ACCESS_READY 条件之后简单地调用 I2C_getInterruptSource()将清除 I2C 状态寄存器中的 NACK 位? 这种情况下是否有权变措施?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Ruta、

    好的、(1)和(2)是我根据文档预期会发生的情况。

    Ruta Bhave 说:
    这是否意味着在停止条件而不是 ACCESS_READY 条件之后,只调用 I2C_getInterruptSource()就会清除 I2C 状态寄存器中的 NACK 位?

    由于 I2C_getInterruptSource()函数读取 I2CISRC.INTCODE 寄存器位,因此清除了相应的状态位,所以似乎就是这种情况。

    [引用 user="Ruta Bhut"]在这种情况下是否有权变措施?

    您的情况的一个可能的权变措施是使用 I2C_getStatus (baseAddress)函数来检测停止条件,而不是 I2C_getInterruptSource()

    最棒的

    Kevin

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Kevin:

    我进行了以下小改动、只是为了检查当我从 TCA9555接收到 nacks 时、在 I2C_getInterruptSource()之前调用的 I2C_getStatus()是否允许我读取状态寄存器并设置 NACK 位。

    void i2cInterruptHandler (uint32_DTC baseAddress)
    {
    I2C_InterruptSource i2cInterruptSrc;
    bool DTC nackDetected;
    uint16_DTC I;
    
    nackWasDetected = I2C_getStatus (baseAddress)& I2C_STS_NO_ACK;
    
    i2cInterruptSrc = I2C_getInterruptSource (baseAddress);
    
    IF (I2C_INTSRC_STOP_Condition = i2cInterruptSrc)
    {
    //如果在 NACK 后的写入结束时检测到 STOP,则重置消息状态
    //如果在正常写入结束时检测到停止条件,则重置消息状态
    if (MSGSTAT_WRITE_BUSY =currMsgPTR->messageStatus)
    {
    IF (nackWasDetected)(nackWasDetected)
    {
    currMsgPtr->messageStatus = MSGSTAT_nack_recd;
    }
    其他
    {
    currMsgPtr ->messageStatus = MSGSTAT_INACTIVE;
    }
    }
    

    但是、这仍然会将消息状态标志更改为 MSGSTAT_INACTIVE、而不是我所期望的 MSGSTAT_nack_recd。 我开始怀疑 NACK 位是否已设置、因为 EVM 上的地址引脚存在问题且 TCA9555无法识别地址0x27、因此应该会发生这种情况。 我很不明白为什么会发生这种情况。

    停止条件后 I2C 模式寄存器(I2CMDR)的内容为0x4220:自由运行、发送模式、模块启用。 当 I2C 主机产生一个停止条件时、主机(MST)位被自动清零。

    此外,使用 I2C_getStatus()函数检测停止条件而不是在 ISR 中读取 I2CISRC 寄存器会导致错误行为。  

    if (I2C_getStatus (baseAddress)& I2C_STS_STOP_Condition)
    {
    nackWasDetected = I2C_getStatus (baseAddress)& I2C_STS_NO_ACK;
    //如果在 NACK 后的写入结束时检测到 STOP,则重置消息状态
    //如果在正常写入结束时检测到停止条件,则重置消息状态
    if (MSGSTAT_WRITE_BUSY =currMsgPTR->messageStatus)
    {
    IF (nackWasDetected)(nackWasDetected)
    {
    currMsgPtr->messageStatus = MSGSTAT_nack_recd;
    }
    其他
    {
    currMsgPtr ->messageStatus = MSGSTAT_INACTIVE;
    }
    } 

    这就是我临时修改原始 ISR 的方法、在这种情况下、messageStatus 标志不会更改为 nack_recd 或不活动。 因此,出于某种原因,if()条件不会评估为 true。

    现在我将恢复到我的原始实现方案,并尝试在读取 I2CISC 之前弄清为何无法使用 I2C_getStatus()读取 NACK 位。

    如果您可以在停止条件后向正确方向指示以检测 NACK、我将不胜感激。

    非常感谢您迄今提供的帮助。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Ruta、

    在最新的代码片段中,I2C_getStatus()返回第1行中的值是什么? 它是否包含 NACK 位? 可以通过如下所示存储返回值并设置一个断点来检查该值:

    uint16_t I2C_int_FLAG_STATUS;//可用于存储状态值
    
    I2C_int_FLAG_STATUS = I2C_getStatus (baseAddress);
    
    ESTOP0;//此处的断点然后检查 I2C_int_FLAG_STATUS 

    这种行为对我来说似乎很奇怪、我本来希望在使用您的最新代码片段运行时设置 NACK 位。 当我有时间时、我会尝试在我的一侧测试此行为。

    您已经查看了 C2000ware 中的 i2c_ex2_EEPROM.c 示例、对吧? 目录中找到

    C:\ti\c2000Ware_1_00_06_00\driverlib\f2837xs\examples\cpu1\i2c\i2c_ex2_EEPROM.c

    此示例似乎在基于 msgStatus 状态机的停止条件后检测到 NACK。 请参阅以下中的注释:

    //
    //中断源=检测到停止条件
    //
    if (intSource = I2C_INTSRC_STOP_Condition)
    {
    //
    //如果已完成的消息正在写入数据,则将 msg 重置为非活动状态
    //
    if (currentMsgPtr ->msgStatus =MSG_STATUS_WRITE_BUSY)
    {
    currentMsgPtr ->msgStatus = MSG_STATUS_INACTIVE;
    }
    其他
    {
    //
    //如果在的地址设置部分收到 NACK 消息
    // EEPROM 读取、下面的代码进一步包含在寄存器中
    //访问就绪中断源代码将生成停止
    //条件。 在接收到停止条件后(此处)、设置
    //要重试的消息状态。 用户可能希望限制该数字
    //在生成错误之前重试次数。
    //
    if (currentMsgPtr ->msgStatus = MSG_STATUS_SEND_NOSTOP_BUSY)
    {
    currentMsgPtr ->msgStatus = MSG_STATUS_SEND_NOSTOP;
    } 

    最棒的

    Kevin

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好、Kevin、感谢您的回复

    我添加了断点、并在 EVM 上运行了另一个测试-正常工作的 EVM 和 NACKing 测试的 EVM。

    请注意、对于这两个电路板、我将运行一个简单的单元测试、该测试将器件上的一个端口配置为输出端口、然后将交替位模式写入端口以切换 LED (在良好的电路板上验证了这种行为)。 此单元测试仅发出 I2C 写入命令、其中包括正常写入结束时的 STP 位

    在有问题的电路板上、我在中断处理程序中的断点处观察到了 I2C 寄存器。 如 I2CSTR 寄存器窗口中所示、ARDY 置位、SCD 清零。 因此、当寻址器件在传输过程中处于 NACK 状态时、似乎会生成 ACCESS_READY 中断。 我的处理程序例程检测 ACCESS_READY 部分中的 NACK 位、将其清除并发出一个随后被检测到的停止条件。 这解释了为何 nackWasDetected 标志复位为0。 但是、它并未解释为什么尽管发出了一个发送 STOP 的写命令、但中断却是 ACCESS_READY 而不是 STOP。   

    2.对于功能板、我看到所有寄存器状态都按预期变化。

    [引用用户="Kevin Allen18"]

    您已经查看 了 C2000ware 中的 i2c_ex2_EEPROM.c 示例、对吧? 目录中找到

    C:\ti\c2000Ware_1_00_06_00\driverlib\f2837xs\examples\cpu1\i2c\i2c_ex2_EEPROM.c

    此示例似乎在基于 msgStatus 状态机的停止条件后检测到 NACK。 请参阅以下中的注释:

    //
    //中断源=检测到停止条件
    //
    if (intSource = I2C_INTSRC_STOP_Condition)
    {
    //
    //如果已完成的消息正在写入数据,则将 msg 重置为非活动状态
    //
    if (currentMsgPtr ->msgStatus =MSG_STATUS_WRITE_BUSY)
    {
    currentMsgPtr ->msgStatus = MSG_STATUS_INACTIVE;
    }
    其他
    {
    //
    //如果在的地址设置部分收到 NACK 消息
    // EEPROM 读取、下面的代码进一步包含在寄存器中
    //访问就绪中断源代码将生成停止
    //条件。 在接收到停止条件后(此处)、设置
    //要重试的消息状态。 用户可能希望限制该数字
    //在生成错误之前重试次数。
    //
    if (currentMsgPtr ->msgStatus = MSG_STATUS_SEND_NOSTOP_BUSY)
    {
    currentMsgPtr ->msgStatus = MSG_STATUS_SEND_NOSTOP;
    } 

    [/报价]

    在这里-在 ACCESS_READY 中断条件下检测到 NACK,而不是停止条件,随后清除 NACK 并发送停止条件。 该注释反映了在后续中断中检测到停止条件后采取的操作。 我的中断处理程序在检测方面类似、只是它还处理在 ACCESS_READY 之后将 I2C 主器件置于接收器模式。

    是否有任何解释说明、在从器件接收到 NACK 的情况下、ARDY 位会置位、但 SCD 不会置位? 我发出的写入命令应发送 STP 条件。

    感谢您的帮助、我非常感谢您的帮助。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好、Kevin、对于我之前的查询、我可能已经找到了一个解释、说明为什么尽管发出了一个带有停止条件的写入、ACCESS_READY 中断会被触发。  

    http://processors.wiki.ti.com/index.php/I2C_Tips#Detecting_and_handling_NACK

    似乎在硬件中清除了 STP 位、因此 ACCESS_READY 中断在 NACKing 事务之后被触发。 按照上述链接中的步骤和其余步骤、我能够针对似乎有效的 NACK 问题实施变通办法。

    这似乎是一个有效的解释吗? 如果您能确认、我将不胜感激。

    谢谢你。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Ruta、

    [引用用户="Ruta Bhut"]

    似乎在硬件中清除了 STP 位、因此 ACCESS_READY 中断在 NACKing 事务之后被触发。 按照上述链接中的步骤和其余步骤、我能够针对似乎有效的 NACK 问题实施变通办法。

    这似乎是一个有效的解释吗? 如果您能确认、我将不胜感激。

    [/报价]

    这似乎很有可能、并且 wiki 中讨论的测量值似乎可以使用(即 C6000中与 C2000器件相同的 I2C 模块)。

    我仍然想在我的一侧运行一些测试以自行验证、但情况确实如此、并与我过去编写的示例软件相匹配。 我将评估之后是否需要进行文档更新。

    谢谢、

    Kevin

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Ruta、

    我已经注意到了进一步的研究、并在将来自己运行测试、但现在没有时间了。

    除非您需要进一步的帮助、否则我会将此帖子标记为已关闭。

    最棒的
    Kevin