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.

MSP430FR5994: I2C master receive mode

Part Number: MSP430FR5994
Other Parts Discussed in Thread: HDC2010,

For our hardware, we are using the MSP430FR5994’s Port B2 in I2C master mode to communicate with a HDC2010 humidity sensor on a battery-powered device.  We’ve had some rare occasions on the boards in which the MSP430 locks up and the battery drains.  We’ve finally traced it down to an issue with I2C master receive mode.  In the file I2CEUSCIB.c in the MSP430 TI Drivers (version 2.20.00.08), in the function I2CEUSCIB_hwiIntFxn(), lines 315 through 325 are as follows:

 

                /*

                 * Start the I2C transfer in master receive mode by sending a

                 * START and STOP bit since it's the last byte

                 */

                    EUSCI_B_I2C_masterReceiveStart(hwAttrs->baseAddr);

                    while ( EUSCI_B_I2C_masterIsStartSent(hwAttrs->baseAddr) ) ;

                    EUSCI_B_I2C_masterReceiveMultiByteStop(hwAttrs->baseAddr);

 

                    Log_print1(Diags_USER2, "I2C:(%p) I2CEUSCIB_WRITE_MODE: -> I2CEUSCIB_READ_MODE; "

                                    "Reading w/ RESTART and STOP",

                                     hwAttrs->baseAddr);

 

The MSP430 will occasionally get stuck indefinitely on the while loop in the code above.  It initiates the I2C start, but it never sees an acknowledgement that the start is sent.  On a few boards, this occurs more regularly than others; it also appears that in certain high/low environmental temperature situations it occurs more frequently with certain boards.  I believe a proper solution would be to have a count limit on the while loop and then to abort the transfer upon failure.  However, we’re unsure of a reasonable loop limit count for this location.  I’m assuming there is a reasonable limit based upon the I2C clock speed, but I’m not sure what that is.  Do you have a suggested limit based upon the I2C bus settings, or another approach that may be suitable?

 

