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.

[参考译文] MSP432WARE:I2C的某些DriverLib函数不支持超时-如何处理或重置?

Guru**** 2535750 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/575316/msp432ware-some-driverlib-functions-for-i2c-do-not-support-timeout---how-to-handle-or-reset

部件号:MSP432WARE

大家好,

我使用TI DriverLib作为I2C接口。  许多呼叫支持“超时”选项,可防止挂起。  但是,有一些基本函数,如I2C_isBusBusy(),I2C_getInterruptStatus(),I2C_masterIsStartSent(),I2C_masterReceiveMultiByteNext()以及其他不支持超时选项的函数。

特别是,如果我无法从设备读取(可能是因为它未连接),我经常看到EUSCI_Bx.STATW.UCBBUSY位设置为1,这表示总线“繁忙”。  这意味着,下次我尝试对I2C总线上的其他设备执行读写操作时,以下设备将挂起:

while (map_I2C_isBusyBusy (moduleInstance));

此函数没有超时,我看不到任何方法可以清除繁忙位以允许其他I2C事务继续进行。

如果I2C调用因超时而失败,建议使用什么方法来重置I2C控制器的状态,以允许其他操作继续(可能与同一EUSCI_Bx通道上的其他I2C设备一起使用)?

这似乎是DriverLib中的一个缺陷,其中一些操作支持超时,而有些操作不支持超时。  此外,似乎没有一种简单的方法可以将I2C控制器恢复到由于超时而导致操作失败之前的状态。

请举例说明在超时后如何正确重置I2C接口?  我曾尝试写信给UCBBUSY来澄清它,但这似乎行不通。

我在同一I2C接口上有两个TMP007温度传感器和AT24D02 EEPROM,并且需要通信才能保持稳定。  衷心感谢您的帮助!

