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);
}
}

.