I also see a similar loop in I2CEUSCIB_primeTransfer().  Whatever solution makes sense in the ISR should also be applied in I2CEUSCIB_primeTransfer.

  • Hi Dan,

    I agree that having a counter in the loop will probably solve the issue, but out of curiosity, have you been able to capture the failure with a logic analyzer? I am wondering if the failure is on the humidity sensor side or the MSP side.

    Below is a data transfer diagram from the I2C spec document (linked below)

     

    It looks like the ACK should be seen in the next clock cycle immediately after the last data bit is sent. To be safe, I would have the count value in the while loop compensate for at least 2 I2C clock cycles after the last data bit it sent. 

    Please let me know if there are any other questions.

    Thanks,

    Mitch

  • Mitch,

    I had originally posed this question to Dan offline and he had posted it to the forum for me.

    I have not attempted to capture the error on a logic analyzer yet.  I'll see if I can do that and share the results.

    If it helps, I'm setting up the I2C bus as follows:

        I2C_Params i2cParams;
    
        /* Close the interface first if it is not NULL */
        if(hI2C)
        {
            I2C_close(hI2C);
            hI2C = NULL;
        }
    
        /* Open an interface to the I2C bus */
        Board_initI2C();
        I2C_Params_init(&i2cParams);
        i2cParams.transferMode = I2C_MODE_CALLBACK;
        i2cParams.transferCallbackFxn = humidityTxfrDone;
        i2cParams.bitRate = I2C_400kHz;
        hI2C = I2C_open(Board_I2C0, &i2cParams);
    

    The callback function tracks whether the I2C transfer completed successfully and posts to a semaphore as follows:

    static void humidityTxfrDone(I2C_Handle i2c, I2C_Transaction *txn, bool result)
    {
        /* Store whether the transaction was successful */
        i2cTxfrSuccess = result;
    
        /* Post to the semaphore to indicate the transaction is complete */
        Semaphore_post(semHumidityTxfrDone);
    }

    Then once I build an I2C message (either a read or a write command), I complete the transfer as follows:

            I2C_Transaction     i2cTransaction;

    /* Populate i2cTransaction as appropriate for the message */
    ...

    /* Start the transfer */ I2C_transfer(hI2C, &i2cTransaction); /* Wait until the transfer completes and return the results */ if(Semaphore_pend(semHumidityTxfrDone, 1000) == false) { /* Transaction took long. Kill the transaction. */ I2C_cancel(hI2C); } else { /* Transaction completed, but may not have completed successfully. * Return the I2C_transfer result. */ retVal = i2cTxfrSuccess; }

    I am using TI-RTOS with multiple tasks, however only a single task interfaces with the humidity sensor.  If there is anything I am doing in the I2C read/write procedure that may be causing a problem, please let me know.

    Thanks,

    Bryan

  • I've been trying a lot, and I have been unable to capture the error on a logic analyzer.  I will continue trying, but I wanted to post an update to let you know I was still working on this issue.  I'm also working on reliably triggering the issue so I can easily show that the code change fixes the issue.  I will post any future updates to my progress.

  • I have a little more information on this issue.  I switched to using blocking mode instead of callback mode for the I2C interface.  I can pretty easily get it in a mode where it gets stuck on line 663 in I2CEUSCIB.c:

            Semaphore_pend(Semaphore_handle(&(object->transferComplete)),
                    BIOS_WAIT_FOREVER);
    

    The first I2C transaction is a master read.  I'm assuming there is an error interrupt that should be firing if the slave is not responsive.  I have breakpoints in the ISR for the error interrupt conditions and it never gets there.

  • Hi Bryan,

    Thanks for the update. Since you are able to get it stuck in this line, are you able to see the error on a logic analyzer now? I am curious to know if the slave is not responding or if the MSP is not recognizing the slave response.

    Also, I noticed you mentioned that you were using the version 2.20.00.08 drivers. Did you mean to say version 2.20.00.06?

    Thanks,

    Mitch
  • I still have been unable to capture a failure on the logic analyzer. I think my logic analyzer is retriggering on a glitch, because whenever it does fail I get a logic analyzer capture with no data (SDA and SCL are high the entire capture).

    I'm using TI-RTOS version 2.20.00.06. Under TI-RTOS the TI drivers for the MSP430 is at version 2.20.00.08 (full path is tirtos_msp43x_2_20_00_06/products/tidrivers_msp43x_2_20_00_08).

    Thanks,
    Bryan
  • Hi Bryan,

    It's hard to tell if the error is on the MSP side or the sensor side. I will check with our team to see if there are any known issues with the SW driver you are using. Have you altered the SW at all? If so, what alterations did you make?

    Thanks,

    Mitch
  • Mitch,

    Sorry for the long delay in response to this topic, I've been bouncing between several different tasks.  I still have not captured a failure on a logic analyzer, but I have determined one hardware issue.  My boards had 100K resistors placed for pullup resistors on the I2C lines instead of 10K resistors.  Surprisingly communication typically works just fine (and works consistently on some boards), but this may be the source of the failed communication on some boards under certain environmental conditions.

    In the example code I have in the earlier posts, I also changed the code so that I do not call I2C_cancel().  After I2C_transfer(), I wait for the semaphore to post and then return pass/fail based upon the results.  If I failed, then I just stop trying to talk to the humidity sensor and try again later.  I did catch at least one instance in which I2C_cancel() got stuck clearing the transaction queue; I think the queue was already clear and it wasn't recognizing that there was nothing to clear out.  It then just sat in its while loop trying to clear the queue that wouldn't empty.

    If it makess a difference, I have a separate power section for the humidity sensor, so the humidity sensor gets powered off between communication sessions which are minutes apart.  I have confirmed the humidity sensor gets fully powered down prior to powering it back up, and that the I2C peripheral is disabled when the humidity sensor is off.  The pullups are in the humidity sensor power section, meaning the pullups are not active until I power up the humidity sensor.

    So far I have only used a logic analyzer for viewing the I2C lines.  I am going to view the transactions using an oscilloscope and see if I can tell what is happening on the I2C with the weaker pullups.  If you have any insights as to what is expected to happen with weak pullups (either on the MSP430 side or the HDC2010 side), please let me know.

  • Hi Bryan,

    Great catch! You will definitely want to reduce your pull up resistor values. If the pullup resistor value is too high, the I2C line may not rise to a logical high before it is pulled low. This could potentially be the cause of your issue.

    I'm not sure what speed you are running your I2C communication, but you will generally want to keep your pull-ups at or below 10K. Here are some resources that will allow you to fine tune your resistor values based on the bus capacitance and I2C speed:

    I2C Bus Pullup Resistor Calculation App Note:
    www.ti.com/.../slva689.pdf

    Official I2C Bus Spec:
    www.nxp.com/.../UM10204.pdf

    I'd recommend swapping out your resistors with the recommended values described in these documents. Please let me know what you find!

    Thanks,

    Mitch
  • Mitch,

    Thanks for the reference to the pullup resistor calculator.  If I'm reading the right places of the datasheets, I believe the MSP430FR5994 has a maximum capacitive load of either 3pF or 5pF on its input pins, and the HDC2010 has 0.5pF capacitive load on its I2C pins.  We have been operating in fast mode, so depending on the capacitive load the maximum pullup value is somewhere between 64KOhm and 100KOhm.  This would make sense to me then why we would be seeing things work fine on some boards and some boards failing under certain environmental conditions.

    However, what does baffle me is that I don't see an error interrupt in this case.  I have all interrupts enabled and I have never triggered on an error interrupt.  In order to recover from the error, I have had to operate in callback mode and then on the first failure power down the humidity sensor and disable the I2C peripheral on the MSP430.  If I do this, I can at least consistently recover from the error.  On boards that I have replaced the 100K resistors with 10K resistors, I can consistently communicate with the humidity sensor without errors.

  • Hey Bryan,

    What error interrupt are you expecting to see, exactly? Are you saying that the device gets "locked up" with the 100K resistors?

    Thanks,

    Mitch
  • Hey Bryan,

    I haven’t heard from you for a little while, so I’m assuming you were able to resolve your issue. If this isn’t the case, please click the "This did NOT resolve my issue" button and reply to this thread with more information. If this thread locks, please click the "Ask a related question" button and in the new thread describe the current status of your issue and any additional details you may have to assist us in helping to solve your issues.

    Thanks!

    -Mitch

**Attention** This is a public forum