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.

MSP432 eUSCI I²C UCBCNTx stuck at UCBxTBCNT value in receiver mode

Hello world,

I've a problem with my MSP432P401R that I don't understand. I have configured the eUSCI register for I²C in master mode to send and receive data, all works well, except in receiver mode when i read the UCBCNTx field in UCBxSTATW register, this not return the number of bytes received on I²C bus since the last START or RESTART as it's indicate in the Technical Reference Manual p802, but always the value of UCTBCNRx field in UCBxTBCNT register that i have previously indicate. Whereas in transmitter mode all works perfectly. Can someone help me to understand this problem?

here is my code:

/******************************************************************************/
/*        @TITRE : i2c.h                                                      */
/*      @VERSION : 0                                                          */
/*     @CREATION : august 20, 2016                                            */
/* @MODIFICATION :                                                            */
/*      @AUTEURS : Enzo IGLESIS                                               */
/*    @COPYRIGHT : Copyright (c) 2016 Enzo IGLESIS                            */
/*      @LICENSE : MIT License (MIT)                                          */
/******************************************************************************/

#ifndef I2C_H_
#define I2C_H_

/******************************************************************************
 *
 *                                /|\  /|\
 *                MSP432P401       R    R
 *                  master         |    |
 *             -----------------   |    |
 *            |     P1.6/UCB0SDA|<-|----+->
 *            |                 |  |
 *            |                 |  |
 *            |     P1.7/UCB0SCL|<-+------>
 *            |                 |
 *
 *****************************************************************************/

/*******************************    LIBRARYS    *******************************/

/*******************************     MACROS     *******************************/
#define I2C_R   (!0)    /* Read */
#define I2C_W   (0)     /* Write */

#define I2C_ERR     (-1)

#define i2c_start()                 (UCB0CTLW0 |= UCTXSTT)
#define i2c_stop()                  (UCB0CTLW0 |= UCTXSTP)
#define i2c_start_stop();           (UCB0CTLW0 |= (UCTXSTT|UCTXSTP))
#define i2c_start_is_sent()         (UCB0CTLW0&UCTXSTT)
#define i2c_stop_is_sent()          (UCB0CTLW0&UCTXSTP)
#define i2c_bus_busy()              (UCB0STATW&UCBBUSY)


/*******************************     TYPES      *******************************/

/*******************************   CONSTANTES   *******************************/

/*******************************    VARIABLES   *******************************/

/*******************************   FUNCTIONS    *******************************/
void i2c_frequency(int_least32_t scl_frequency);
void i2c_setup_device(void);
void i2c_bytes_to_process(uint8_t counter);
void i2c_slave_address(uint8_t address, uint8_t r_w);
int i2c_status(void);
int i2c_read_write(uint8_t r_w, uint8_t address, uint8_t * data, uint8_t length);
int i2c_write(uint8_t address, uint8_t * data, uint8_t length);
int i2c_read(uint8_t address, uint8_t * data, uint8_t length);

#endif

/******************************************************************************/
/*        @TITRE : i2c.c                                                      */
/*      @VERSION : 0                                                          */
/*     @CREATION : august 20, 2016                                            */
/* @MODIFICATION :                                                            */
/*      @AUTEURS : Enzo IGLESIS                                               */
/*    @COPYRIGHT : Copyright (c) 2016 Enzo IGLESIS                            */
/*      @LICENSE : MIT License (MIT)                                          */
/******************************************************************************/

/*******************************    LIBRARYS    *******************************/
#include <msp432p401r.h>
#include "i2c.h"
/*******************************     MACROS     *******************************/

/*******************************     TYPES      *******************************/

/*******************************   CONSTANTES   *******************************/