Scott

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Scott,
    我将提请driverLib作者注意这一点。 API使用'Is'和'Get'等命名来指示及时的快照,而不是轮询或阻止类型的函数。 在While循环中,您描述需要添加自己的轮询超时。

    while (map_I2C_isBusyBusy (moduleInstance)&&--timeout);

    我想了解是什么导致繁忙的一段时间保持'1'。 根据技术参考手册,在停机条件后,UCBBUSY将被清除。 您何时发送停止?

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

    您好,Chris:

    非常感谢您的回复和帮助。  最好知道在发送停止条件后应该清除繁忙位。  我还想到了为忙等待循环创建自己的超时的提示,但尚未实现。

    我的方法仍然很粗糙,但当我故意断开I2C设备以查看是否可以检测到它并正常恢复时,就会发生挂起。  我在RTOS环境中运行,因此轮询操作而不是中断驱动操作是很好的,我将这些<不完整>示例主要基于DriverLib提供的示例。  我觉得当操作失败时,我并不总是发送停止条件,所以I2C接口仍然很忙,我会进一步调查。

    现在,这里是一些I2C类代码的摘录,用于写入和读取一系列字节:

    //------------------
    //@写入I2C地址并使用指定的数据和长度进行注册。
    //
    ////@param addr I2C地址写入
    //@param reg 哪个寄存器写入
    //@param pData指向要写入的数据字节
    //@param字节要写入的字节数量
    //
    @如果成功则返回true,否则返回false
    //------------------
    布尔CI2C::写入(uint8_t addr,uint8_t reg,uint8_t *pData,uint8_t bytes)
    {
    布尔成功;//操作成功还是失败?
    
    //待办:实施延迟
    //等待直至准备好写入
    while (map_I2C_isBusy (_moduleInstance));
    
    //加载设备从属地址
    MAP_I2C_setSlaveAddress (_moduleInstance,addr);
    
    //发送起始位和寄存器
    成功= MAP_I2C_masterSendMultiByteStartWithTimeout (_moduleInstance,reg,I2C_timeout);
    如果(!success)
    {
    返回false;
    }
    
    //等待TX完成
    while (!(MAP_I2C_getInterruptStatus (_moduleInstance,EUSCI_B_I2C_Transmit_INTERRUPT0)&)
    EUSCI_B_I2C_Transmit_INTERRUPT0);
    
    //检查是否为从ACK/nack
    IF ((MAP_I2C_getInterruptStatus (_moduleInstance,EUSCI_B_I2C_NAK_INTERRUPT))&
    EUSCI_B_I2C_NAK_INTERRUPT)
    {
    //如果是nack,则设置停止位并退出
    (void) map_I2C_masterSendMultiByteStopWithTimeout (_moduleInstance,I2C_timeout);
    return (fals);}
    
    
    //现在写入一个或多个数据字节
    同时(1)
    {
    //等待下一个INT
    while (!(MAP_I2C_getInterruptStatus (_moduleInstance,EUSCI_B_I2C_Transmit_INTERRUPT0)&)
    EUSCI_B_I2C_Transmit_INTERRUPT0);
    
    //如果没有数据可供跟踪,我们就会完成
    如果(字节== 0)
    {
    成功= MAP_I2C_masterSendMultiByteStopWithTimeout (_moduleInstance,I2C_timeout);
    MAP_I2C_clearInterruptFlag (_moduleInstance,EUSCI_B_I2C_Transmit_INTERRUPT0);
    返回成功;
    }
    //如果更多,则发送下一个字节
    否则
    {
    成功= MAP_I2C_masterSendMultiByteNextWithTimeout (_moduleInstance,*pData++,I2C_timeout);
    如果(!success)
    {
    返回false;
    }
    }
    字节--;
    }
    }//------------------
    
    
    //@从I2C地址和寄存器中读取数据和长度的指针。
    //
    ////@param addr I2C地址从
    //@param reg 哪个寄存器要读取
    //@param pData指向要读取的数据字节
    //@param字节要读取的字节数量
    //
    @如果成功则返回true,否则返回false
    //------------------
    bool CI2C::read(uint8_t addr, uint8_t reg, uint8_t *pData, uint8_t bytes)
    {
    布尔成功;//操作成功还是失败?
    
    //待办:实施延迟
    //等待就绪
    while (map_I2C_isBusy (_moduleInstance));
    
    //加载设备从属地址
    MAP_I2C_setSlaveAddress (_moduleInstance,addr);
    
    //发送起始位和寄存器
    成功= MAP_I2C_masterSendMultiByteStartWithTimeout (_moduleInstance,reg,I2C_timeout);
    如果(!success)
    {
    返回false;
    }
    
    //等待TX完成
    while (!(MAP_I2C_getInterruptStatus (_moduleInstance,EUSCI_B_I2C_Transmit_INTERRUPT0)&)
    EUSCI_B_I2C_Transmit_INTERRUPT0);
    
    //检查是否为从ACK/nack
    IF ((MAP_I2C_getInterruptStatus (_moduleInstance,EUSCI_B_I2C_NAK_INTERRUPT))&
    EUSCI_B_I2C_NAK_INTERRUPT)
    {
    //如果是nack,则设置停止位并退出
    (void) map_I2C_masterSendMultiByteStopWithTimeout (_moduleInstance,I2C_timeout);
    return (fals);}
    
    
    //关闭TX并生成重新启动
    MAP_I2C_masterReceiveStart(_moduleInstance);
    
    //等待开始位完成
    while (map_I2C_masterIsStartSent (_moduleInstance));
    
    IF ((MAP_I2C_getInterruptStatus (_moduleInstance,EUSCI_B_I2C_NAK_INTERRUPT))&
    EUSCI_B_I2C_NAK_INTERRUPT)
    {
    //如果是nack,则设置停止位并退出
    (void) map_I2C_masterSendMultiByteStopWithTimeout (_moduleInstance,I2C_timeout);
    return (fals);}
    
    
    //读取一个或多个字节
    while (字节)
    {
    //如果读取1个字节(或最后一个字节),则生成符合规范的停止
    IF (字节--== 1)
    {
    成功= MAP_I2C_masterReceiveMultiByteFinishWithTimeout(_moduleInstance,pData,I2C_timeout);
    如果(!success)
    {
    返回false;
    }
    }
    否则
    {
    //等待下一个RX中断
    while (!(MAP_I2C_getInterruptStatus (_moduleInstance,EUSCI_B_I2C_Receive_INTERRUPT0)&)
    EUSCI_B_I2C_Receive_INTERRUPT0);
    
    //读取Rx字节
    *pData++= MAP_I2C_masterReceiveMultiByteNext(_moduleInstance);
    }
    }
    
    MAP_I2C_clearInterruptFlag (_moduleInstance,EUSCI_B_I2C_Transmit_INTERRUPT0);
    
    return(true);
    }
    
    

    正如您所看到的,有多种调用带有超时,还有一些只提供您提到的"快照"的调用。  如果我理解正确,如果我在返回FALSE指示故障之前得到超时并发送停止条件,那么应该清除所有繁忙位,以便我可以尝试与其他I2C设备(它们位于唯一的I2C地址上)通信?

    非常感谢您的提示和帮助!

    Scott

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Scott,
    如果您有时间,我建议您查看软件开发套件,并了解如何在TIRTOS/FreeRTOS环境中完成此操作。 以下是您参考的TMP007示例:

    dev.ti.com/.../

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

    您好,Chris:

    非常感谢您将指针指向示例。  我一定会看看TIRTOS/FreeRTOS是如何实现的。

    我想了一种恢复I2C控制器控制的方法,但它可能不是理想的方法。  我在这里分享只是为了完整。  每当我检测到超时或错误时,我都会调用以下命令:

    //------------------
    ///@简要通过强制停止
    ///将I2C控制器设置回已知状态 条件并清除任何挂起的中断。
    //------------------
    void CI2C:ResetController()
    {
    //强制停止位清除占线
    BITBAND_PERI(EUSCI_B_CMIS(_moduleInstance)->CTLW0,UCTXSTP_OFS)=1;
    //清除挂起的中断标志
    MAP_I2C_clearInterruptFlag(_moduleInstance, EUSCI_B_I2C_Transmit_INTERRUPT0|
    EUSCI_B_I2C_NAK_interrupt | EUSCI_B_I2C_STOP_interrupt);
    }
    
    

    这无疑会有所帮助,但您指出的示例可能会有更好的整体方法。

    非常感谢!

    Scott

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    很抱歉这么密集,但您能告诉我I2C_init(),I2C_open(),I2C_TRANSFER和I2C_CLOSE ()的来源是什么? 从 我看到的#include文件中,它们可能是通过ti/drivers/I2c.h导入的,但我在导航树中找不到此源。 您能否提供链接?

    再次感谢!
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Scott,
    感谢您发布解决方案。 如果您在C:\ti\tirrex-content\simplelink_msp432_sdk_1_20_00_45\sources\ti\drivers中查找与设备无关的I2c.c文件,然后如果您在i2c文件夹中查找I2CMSP432.c/h文件。

    希望能有所帮助,
    Chris
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好,Chris,另一个很愚蠢的问题,但我需要什么来下载此内容? 现在我只有DriverLib,没有TIRTOS,FreeRTOS或您提到的驱动程序。 我需要下载哪个软件包才能查看这些驱动程序文件? 很抱歉,如果这应该很明显... :-)

    Scott
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Scott,
    您可以在 http://dev.ti.com/tirex/#/All上看到这些信息 。 如果您有CCS,则可以通过资源管理器,查看->资源管理器下载。 它称为SmImplLink MSP432 SDK。

    此致,
    Chris