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.

MSP430G2553:I2C problems

Other Parts Discussed in Thread: LDC1614, MSP430G2553

Hi,

I tried to use MSP430G2553 + LDC1614 + MPU6050 in my own PCB, but I encountered some problems in communicating with LDC1614 via I2C channel.

PCB configuration:
pull high resistance 10K
P1.6 > I2C SCL
P1.7 > I2C SDA
P2.4 > LDC1614 INTB
P2.5 > LDC1614 SD
LDC1614 ADDR > GND
LDC1614 CLKIN > GND

Problems:
1.The last packet cannot be sent when LDC1614 is I2C slave.
Assuming there are 3 Bytes, the code sends one byte as a packet each time.
UCB0TXIFG of IFG2 will be cleared when the second one is sent successfully.
Noise will then appear when the oscilloscope measures the signal from SCL pin.
2.MPU6050 works well with MSP430G2553 for I2C communication in the PCB.
3.The same code can work well for Launch pad (MSP430G2553 embedded) and LDC1614 EVM board.

int main(void)
{
    WDTCTL = WDTPW + WDTHOLD;   // Stop WDT
    BCSCTL1 = CALBC1_8MHZ;      //20201127   1M -> 8M
    DCOCTL  = CALDCO_8MHZ;
    BCSCTL2 |= DIVS_1;          //20201127   SMCLK / 2 = 4MHz
 
    __delay_cycles(10000);
 
    //reset EVM
    P2SEL &= ~BIT5;
    P2REN |= BIT5;
    P2DIR |= BIT5;              //P2.5 > SD
    P2OUT |= BIT5;
    __delay_cycles(480);
    P2OUT &= ~BIT5;
 
    I2C_init();
    EVM_init();
    MPU_init();
 
    for(;;)
    {
        sensor_mode();
        MPU_read();
    }
}
void MPU_init()
{
    UCB0CTL1 |= UCSWRST;        //20210927
    UCB0I2CSA = 0x68;
    UCB0CTL1 &= ~UCSWRST;       //20210927
    TX_Data[1] = 0x6B;
    TX_Data[0] = 0x00;
    TX_ByteCtr = 2;
    I2C_TX_DATA();
}
 
void MPU_read()
{
    UCB0CTL1 |= UCSWRST;        //20210927
    UCB0I2CSA = 0x68;
    UCB0CTL1 &= ~UCSWRST;       //20210927
    TX_Data[0] = 0x3B;
    TX_ByteCtr = 1;
    I2C_TX_DATA();
 
    RX_ByteCtr = 6;
    I2C_RX_DATA();
 
    xAccel = RX_Data[5] << 8 | RX_Data[4];
    yAccel = RX_Data[3] << 8 | RX_Data[2];
    zAccel = RX_Data[1] << 8 | RX_Data[0];
 
    __no_operation();
    __delay_cycles(600000);
}
 
void EVM_init()
{
    //LDC1614 INTB setup
    EVM_INT_DIR &= ~EVM_INT_BIT;           // INPUT
    EVM_INT_IE |= EVM_INT_BIT;             // interrupt enabled
    EVM_INT_IES |= EVM_INT_BIT;            // Hi->Lo Edge
    EVM_INT_IFG &= ~EVM_INT_BIT;          // Clear IFG
 
    Transmit(0x1C,0x8000);              //LDC13xx16xx_CMD_RESET_DEVICE
    Transmit(0x08,0xFFFF);              //LDC13xx16xx_CMD_REF_COUNT_CH0
    Transmit(0x0C,0x0000);              //LDC13xx16xx_CMD_OFFSET_CH0
    Transmit(0x10,0x044c);              //LDC13xx16xx_CMD_SETTLE_COUNT_CH0
    Transmit(0x14,0x1001);              //LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH0
    Transmit(0x1E,0x8c40);              //LDC13xx16xx_CMD_DRIVE_CURRENT_CH0
    Transmit(0x1A,0x1d01);              //LDC13xx16xx_CMD_CONFIG
    Transmit(0x1B,0x020C);              //LDC13xx16xx_CMD_MUX_CONFIG
    Transmit(0x19,0x0001);              //LDC13xx16xx_CMD_ERROR_CONFIG
}
 
void sensor_mode()
{
    EVM_INT_IE |= EVM_INT_BIT;
    EVM_read();
}
 
void EVM_read()
{
    static unsigned int evmStatus;
 
    if(dataReady == 0)
    {
        if(evmStatus & 0x0048)
        {
            dataReady=1;
        }
    }
 
    if(dataReady==1)
    {
        Receive(LDC13xx16xx_CMD_STATUS,&evmStatus);
        Receive(LDC13xx16xx_CMD_DATA_MSB_CH0,&allData[0]);
        Receive(LDC13xx16xx_CMD_DATA_LSB_CH0,&allData[1]);
 
        uHcal(allData[0],allData[1]);
        dataReady=0;
    }
}
 