/*******************************   VARIABLES    *******************************/
/* IRQHandler */
static volatile uint8_t * rtx_data;
static volatile int8_t status;
/*******************************   FUNCTIONS    *******************************/
void i2c_enable_interrupt(void)
{
	UCB0IE |= UCBCNTIE;         /* Byte counter interrupt enable */
	UCB0IE |= UCNACKIE;         /* Not-acknowledge interrupt enable */
	UCB0IE |= UCTXIE0;          /* Transmit interrupt enable 0 */
	UCB0IE |= UCRXIE0;          /* Receive interrupt enable 0 */
	NVIC_EnableIRQ(EUSCIB0_IRQn);
}

void i2c_frequency(int_least32_t scl_frequency)
{
    UCB0CTLW0 |= UCSWRST;        /* Software reset enable */
    UCB0BRW = SystemCoreClock/scl_frequency;  /* prescale */
    UCB0CTLW0 &= ~UCSWRST;      /* Software reset released for operation */
    i2c_enable_interrupt();
}

void i2c_setup_device(void)
{
	/* Set UCSWRST */
	UCB0CTLW0 = UCSWRST;        /* Software reset enable */
	/* initialize eUSCI_B register */
    UCB0CTLW0 &= ~UCA10;        /* Own address is a 7-bit address */
    UCB0CTLW0 &= ~UCSLA10;      /* Address slave with 7-bit address */
    UCB0CTLW0 &= ~UCMM;         /* Single master environment. There is no other master in the system. The address compare unit is disabled */
    UCB0CTLW0 |= UCMST;         /* Master mode */
    UCB0CTLW0 |= UCMODE_3;      /* I2C mode */
    UCB0CTLW0 |= UCSYNC;        /* Synchronous mode enable */
    UCB0CTLW0 |= UCSSEL_3;      /* clock source : SMCLK */
    UCB0CTLW0 &= ~UCTXACK;      /* (slave mode) Do not acknowledge the slave address */
    UCB0CTLW0 |= UCTR;          /* Transmitter */
    UCB0CTLW0 &= ~UCTXSTP;      /* No STOP generated */
    UCB0CTLW0 &= ~UCTXSTT;      /* Do not generate START condition */
    UCB0CTLW0 &= ~UCTXNACK;     /* Acknowledge normally */
    UCB0CTLW1 = 0x0000;			/* Reset UCB0CTLW1 */
    UCB0CTLW1 &= ~UCETXINT;     /* (slave mode) UCTXIFGx is set after an address match with UCxI2COAx and the direction bit indicating slave transmit */
    UCB0CTLW1 &= ~UCCLTO_3;     /* Disable clock low timeout counter */
    UCB0CTLW1 &= ~UCSTPNACK;    /* Send a not acknowledge before the STOP condition as a master receiver */
    UCB0CTLW1 &= ~UCSWACK;      /* The address acknowledge of the slave is controlled by the eUSCI_B module */
    UCB0CTLW1 |= UCASTP_2;      /* A STOP condition is generated automatically after the byte counter value reached UCBxTBCNT */
    UCB0CTLW1 |= UCGLIT_0;      /* Deglitch time = 50 ns */
    UCB0ADDMASK |= ADDMASK_M;   /* the address mask feature is desactivated */
    UCB0I2COA0 &= ~UCGCEN;      /* Do not respond to a general call */
    UCB0I2COA0 &= ~UCOAEN;      /* The slave address defined in I2COA0 is disabled */
    UCB0I2COA1 &= ~UCOAEN;      /* The slave address defined in I2COA1 is disabled */
    UCB0I2COA2 &= ~UCOAEN;      /* The slave address defined in I2COA2 is disabled */
    UCB0I2COA3 &= ~UCOAEN;      /* The slave address defined in I2COA3 is disabled */
    /* Configure ports */
    P1SEL0 |= BIT6;				/* Configure P1.6 as SDA */
    P1SEL1 &= ~BIT6;
    P1SEL0 |= BIT7;				/* Configure P1.7 as SCL */
    P1SEL1 &= ~BIT7;
    /* Reset UCSWRST */
    UCB0CTLW0 &= ~UCSWRST;      /* Software reset released for operation */
    /* Enable interrupts */
    i2c_enable_interrupt();
}

