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.

MSP430FR5962: I2C COMMINICATION GETTING STOP RANDOMLY

Part Number: MSP430FR5962

I am facing an issue with my I²C communication where the slave device initializes correctly, but when I attempt to read multiple bytes, the communication randomly stops and both the SCL and SDA lines get stuck low. Single-byte reads work consistently without any problem, but as soon as I perform multi-byte reads, the bus hangs unpredictably during the transaction. It appears that either the slave is not releasing the lines or the master is getting stuck waiting for a byte-ready condition, causing the bus to remain busy until a reset. I need assistance in understanding why the I²C bus locks up specifically during multi-byte reads and how to prevent SCL and SDA from being pulled low indefinitely. 

#include <msp430.h>
#include <stdint.h>
#include <msp430fr5992.h>

/* Generic typedefs */
typedef unsigned char  UINT8;
typedef unsigned short UINT16;

/* -----------------------
   GENERIC DEFINITIONS
------------------------ */
#define DEVICE_ADDR_1   0x42
#define DEVICE_ADDR_2   0x44
#define DEVICE_ADDR_3   0x46
#define REG_READ_FIFO   0x01

UINT8 ReceiveBuffer[20] = {0};
UINT8 TransmitBuffer[20] = {0};
UINT8 RXByteCtr = 0, TXByteCtr = 0;
UINT8 ReceiveIndex = 0, TransmitIndex = 0;
UINT8 i2c_busy = 0;

volatile UINT8 *i2c_tx_ptr, *i2c_rx_ptr;

/* ============================================================
   I2C MASTER INITIALIZATION
============================================================ */
void clock_init( void )
{
	PM5CTL0 &= ~LOCKLPM5;
	CSCTL0_H = CSKEY_H ;									// Unlock CS registers
	CSCTL1 = DCOFSEL_4 + DCORSEL ;								// Set DCO to 16MHz
	CSCTL2 = SELA__LFXTCLK | SELS__DCOCLK | SELM__HFXTCLK ; 	// Set set ACLK =  LFXT1;MCLK = DCO
	CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1 ;						// Set all dividers to 1
	CSCTL4 = HFFREQ_2 | HFXTDRIVE_3;
	CSCTL4 &= ~HFXTOFF ;
	CSCTL0_H = 0;
}

void init_i2c_master(void)
{
    /* Configure pins P7.0 = SDA, P7.1 = SCL (eUSCI_B2) */
    P7SEL0 |= BIT0 | BIT1;
    P7SEL1 &= ~(BIT0 | BIT1);

    UCB2CTLW0 = UCSWRST;
    UCB2CTLW0 |= UCSSEL__SMCLK | UCMODE_3 | UCMST | UCSYNC | UCSWRST;
    UCB2BRW = 100;
    UCB2I2CSA = DEVICE_ADDR_1;    /* default – will be changed per call */
    UCB2IFG = 0;
    UCB2CTLW0 &= ~UCSWRST;
}

/* Simple memcpy */
void CopyArray(UINT8 *source, UINT8 *dest, UINT8 count)
{
    for (UINT8 i = 0; i < count; i++)
        dest[i] = source[i];
}

/* Timeouts */
#define I2C_TIMEOUT_LOOPS  30000u
#define I2C_POST_STOP_DELAY_CYCLES  0u

static int i2c_wait_for_ifg(UINT16 mask)
{
    UINT16 t = I2C_TIMEOUT_LOOPS;
    while (!(UCB2IFG & mask))
    {
        if (--t == 0) return 0;
    }
    return 1;
}

static int i2c_wait_for_ctl_clear(UINT16 mask)
{
    UINT16 t = I2C_TIMEOUT_LOOPS;
    while (UCB2CTLW0 & mask)
    {
        if (--t == 0) return 0;
    }
    return 1;
}

static void i2c_issue_stop_and_wait(void)
{
    UCB2CTLW0 |= UCTXSTP;
    i2c_wait_for_ctl_clear(UCTXSTP);
    __delay_cycles(I2C_POST_STOP_DELAY_CYCLES);
}

/* ============================================================
   GENERIC I2C WRITE
============================================================ */
UINT8 i2c_master_write(UINT8 dev, UINT8 reg, UINT8 *data, UINT8 count)
{
    if (!i2c_wait_for_ctl_clear(UCTXSTP)) return 0;

    UCB2I2CSA = dev;
    UCB2IFG = 0;

    UCB2CTLW0 |= UCTR | UCTXSTT;

    if (!i2c_wait_for_ifg(UCTXIFG)) { i2c_issue_stop_and_wait(); return 0; }
    if (UCB2IFG & UCNACKIFG)        { i2c_issue_stop_and_wait(); return 0; }

    UCB2TXBUF = reg;

    if (!i2c_wait_for_ifg(UCTXIFG)) { i2c_issue_stop_and_wait(); return 0; }
    if (UCB2IFG & UCNACKIFG)        { i2c_issue_stop_and_wait(); return 0; }

    for (UINT8 i = 0; i < count; i++)
    {
        UCB2TXBUF = data[i];
        if (!i2c_wait_for_ifg(UCTXIFG)) { i2c_issue_stop_and_wait(); return 0; }
        if (UCB2IFG & UCNACKIFG)        { i2c_issue_stop_and_wait(); return 0; }
    }

    i2c_issue_stop_and_wait();
    return 1;
}

