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.

MSP432P401R: I2C clock hang

Part Number: MSP432P401R

I wrote some code that is supposed to follow the following scheme to communicate with a sensor using I2C.

I expected the oscilloscope reading to be what's in the following table:

S 1 1 0 0 0 0 0 W ACK 0 0 0 0 1 0 0 0 ACK S 1 1 0 0 0 0 0 R ACK 0 0 0 0 0 0 0 0 ACK/NACK

P

What I got was what is pictured:

I interpret that as:

S 1 1 0 0 0 0 0 W ACK 0 0 0 0 1 0 0 0 ACK P S 1 1 0 0 0 0 0 R ACK 0 0 0 0 0 0 0 0 ACK 1 1 1 1 1 1 1

Issues/Sources of confusion:

  • The clock gets held low and the bus can't be used again until a reset occurs
  • Extra clock pulses are generated and a stop isn't sent
  • I've tested this bug with a separate I2C device and gotten the same issue

My code is as follows:

#include "driverlib.h"

#define I2C_PINS GPIO_PORT_P3, GPIO_PIN6 + GPIO_PIN7
#define USCI_MODULE EUSCI_B2_BASE
#define SLAVE_ADDRESS 0b1100000
#define PROX_REGISTER 0x08

volatile uint16_t response = 0;
volatile uint8_t lsb = 0;
volatile uint8_t msb = 0;


/* I2C Master Configuration Parameter */
const eUSCI_I2C_MasterConfig i2cConfig =
{
        EUSCI_B_I2C_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
        3000000,                                // SMCLK = 3MHz
        EUSCI_B_I2C_SET_DATA_RATE_100KBPS,      // Desired I2C Clock of 100khz
        0,                                      // No byte counter threshold
        EUSCI_B_I2C_NO_AUTO_STOP                // No Autostop
};


int main(void) 
{
    WDT_A_holdTimer();

    GPIO_setAsPeripheralModuleFunctionInputPin(I2C_PINS, GPIO_PRIMARY_MODULE_FUNCTION);

    /* Initializing I2C Master to SMCLK at 100khz with no autostop */
    I2C_initMaster(USCI_MODULE, &i2cConfig);

    /* Specify slave address */
    I2C_setSlaveAddress(USCI_MODULE, SLAVE_ADDRESS);

    /* Set Master in transmit mode */
    I2C_setMode(USCI_MODULE, EUSCI_B_I2C_TRANSMIT_MODE);

    /* Enable I2C Module to start operations */
    I2C_enableModule(USCI_MODULE);

    while (I2C_isBusBusy(USCI_MODULE) == EUSCI_B_I2C_BUS_BUSY);

    I2C_masterSendSingleByte(USCI_MODULE, PROX_REGISTER);
    I2C_masterReceiveStart(USCI_MODULE);
    lsb = I2C_masterReceiveMultiByteNext(USCI_MODULE);
    msb += I2C_masterReceiveMultiByteNext(USCI_MODULE);
    I2C_masterReceiveMultiByteStop(USCI_MODULE);
    response = (msb << 8 ) | (lsb & 0xff);

    while(1);
}

If anyone could shed some light on what is wrong, I would greatly appreciate it.

Thanks,