void Transmit(unsigned char code, unsigned int data)
{
    __disable_interrupt();
    UCB0CTL1 |= UCSWRST;                //20210927
    UCB0I2CSA = 0x2A;
    UCB0CTL1 &= ~UCSWRST;
    TX_Data[2] = code;
    TX_Data[1] = (data >> 8) & 0xFF;
    TX_Data[0] = data & 0xFF;
    TX_ByteCtr = 3;
    done = FALSE;
    I2C_TX_DATA();
}
 
void Receive(unsigned char code, unsigned int* data)
{
    UCB0CTL1 |= UCSWRST;                //20210927
    UCB0I2CSA = 0x2A;
    UCB0CTL1 &= ~UCSWRST;
 
    TX_Data[0] = code;
    I2C_TX_DATA();
 
    RX_ByteCtr = 2;
    I2C_RX_DATA();
}
 
void I2C_TX_DATA()
{
    __disable_interrupt();
    IE2 |= UCB0TXIE;
    while (UCB0CTL1 & UCTXSTP);
    UCB0CTL1 |= UCTR + UCTXSTT;
    if(UCB0I2CSA == 0x2A)
    {
        __bis_SR_register(GIE);
        __no_operation();
    }
    else
    {
        __bis_SR_register(CPUOFF + GIE);
        __no_operation();
    }
}
 
void I2C_RX_DATA()
{
    __disable_interrupt();
    IE2 |= UCB0RXIE;
    while (UCB0CTL1 & UCTXSTP);
    UCB0CTL1 &= ~UCTR;
    UCB0CTL1 |= UCTXSTT;
    __bis_SR_register(CPUOFF + GIE);
    __no_operation();
    IE2 &= ~UCB0RXIE;
}
 