void i2c_bytes_to_process(uint8_t counter)
{
    UCB0CTLW0 |= UCSWRST;       /* Software reset enable */
    UCB0TBCNT &= ~UCTBCNT_M;    /* reset Counter Threshold Register */
    UCB0TBCNT |= counter;       /* set Counter Threshold Register */
    UCB0CTLW0 &= ~UCSWRST;      /* Software reset released for operation */
    i2c_enable_interrupt();
}

void i2c_slave_address(uint8_t address, uint8_t r_w)
{
    UCB0I2CSA &= ~I2CSA_M;  /* Reset Slave Address Register */
    UCB0I2CSA |= address;   /* I2C slave address */
    if(r_w) /* read */
    {
        UCB0CTLW0 &= ~UCTR; /* Receiver */
    }
    else    /* write */
    {
        UCB0CTLW0 |= UCTR;  /* Transmitter */
    }
}

int i2c_status(void)
{
    /* local declaration */
    int8_t old_status = status;
    /* program statement */
    status = 0;
    return old_status;
}

int i2c_read_write(uint8_t r_w, uint8_t address, uint8_t * data, uint8_t length)
{
    while(i2c_bus_busy());  /* Wait until i2c bus is available */
    rtx_data = data;
    status = 0;
    i2c_bytes_to_process(length);   /* set the number of bytes to send */
    i2c_slave_address(address, r_w);  /* set the slave address in write or read mode */
    i2c_start();    /* send an i2c start signal */
    /* IRQHandler */
    __sleep();
    return i2c_status();    /* return the number of bytes processed or -1 if an error occured */
}

int i2c_write(uint8_t address, uint8_t * data, uint8_t length)
{
    return i2c_read_write(I2C_W, address, data, length);
}

int i2c_read(uint8_t address, uint8_t * data, uint8_t length)
{
    return i2c_read_write(I2C_R, address, data, length);
}

/*******************************   INTERRUPT    *******************************/
void EUSCIB0_IRQHandler(void)
{
    if(UCB0IFG&UCTXIFG0)	/* transmit */
    {
        UCB0TXBUF = rtx_data[(UCB0STATW&UCBCNT_M)>>UCBCNT_OFS];    // Here it's incremented
	UCB0IFG &= ~UCTXIFG0;
    }
    if(UCB0IFG&UCRXIFG0)	/* receive */
    {
        UCB0IFG &= ~UCRXIFG0;
	rtx_data[(UCB0STATW&UCBCNT_M)>>UCBCNT_OFS] = UCB0RXBUF;    // Here it's stuck at the number of byte to process
    }
    if(UCB0IFG&UCNACKIFG)	/* Not-acknowledge received */
    {
    	UCB0IFG &= ~UCNACKIFG;
    	i2c_stop();             /* I2C Stop condition */
    	status = I2C_ERR;
    	__low_power_mode_off_on_exit()
    }
    if(UCB0IFG&UCBCNTIFG)	/* Byte counter */
    {
 	UCB0IFG &= ~UCBCNTIFG;
        status = UCB0TBCNT&UCTBCNT_M;
	__low_power_mode_off_on_exit();
    }
}

  • Hi Enzo,

    After looking in the TRM for the MSP432P401R, I noticed a faulty read can occur when reading UCBxBCNT during the first bit position:

    Is it possible that you are trying to read this value on the first byte received?

    What may be happening is the register has not reset yet when the first byte is received so the value is not valid and still reads as UCTBCNTx. Have you tried reading this value after receiving more than one byte?

    Best regards, 

    Caleb Overbay

  • Hi, thank for your answer,
    I just trying with 10 bytes and indeed, on the first reading the value is 10, then it's start from 2 and finish at 10:

    bytes n° | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
    ---------------------------------------------------------------------------
    UCBCNTx | 10 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

    and i attempted with just 2 bytes this is why it was always stuck at 2.

    Sorry, my fault.

    Thank you again,
    Best regards,

    Enzo Iglésis

**Attention** This is a public forum