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.

[参考译文] MSP430F5359:使用 driverlib 处理重复起始条件:奇怪的停止条件

Guru**** 2528040 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/699905/msp430f5359-handling-repeated-start-condition-with-driverlib-strange-stop-condition

器件型号:MSP430F5359

您好!

我在 driverlib 之上构建了两个 i2c_write 和 i2c_read 轮询函数。

我需要执行一个包含重复起始条件的 I2C 读取。
由于我的器件响应错误、我在 I2C 总线上插入了逻辑分析仪、我注意到在重复启动之前会发生停止、而我使用的 driverlib 函数应该'NT 触发停止条件。
我的目标器件在两条命令之间执行停止操作以及在总线上连接的其他器件时工作良好、但我无法从容地处理重复启动。


逻辑分析仪输出:




我编写的代码

bool i2c_read (uint8_t device_address、uint8_t register_address、uint8_t *数据、uint8_t len)
{
bool 结果= false;
USCI_B_I2C_initMaster (USCI_B2_base、device_address);
USCI_B_I2C_setMode (USCI_b2_base、USCI_B2_transmit);USCI_b2_b2_mode
USCI_B_I2C_ENABLE (USCI_B2_base);
_disable_interrupts ();

//
if (!USCI_B_I2C_masterSendMultiByteStartWithTimeout (USCI_B2_base、register_address、400)
)转到末尾;

/*读取结果*/
USCI_B_I2C_setMode (USCI_B2_base、USCI_B_I2C_Receive_mode);
USCI_B_I2C_ENABLE (USCI_B2_base);

如果(




















B = 1){if (!USCI_B_I2C_masterReceiveSingleStartWithTimeout (USCI_B2_base、timeout))转至结束;*数据= USCI_B_I2C_masterReceiveSingle (USCI_B2_base);}否则{USCI_B2_masterReceiveMultitleStart (UCI_ble+);}+(UI2C_ble_ble_end);(UI2C_while = 1 +)+(UI2C_ble_ble_end);(while +)+(+)+)++(UI2C_Receive+)+(while (+)+)++++++++(UI2C_Receive+)(while (+)+)+(UI2C_Byte+)(while (+)+)+++++(while ++)(+)++++++++++(1

为什么我观察到这种停止条件 ?

我出了什么问题?

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

    您好!

    感谢您的详细博文。 遗憾的是、I2C 问题不是我的专长、但我会尽力帮助解决问题。 首先、您能否缩小导致停止条件出现的 DriverLib 函数的范围? 同时、您可能会发现以下线程对于重复启动条件很有帮助。 我尝试找到具有重复启动功能的代码示例、但似乎它们仅适用于我们的 MSP432器件(不确定引用它们是否有用)。

    在 MSP430x5xx 用户指南中、我找到 了在主发送器模式中再次设置 UCTXSTT 会触发一个重复起始条件的位置。 在主机接收模式部分(第1007页)、我发现在接收到最后一个数据字节之前必须将 UCTXSTT 位置位; 也就是说、在 UCRXIFG 被置位并且具有第二个到最后一个字节的 UCRXBUF 被读取后、应立即置位 UCTXSTT 位。

    此致、

    James

    MSP 客户应用

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

    似乎没有任何 driverlib 函数允许在发出重新启动命令之前等待 TXIFG:

    USCI_B_I2C_masterSendMultiByteStart (...、baseAddress);
    
    //发送中断标志轮询。
    while (!(HWREG8 (baseAddress + OFS_UCBxIFG)& UCTXIFG)
    ){
    ;
    }
    HWREG8 (baseAddress + OFS_UCBxIFG)&&~UCTXIFG;
    
    USCI_B_I2C_masterReceiveSingleStart (...);
    
    数据= USCI_B_I2C_masterReceiveSingle (...); 

    (未经测试)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    大家好、感谢您的回答。
    触发停止条件的函数似乎是 USCI_B_I2C_masterSendMultiByteStartWithTimeout、但读取其代码时我看不到任何可能成为问题的东西。

    我还在用户指南中找到了该注释、但目前没有成功。 我再次置位 UCTXSTT 位、但无论如何都会生成停止条件。
    如果您可以为我提供一些重复启动的代码示例、即使对于 MSP432也是如此、这将是一个不错的选择。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    大家好、感谢您的回答。 由于您已将此代码示例发布在另一个 I2C 线程上、因此我已经对其进行了测试、但我无法使其正常工作。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我找到了一个讨论重复启动的 MSP432线程、我还在代码中找到了以下注释、这些注释可能会有所帮助。

    /*如果我们到达发送中断、则意味着我们位于
    
    *发送缓冲区的索引1。 在执行重复启动时、在到达
    
    *最后一个字节之前、我们需要将模式更改为接收模式、设置 START
    
    *条件发送位、然后将最终字节加载到 TXBUF 中。 

    此致、

    James

    MSP 客户应用

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

    我找到了 MSP432代码示例、其中包含我之前的回复中的注释。 请记住、MSP432的这些 DriverLib 函数可能不同于 MSP430 DriverLib 函数的操作。 我认为这可能有助于您作为参考。 重复起始条件似乎在 ISR 中处理。

    I2C_MASTER_RW_REPEATE_START-MASTER_CODE

    /*
    --------------------------------
    * MSP432 DriverLib - v3_21_00_05
    *--------------------
    *
    *-版权所有-、BSD、BSD
    *版权所有(c) 2016、德州仪器(TI)公司
    *保留所有权利。
    *
    *
    只要
    符合以下条件*、允许以源代码和二进制形式重新分发和使用:
    *
    *源代码的重新分发必须保留上述版权
    声明*、此条件列表和以下免责声明。
    *
    ***二进制形式的再发行必须在
    
    *随发行提供的文档和/或其他材料中复制上述版权声明、本条件列表和以下免责声明。
    *
    ***未经
    
    事先书面许可、不得使用德州仪器公司的名称或*其贡献者的名称认可或推广从本软件衍生的产品*。
    *
    *本软件由版权所有者和贡献者"按原样"提供
    *、
    
    不承担任何明示或暗示的保证、包括但不限于*适销性和特定用途适用性的暗示保证*。 在任何情况下、版权所有者或
    *贡献者都不对任何直接、间接、偶然、特殊、
    *模范、 或相应的损害(包括但不限于
    *采购替代产品或服务;丧失使用、数据或利润;
    *或业务中断)、但出于任何责任理论
    、*无论是在合同中、严格责任还是由于
    使用本软件而以任何方式产生的侵权行为(包括疏忽或*其他)
    、*即使已获悉可能会发生此类损坏。
    *--/版权--*/
    
    * MSP432 I2C - EUSCI_B0_BASE I2C 主机 TX 字节到 MSP432从机-重复启动
    *
    说明:此演示通过 I2C 总线连接两个 MSP432。 主
    设备*发送到从设备。 这是主代码。 它持续
    *传输一组数据、并演示如何实现 I2C
    *主发送器、发送多个字节、后跟重复起始
    *和读取多个字节。
    这是从传感器等 I2C 从器件读取寄存器值的常见操作。
    写入的 I2C 的*事务如下所示:
    *
    *______________________________
    *|开始| | |开始| | |
    *| 0x48Addr | 0x04 | 0x00 | 0x48Addr |<10 Byte Read>| Stop |
    *| W | | | R | | |
    *|_________________ _________________ _________________ _________________ _________________________________ _________________ |
    *
    * ACLK = n/a、MCLK = HSMCLK = SMCLK = BRCLK =默认 DCO =~3.0MHz
    *
    /|\/|\
    * MSP432P401 10k 10k MSP432P401
    * 从器件 || Master
    * -------- |||---
    * | P1.6/UCB0SDA|<-|--+-|P1.6/UCB0SDA |
    * | || | |
    * | || | |
    * | P1.7/UCB.S.|<!---- >|P1.7/UCB.S. |
    * | | | |
    *
    作者:Timothy Logan
    /*
    DriverLib 定义*/
    #include "driverlib.h"
    
    /*标准定义*/
    #include 
    
    #include 
    #include 
    
    /* I2C 从机的从机地址*/
    #define SLAVE_ADDRESS 0x48
    #define NUM_OF_REC_Bytes 10
    
    /*变量*/
    const uint8_t TXData[2]={0x04、0x00};
    static uint8_t RXData[NUM_OF_REC_Bytes];
    static volatile UINT32_t xferIndex;
    static volatile bool MasterSent;
    
    /* I2C Master Configuration parameter */
    
    {i2i2ec_stopeConfig_bytes}
    EUSCI_B_I2C_CLOCKSOURCE_SMCLK、 // SMCLK 时钟源
    3000000、 // SMCLK = 3MHz
    EUSCI_B_I2C_SET_DATA_RATE 100KBPS、 //所需的100kHz I2C 时钟
    0、 //无字节计数器阈值
    EUSCI_B_I2C_NO_AUTO_STOP //无自动停止
    };
    
    int main (void)
    {
    volatile uint32_t ii;
    
    /*禁用看门狗*/
    MAP_WDT_A_HOLDTimer();
    
    /*为 I2C 选择端口1 -将引脚6、7设置为输入主模块功能、
    (UCB0SIMO/UCB0SDA、UCB0SOMI/UCB.S.)。
    *
    MAP_GPIO_setPeripheralModuleFunctionInputPin (GPIO_PORT_P1、
    GPIO_PIN6 + GPIO_PIN7、GPIO_PRIMARY_MODULE_FUNCTION);
    stopSent = false;
    memset (RXData、0x00、NUM_OF_REC_Bytes);
    
    /*以100kHz 的频率将 I2C 主设备初始化为 SMCLK,而不进行自动停止*/
    MAP_I2C_initMaster (EUSCI_B0_BASE、&i2cConfig);
    
    /*指定从地址*/
    MAP_I2C_setSlaveAddress (EUSCI_B0_BASE、SLAVE_ADDRESS);
    
    /*将主设备设置为传输模式*/
    MAP_I2C_setMode (EUSCI_B0_BASE、EUSCI_B_I2C_Transmit 模式);
    
    /*启用 I2C 模块以启动操作*/
    MAP_I2C_enableModule (EUSCI_B0_BASE);
    
    /*启用和清除中断标志*/
    MAP_I2C_clearInterruptFlag (EUSCI_B0_BASE、
    EUSCI_B_I2C_Transmit INTERRUPT0 + EUSCI_B_I2C_Receive_INTERRUPT0);
    //启用主机接收中断
    MAP_I2C_enableInterrupt (EUSCI_B0_BASE、EUSCI_B_I2C_Transmit INTERRUPT0);
    MAP_Interrupt_enableSlepOnIsrExit();
    MAP_Interrupt_enableInterrupt (INT_EUSCIB0);
    
    while (1)
    {
    /*确保最后一个交易已完全发送*/
    while (MAP_I2C_masterIsStopSent (EUSCI_B0_BASE)== EUSCI_B_I2C_Sending _stop);
    
    /*发送开始和发送缓冲区的第一个字节。 我们必须发送
    *两个字节、用于清理缓冲区中的任何内容
    *发送*/
    MAP_I2C_masterSendMultiByteStart (EUSCI_B0_BASE、TXData[0]);
    MAP_I2C_masterSendMultiByteNext (EUSCI_B0_BASE、TXData[0]);
    
    
    /*在发送 STOP 后启用传输中断*/
    MAP_I2C_enableInterrupt (EUSCI_B0_BASE、EUSCI_B_I2C_Transmit INTERRUPT0);
    
    /*当停止条件尚未发出时... *
    while (!stopSent)
    {
    MAP_PCM_gotoLPM0InterruptSafe ();
    }
    
    stopSent = false;
    }
    }
    
    /*********
    * eUSCIB0 ISR。 重复的启动和发送/接收操作在
    该 ISR 内发生*。
    秘书长的报告 /
    void EUSCIB0_IRQHandler (void)
    {
    uint_fast16_t status;
    
    STATUS = MAP_I2C_getEnabledInterruptStatus (EUSCI_B0_BASE);
    MAP_I2C_clearInterruptFlag (EUSCI_B0_BASE、STATUS);
    
    /*如果我们到达发送中断、则意味着我们位于的索引1
    *传输缓冲区。 重复启动时、我们才会到达
    *我们需要将模式更改为接收模式的最后一个字节、设置开始
    *条件发送位、然后将最终字节加载到 TXBUF 中。
    *
    IF (STATUS & EUSCI_B_I2C_Transmit _INTERRUPT0)
    {
    MAP_I2C_masterSendMultiByteNext (EUSCI_B0_BASE、TXData[1]);
    MAP_I2C_DisableInterrupt (EUSCI_B0_BASE、EUSCI_B_I2C_Transmit INTERRUPT0);
    MAP_I2C_setMode (EUSCI_B0_BASE、EUSCI_B_I2C_Receive_mode);
    xferIndex = 0;
    MAP_I2C_masterReceiveStart (EUSCI_B0_BASE);
    MAP_I2C_enableInterrupt (EUSCI_B0_BASE、EUSCI_B_I2C_Receive_INTERRUPT0);
    
    }
    
    /*将字节接收到接收缓冲区中。 如果我们已接收所有字节、
    *发送停止条件*/
    IF (STATUS & EUSCI_B_I2C_Receive_INTERRUPT0)
    {
    if (xferIndex = NUM_OF_REC_Bytes - 2)
    {
    MAP_I2C_masterReceiveMultiByteStop (EUSCI_B0_BASE);
    RXData[xferIndex+]]= MAP_I2C_ReceivmasterMultiByteNext (EUSCI_B0_BASE);
    }
    否则、如果(xferIndex = NUM_OF_REC_Bytes - 1)
    {
    RXData[xferIndex++]= MAP_I2C_ReceivmasterMultiByteNext (EUSCI_B0_BASE);
    MAP_I2C_DisableInterrupt (EUSCI_B0_BASE、EUSCI_B_I2C_Receive_INTERRUPT0);
    MAP_I2C_setMode (EUSCI_B0_BASE、EUSCI_B_I2C_Transmit 模式);
    xferIndex = 0;
    stopSent = true;
    MAP_Interrupt_disableSlepOnIsrExit();
    }
    其他
    {
    RXData[xferIndex+]]= MAP_I2C_ReceivmasterMultiByteNext (EUSCI_B0_BASE);
    }
    
    }
    
    

    此致、

    James

    MSP 客户应用

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

    大家好、感谢您的回答。 在过去几周里、我对这个问题进行了大量研究、我发现我只是误编了我的日志分析器。 我已经设置了更高的采样率(5MHz)、并且不再观察到奇怪的停止条件。

    从硬方面来说、一切似乎都正常、我设法使我的软件实现工作。 但是、相同的代码是否正常工作取决于 I2C 块的最终时钟...

    我使用 driverlib 来配置我的 i2c 块、如果我在配置结构中将数据速率设置为100000、那么一切都可以正常工作。
    如果我输入10000的数据速率、它将不再工作。

    我注意到在 driverlib 中、数据速率只有两个可用的值(作为宏):100000和400000。 但我还注意到、在内核中、该参数仅用于除以 i2cClk 参数、以获取将写入 OFS_UCBxBRW 的预分频值。

    我使用频率为1MHz 的 SMCLK 作为 USCI 块的输入时钟。

    在我的案例中,10000是否是数据速率的有效值?

    感谢您的回答。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    此问题可能与超时有关。 在100kHz 的较高 I2C 频率下、超时很可能不会被触发、但可能处于10kHz 的较低(较慢)频率。 我建议使用100kHz。

    此致、

    James

    MSP 客户应用