// USCIAB0TX_ISR
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
    if(UCB0CTL1 & UCTR)     // TX mode (UCTR == 1)
    {
        if (TX_ByteCtr)     // TRUE if more bytes remain
        {
            TX_ByteCtr--;                           // Decrement TX byte counter
            UCB0TXBUF = TX_Data[TX_ByteCtr];        // Load TX buffer
        }
        else                                        // no more bytes to send
        {
            UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
            IFG2 &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
            __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
        }
    }
    else // (UCTR == 0)                             // RX mode
    {
        if (--RX_ByteCtr)                           // RxByteCtr != 0
        {
            RX_Data[RX_ByteCtr] = UCB0RXBUF;        // Get received byte
            if (RX_ByteCtr == 1)                    // Only one byte left?
            {
                UCB0CTL1 |= UCTXSTP;                // Generate I2C stop condition
            }
        }
        else                                        // RxByteCtr == 0
        {
            RX_Data[RX_ByteCtr] = UCB0RXBUF;        // Get final received byte
            IFG2 &= ~UCB0RXIFG;
            __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
        }
    }
}

  • The problem seems that G2553 can work well with MPU6050 and LDC1614 separately. But has some problem when put these three devices on the same I2C bus.

    Can you show me the noise you catch?

  • I2C_TX_DATA disables interrupts before checking to see if the I2C port is stopped. This causes a previous transaction to stop in the middle. Which will happen because it doesn't wait for the transaction to complete. So that string of Transmit() calls to init the EVM does little more than annoy it.

    Also, Receive() doesn't do anything with the buffer address passed to it. It doesn't set the TX byte counter before calling I2C_TX_DATA so that call will fail to work as expected. There are probably more problems.

  • To make it even worse, Transmit() disables interrupts and resets the I2C port without bothering to check and see if it is busy. Which it will be.

    It isn't clear from the documentation for the G2553 but for many other parts you don't have to put the port in reset to change the I2C slave address.

  • Hi David,

    Sorry, I am a little confused. It seems that the problem lies on the software configuration and interrupt?

    Eason

  • Hi , Eason , David,

    I have tried catch noise but I encountered a new problem.

    MPU6050 and LDC1614 can't work now. I2C start condition can't generate(SCL can't pull low)

    I have tried fix the problem , I had remove all "__disable_interrupt();" , "UCB0CTL1 |= UCSWRST;" before change I2C slave address and set TX byte counter before calling I2C_TX_DATA. But I2C still can't work and encountered a new problem , I2C start condition can't generate(SCL can't pull low).

    I have tried recovery code , but problem still exist. Is there have other promble I missed?

    int main(void)
    {
        WDTCTL = WDTPW + WDTHOLD;  // Stop WDT
        BCSCTL1 = CALBC1_8MHZ;     //8M
        DCOCTL  = CALDCO_8MHZ;
        BCSCTL2 |= DIVS_1;         //SMCLK / 2 = 4MHz
    
         __delay_cycles(10000);
    
        //reset EVM
        P2SEL &= ~EVM_SD_BIT;
        //P2REN |= EVM_SD_BIT;
        P2DIR |= EVM_SD_BIT;              //P2.5 > SD
        P2OUT |= EVM_SD_BIT;
        __delay_cycles(I2C_TOGGLE_DELAY);
        P2OUT &= ~EVM_SD_BIT;
    
        I2C_init();
        MPU_init();
        EVM_init();
    
        for(;;)
        {
        	sensor_mode();
    		MPU_read();
        }
    }
    
    void MPU_init()
    {
        //UCB0CTL1 |= UCSWRST;              
        UCB0I2CSA = MPU6050;
        //UCB0CTL1 &= ~UCSWRST;            
        TX_Data[1] = 0x6B;
        TX_Data[0] = 0x00;
        TX_ByteCtr = 1;
        I2C_TX_DATA();
    }
    
    void MPU_read()
    {
        //UCB0CTL1 |= UCSWRST;             
        UCB0I2CSA = MPU6050;
        //UCB0CTL1 &= ~UCSWRST;            
        TX_Data[0] = 0x3B;
        TX_ByteCtr = 1;
        I2C_TX_DATA();
    
        RX_ByteCtr = 6;
        I2C_RX_DATA();
    
        xAccel = RX_Data[5] << 8 | RX_Data[4];
        yAccel = RX_Data[3] << 8 | RX_Data[2];
        zAccel = RX_Data[1] << 8 | RX_Data[0];
    
        __no_operation();
        __delay_cycles(600000);
    }
    
    void EVM_init()
    {
        //LDC1614 INTB setup
        EVM_INT_DIR &= ~EVM_INT_BIT;           // INPUT
        EVM_INT_IE |= EVM_INT_BIT;             // interrupt enabled
        EVM_INT_IES |= EVM_INT_BIT;            // Hi->Lo Edge
        EVM_INT_IFG &= ~EVM_INT_BIT;           // Clear IFG
     
        Transmit(0x1C,0x8000);              //LDC13xx16xx_CMD_RESET_DEVICE
        Transmit(0x08,0xFFFF);              //LDC13xx16xx_CMD_REF_COUNT_CH0
        Transmit(0x0C,0x0000);              //LDC13xx16xx_CMD_OFFSET_CH0
        Transmit(0x10,0x044c);              //LDC13xx16xx_CMD_SETTLE_COUNT_CH0
        Transmit(0x14,0x1001);              //LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH0
        Transmit(0x1E,0x8c40);              //LDC13xx16xx_CMD_DRIVE_CURRENT_CH0
        Transmit(0x1A,0x1d01);              //LDC13xx16xx_CMD_CONFIG
        Transmit(0x1B,0x020C);              //LDC13xx16xx_CMD_MUX_CONFIG
        Transmit(0x19,0x0001);              //LDC13xx16xx_CMD_ERROR_CONFIG
    }
    
    void sensor_mode()
    {
        EVM_INT_IE |= EVM_INT_BIT;
        EVM_read();
    }
    
    void EVM_read()
    {
        static unsigned int evmStatus;
    
        if(dataReady == 0)
        {
            if(evmStatus & 0x0048)
            {
                dataReady=1;
            }
        }
    
        if(dataReady==1)
        {
            Receive(LDC13xx16xx_CMD_STATUS,&evmStatus);
            Receive(LDC13xx16xx_CMD_DATA_MSB_CH0,&allData[0]);
            Receive(LDC13xx16xx_CMD_DATA_LSB_CH0,&allData[1]);
    
            uHcal(allData[0],allData[1]);
            dataReady=0;
       }
    }
    
    void Transmit(unsigned char code, unsigned int data)
    {
        //__disable_interrupt();
        //UCB0CTL1 |= UCSWRST;			
        UCB0I2CSA = LDC1614;
        //UCB0CTL1 &= ~UCSWRST;
        TX_Data[2] = code;
        TX_Data[1] = (data >> 8) & 0xFF;
        TX_Data[0] = data & 0xFF;
        TX_ByteCtr = 3;
        done = FALSE;
        I2C_TX_DATA();
    }
    
    void Receive(unsigned char code, unsigned int* data)
    {
        //UCB0CTL1 |= UCSWRST;			
        UCB0I2CSA = LDC1614;
        //UCB0CTL1 &= ~UCSWRST;
    
        TX_Data[0] = code;
        TX_ByteCtr = 1;
        I2C_TX_DATA();
    
        RX_ByteCtr = 2;
        I2C_RX_DATA();
        *data = RX_Data[0] | (RX_Data[1] << 8);
    }
    
    void I2C_TX_DATA()
    {
        //__disable_interrupt();
        IE2 |= UCB0TXIE;
        while (UCB0CTL1 & UCTXSTP);
        UCB0CTL1 |= UCTR + UCTXSTT;
    	__bis_SR_register(CPUOFF + GIE);
    	__no_operation();
    }
    
    void I2C_RX_DATA()
    {
        //__disable_interrupt();
        IE2 |= UCB0RXIE;
        while (UCB0CTL1 & UCTXSTP);
        UCB0CTL1 &= ~UCTR;
        UCB0CTL1 |= UCTXSTT;
        __bis_SR_register(CPUOFF + GIE);
        __no_operation();
        //IE2 &= ~UCB0RXIE;
    }
    
    // USCIAB0TX_ISR
    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
        if(UCB0CTL1 & UCTR)                          // TX mode (UCTR == 1)
        {
            if (TX_ByteCtr)                          // TRUE if more bytes remain
            {
                UCB0TXBUF = TX_Data[TX_ByteCtr--];   // Load TX buffer
            }
            else                                     // no more bytes to send
            {
            	UCB0TXBUF = TX_Data[TX_ByteCtr];     // Load TX buffer
                UCB0CTL1 |= UCTXSTP;                 // I2C stop condition
                IFG2 &= ~UCB0TXIFG;                  // Clear USCI_B0 TX int flag
                __bic_SR_register_on_exit(CPUOFF);   // Exit LPM0
            }
        }
        else // (UCTR == 0)                          // RX mode
        {
            //RX_ByteCtr--;                          // Decrement RX byte counter
            if (--RX_ByteCtr)                        // RxByteCtr != 0
            {
                RX_Data[RX_ByteCtr] = UCB0RXBUF;     // Get received byte
                if (RX_ByteCtr == 1)                 // Only one byte left?
                {
                    UCB0CTL1 |= UCTXSTP;             // Generate I2C stop condition
                }
            }
            else                                     // RxByteCtr == 0
            {
                RX_Data[RX_ByteCtr] = UCB0RXBUF;     // Get final received byte
                IFG2 &= ~UCB0RXIFG;
                __bic_SR_register_on_exit(CPUOFF);   // Exit LPM0
            }
        }
    }

  • I advise you remove MPU6050 and LDC1614 to see which device make the SCL can't pull.

    It should not be a software problem.

  • Hi Eason , sorry for replied late.

    I had solve  SCL can't pull low problem and MPU6050 can work well now., Because UCBBUSY set 1 after LDC1614 exit shutdown mode.

    But LDC1614 still have problem , after I send start condition , LDC1614 will receive NACK. I had try send stop and start condition again , but LDC1614 still receive NACK.

    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
    	if(UCB0STAT & UCNACKIFG)
    	{
    		UCB0CTL1 |= UCTXSTP;
    		while(UCB0CTL1 & UCTXSTP);
    		UCB0CTL1 |= UCTXSTT;
    	}
    	else
    	{
    	    if(UCB0CTL1 & UCTR)                          // TX mode (UCTR == 1)
    	    {
    	        if (TX_ByteCtr)                          // TRUE if more bytes remain
    	        {
    	            TX_ByteCtr--;                        // Decrement TX byte counter
    	            UCB0TXBUF = TX_Data[TX_ByteCtr];     // Load TX buffer
    	            UCB0CTL1 |= UCTXSTT;
    	        }
    	        else                                     // no more bytes to send
    	        {
    	            UCB0CTL1 |= UCTXSTP;                 // I2C stop condition
    	            IFG2 &= ~UCB0TXIFG;                  // Clear USCI_B0 TX int flag
    	            __bic_SR_register_on_exit(CPUOFF);   // Exit LPM0
    	        }
    	    }
    	    else // (UCTR == 0)                          // RX mode
    	    {
    	        //RX_ByteCtr--;                          // Decrement RX byte counter
    	        if (--RX_ByteCtr)                        // RxByteCtr != 0
    	        {
    	            RX_Data[RX_ByteCtr] = UCB0RXBUF;     // Get received byte
    	            if (RX_ByteCtr == 1)                 // Only one byte left?
    	            {
    	                UCB0CTL1 |= UCTXSTP;             // Generate I2C stop condition
    	            }
    	        }
    	        else                                     // RxByteCtr == 0
    	        {
    	            RX_Data[RX_ByteCtr] = UCB0RXBUF;     // Get final received byte
    	            IFG2 &= ~UCB0RXIFG;
    	            __bic_SR_register_on_exit(CPUOFF);   // Exit LPM0
    	        }
    	    }
    	}
    }
    

  • Can you check if you can communicate with LDC1614 without MPU6050? Can you use an oscilloscope to catch the wave to see whether it meets the requirement from LDC1614.

**Attention** This is a public forum