/* ============================================================
   GENERIC I2C READ
============================================================ */
UINT8 i2c_master_read(UINT8 dev, UINT8 reg, UINT8 count, UINT8 *rx_buf)
{
    if (!i2c_wait_for_ctl_clear(UCTXSTP)) return 0;

    UCB2I2CSA = dev;
    UCB2IFG = 0;

    UCB2CTLW0 |= UCTR | UCTXSTT;

    if (!i2c_wait_for_ifg(UCTXIFG)) { i2c_issue_stop_and_wait(); return 0; }
    if (UCB2IFG & UCNACKIFG)        { i2c_issue_stop_and_wait(); return 0; }

    UCB2TXBUF = reg;
    if (!i2c_wait_for_ifg(UCTXIFG)) { i2c_issue_stop_and_wait(); return 0; }
    if (UCB2IFG & UCNACKIFG)        { i2c_issue_stop_and_wait(); return 0; }

    UCB2CTLW0 &= ~UCTR;
    UCB2CTLW0 |= UCTXSTT;

    if (!i2c_wait_for_ctl_clear(UCTXSTT)) { i2c_issue_stop_and_wait(); return 0; }

    if (count == 1) UCB2CTLW0 |= UCTXSTP;

    for (UINT8 i = 0; i < count; i++)
    {
        if (!i2c_wait_for_ifg(UCRXIFG)) { i2c_issue_stop_and_wait(); return 0; }
        rx_buf[i] = UCB2RXBUF;

        if (i == count - 2) UCB2CTLW0 |= UCTXSTP;
    }

    if (!i2c_wait_for_ctl_clear(UCTXSTP)) return 0;

    return count;
}

/* ============================================================
   MAIN LOOP (GENERIC VERSION)
============================================================ */
int main(void)
{
clock_init();
    init_i2c_master();

    UINT8 buf1[5], buf2[5], buf3[5];

    while (1)
    {
        i2c_master_read(DEVICE_ADDR_1, REG_READ_FIFO, 5, buf1);
        i2c_master_read(DEVICE_ADDR_2, REG_READ_FIFO, 5, buf2);
        i2c_master_read(DEVICE_ADDR_3, REG_READ_FIFO, 5, buf3);

        __delay_cycles(10000);
    }
}
  • Hi Ankush,

    Can you share a capture of your communication lines?

    Best Regards,

    Diego Abad

  • Hi Diego Abad Sajamin,

    Sure, I will share the data capture.
    Below, I am sharing the capture showing where it is getting stuck during read Here it is getting stuckHere sensors got initilized.

    Thank you.

  • Hi Ankush,

    You can restart the I2C Module and retry the I2C communication again. However, it seems that the slave device is not responding any information, and it's clock stretching. Thus, maybe something is wrong with the device. Which device is the slave?

    Best Regards,

    Diego Abad

  • Hello Diego,
    I wait for the read flag (RX REGISTER )and then read the data. If I move the read operation before waiting, the code runs continuously but the buffer does not get the correct data. So I am waiting until the read flag(RX REGISTER) is set, then I load the data — but it gets stuck there. My slave is a sensor that supports up to 1 MHz I²C frequency.

  • If it is the MSP430 master that is waiting for you to read data, it will pause during the final bit of the current byte. So you can count clock cycles to check for that.

    The timeouts are a good thing but returning a unique error code for each one could make it easier to determine where the error is happening. Unless you enjoy setting breakpoints.

    When you do timeout, telling the hardware to send a stop is probably not the way to restore order. At least not for every error. (Another use for those codes.) Reseting the I2C port and manually generating a stop would be better. 

  • The traces appear to show the MSP430-side I2C waiting for your program to recognize the RXIFG from the first byte. This is consistent with your program being trapped waiting for UCTXSTT to go low in:

    if (!i2c_wait_for_ctl_clear(UCTXSTT)) { i2c_issue_stop_and_wait(); return 0; }

    This "should" complete after the slave ACKs the SLA byte (long ago, before the first Rx byte). Personally, I don't usually do this -- rather I just wait for either (a) RXIFG or (b) NACKIFG [you can check both for each byte, though you'll only see NACK on the first].

    What happens if you remove this line?

    -----

    I'm also suspicious of the fact that the CPU (MCLK) and the I2C unit (SMCLK) are running on different clocks (HFXT vs DCO). This isn't the way clock-boundary problems usually present; that said, do you get the same results if you run both on the same clock (either HFXT or DCO)?

**Attention** This is a public forum