Christian

  • Christian,

    I tried to recreated your issue using our sensor boosterpack.  I was successful in recreating the issue. 

    I added the following line:

    while( I2C_masterIsStopSent(USCI_MODULE) != EUSCI_B_I2C_STOP_SEND_COMPLETE );

    Just after this line:


    I2C_masterSendSingleByte(USCI_MODULE, PROX_REGISTER);


    And it seemed to give me the missing NACK and Stop(P).  Does this also work for you?

    However, I still find issues with the code.  When I single step through the program, I see the values for lsb (but not always msb) load properly; but when I let it run and then pause, I notice lsb and msb are still equal to 0.

    Do you see this same issue?  I have noticed all of the example codes I come across use interrupts and none attempt polling as you have.  I do not for sure know the reason for this, but I will be looking into it.  I might suggest going to interrupt based code instead of polling unless you have a reason to stick strictly to polling.

  • OK.  I changed this to use interrupts as I had suggested in the prior post using this example code as a base.  I think it will be useful to you.  Please note that I use USCI_B1 so you will have to correct that both in the macro definition and in the ISR there are a few places referencing B1.  Also, good to note is that the example code I used sets the stop bit after the second to last bit has been received that way on the reception of the last byte, the TXSTP bit is already set and the NACK and Stop(P) will be set after the final RX happens.

    Here is the code:

    #include <ti/devices/msp432p4xx/driverlib/driverlib.h>
    
    #define I2C_PINS GPIO_PORT_P6, GPIO_PIN4 + GPIO_PIN5
    #define USCI_MODULE EUSCI_B1_BASE
    #define SLAVE_ADDRESS 0b1000000
    #define PROX_REGISTER 0x03
    
    volatile uint16_t response = 0;
    volatile uint8_t lsb = 0;
    volatile uint8_t msb = 0;
    static volatile uint32_t xferIndex = 0;
    static volatile bool msbCaptured = false;
    /* I2C Master Configuration Parameter */
    const eUSCI_I2C_MasterConfig i2cConfig =
    {
            EUSCI_B_I2C_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
            3000000,                                // SMCLK = 3MHz
            EUSCI_B_I2C_SET_DATA_RATE_100KBPS,      // Desired I2C Clock of 100khz
            0,                                      // No byte counter threshold
            EUSCI_B_I2C_NO_AUTO_STOP                // No Autostop
    };
    
    int main(void)
    {
        WDT_A_holdTimer();
    
        GPIO_setAsPeripheralModuleFunctionInputPin(I2C_PINS, GPIO_PRIMARY_MODULE_FUNCTION);
    
        I2C_disableModule(USCI_MODULE); //Change 1
        /* Initializing I2C Master to SMCLK at 100khz with no autostop */
        I2C_initMaster(USCI_MODULE, &i2cConfig);
    
        /* Specify slave address */
        I2C_setSlaveAddress(USCI_MODULE, SLAVE_ADDRESS);
    
        /* Set Master in transmit mode */
        I2C_setMode(USCI_MODULE, EUSCI_B_I2C_TRANSMIT_MODE);
    
        /* Enable I2C Module to start operations */
        I2C_enableModule(USCI_MODULE);
    
        /* Enable and clear the interrupt flag */
        I2C_clearInterruptFlag(USCI_MODULE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
        //Enable master Receive interrupt
        I2C_enableInterrupt(USCI_MODULE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
        Interrupt_enableInterrupt(INT_EUSCIB1);
    
        while (I2C_isBusBusy(USCI_MODULE) == EUSCI_B_I2C_BUS_BUSY);
    
        I2C_masterSendSingleByte(USCI_MODULE, PROX_REGISTER);
        /* Wait until byte is sent before receive.*/
        while( I2C_masterIsStopSent(USCI_MODULE) != EUSCI_B_I2C_STOP_SEND_COMPLETE );
        I2C_masterReceiveStart(USCI_MODULE);
    
        /* Wait until last byte received */
        while( I2C_masterIsStopSent(USCI_MODULE) != EUSCI_B_I2C_STOP_SEND_COMPLETE );
    
        /* Wait to ensure value has been loaded into msb. */
        while(!msbCaptured)
        {
            ;
        }
        
        /* Swap byte order and load into response */
        response = (msb << 8 ) | (lsb & 0xff);
    
        while(1);
    }
    
    /*****************************************************************************
     * eUSCIB0 ISR. The receive operations happen within this ISR.
     *****************************************************************************/
    void EUSCIB1_IRQHandler(void)
    {
        uint_fast16_t status;
    
        status = I2C_getEnabledInterruptStatus(USCI_MODULE);
        MAP_I2C_clearInterruptFlag(USCI_MODULE, status);
    
        /* Receives bytes into the receive buffer. If we have received all bytes,
         * send a STOP condition */
        if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0)
        {
            if(xferIndex == 0)
            {
                I2C_masterReceiveMultiByteStop(USCI_MODULE);
                lsb = I2C_masterReceiveMultiByteNext(USCI_MODULE);
                xferIndex++;
            }
            else if(xferIndex == 1)
            {
                msb = I2C_masterReceiveMultiByteNext(USCI_MODULE);
                I2C_disableInterrupt(USCI_MODULE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
                msbCaptured = true;
            }
        }
    }
    
    

  • Christian, I haven't heard from you in a while. Hopefully that means you were able to get this working?
  • Hey John,
    Sorry for the delayed response. I used the code that you provided earlier (but with different pins and eusci module) and I am still having issues with clock stretching on bit 7 but it is happening on the second receive bit instead of generating extra clock pulses. I'm going to do some further testing to see if I can isolate the issue.

**Attention** This is a public forum