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: USCIB I2C Lines held low and not sending STP in master receive mode

Part Number: MSP432P401R

Hello,

We are using the MSP432P401R in order to communicate with a MAX-32664 (located in a SEN-15219 board). We have created our own custom i2c driver and we can successfully send and receive one or two bytes. For example, we can check the AFE'S SpO2 Configuration by sending "0x41 0x03 0x0A" and we get "0b01100011" which means the sample rate is 50 samples and the pulse width is 441 uS. We are doing the full initialization and the SEN-15219's status byte always replies with 0 ("ok").

The problem arises when we try to get the sensor and algorithm data which consists of a frame of 24 bytes... When we do that, both i2c lines are held low and, in spite of this line is called "EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTP;", the program counter hangs in " while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTP);". Another thing that we tried if to only try to read 17 bytes. This seems to be working but after performing this twice, the same issue happens on the third try. This problems happens all the time and it is not something we could fix using the UCCLTOIFG. 

We have already tried the following with no luck:

- setting the SCL to 25 kHZ and 400 kHz.

- disabling other ISR when reading data (we had a 1ms interrupt using TIMERA)

In order to make sure the SEN-15219 is not faulty, we have connected it to an Arduino and we can run the sample code with no issues and we can get the 24 byte frame...

Other details of our hardware:

- The i2c lines are pulled up using the 4.7kOhm resistors provided in the SEN-15219.

- We are using the launchpad and its 48MHz crystal for MCLK. This is divided by 4 and used for the peripherals, including the EUSCI.

Below you can see the initialization code for the i2c, the function used to receive bytes, the one used for sending data and the ISR... I have also attached a picture of the lines...

What can be wrong? What else can we try?

Our best guess is that there might be an synchronization issue when sending the stop signal but is this because of the errata (SLAZ610R)? I believe we are following the recommendations that are provided there... Something similar to this is that we have to send the STP together with the STT when we need to receive only one byte of data.

Thanks in advace for your help! 

void initializeI2C(int slave_address)
{
    //Configure I2C pins  P1.7 - SCL / P1.6 - SDA
    P1SEL0 |=  SCL;
    P1SEL1 &= ~SCL;
    P1SEL0 |=  SDA;
    P1SEL1 &= ~SDA;

    //Configure USCI_B0 as I2C
    //Reset EUSCI_B0 while being configured
    EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_SWRST;

    //MST Master mode enable
    //MODE 3 i2c
    //Synchronous mode enabled
    //UCSSEL 2 SMCLK (12MHz)
    EUSCI_B0->CTLW0 |=  EUSCI_B_CTLW0_MST |
            EUSCI_B_CTLW0_MODE_3 | EUSCI_B_CTLW0_SYNC |
            EUSCI_B_CTLW0_SSEL__SMCLK;

    EUSCI_B0->CTLW1 = 0;

    // SMCLK / BRW = 100kHz - desired baudrate (12MHz/100kHz)=120
    EUSCI_B0->BRW = 120;

    //Slave address
    EUSCI_B0->I2CSA = slave_address;

    //Turn on the module
    EUSCI_B0->CTLW0 &= ~EUSCI_B_CTLW0_SWRST;

    //Enable RX interrupts:receive, NACK
    EUSCI_B0->IE = EUSCI_B_IE_NACKIE;

    //Init queues
    initQueue(&head_tx, &tail_tx);
    initQueue(&head_rx, &tail_rx);

    NVIC_SetPriority(EUSCIB0_IRQn,0);
    NVIC_EnableIRQ(EUSCIB0_IRQn);
}

int i2cReceive(char* buffer_pointer, int length)
{
    int i = 0;
    char value = 0;

    stop_set_in_receive = 0;
    bytes_to_use = length;

    //Wait for bus to be available
    while(EUSCI_B0->STATW & EUSCI_B_STATW_BBUSY);

    //Sets ISR sources
    TIMER_A0 -> CCTL[0] &= ~TIMER_A_CCTLN_CCIE;
    EUSCI_B0->IE |= EUSCI_B_IE_RXIE;
    EUSCI_B0->IE &= ~EUSCI_B_IE_TXIE;

    //Sets receive mode and starts communication
    i2c_state_transmission = I2C_READING;
    EUSCI_B0->CTLW0 &= ~EUSCI_B_CTLW0_TR;
    EUSCI_B0->CTLW0 |=  EUSCI_B_CTLW0_TXSTT;

    if(bytes_to_use == 1)
    {
        //Sends stop to stop communication
        EUSCI_B0->CTLW0 |=  EUSCI_B_CTLW0_TXSTP;
        stop_set_in_receive = 1;
    }

    i2c_state = I2C_STATE_BUSY;

    //TODO Use FIFO Function Queue externally
    while (i2c_state == I2C_STATE_BUSY);
    while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTP);

    i2c_state_transmission = I2C_IDLE;

    while (i < length)
    {
        if(!queueIsEmpty(head_rx, tail_rx))
        {
            value = getFromQueue(&tail_rx, rx_buffer);
        }
        *(buffer_pointer + i) = value;
        i++;
    }

    //Reset ISR sources
    EUSCI_B0->IE &= ~EUSCI_B_IE_RXIE;
    TIMER_A0 -> CCTL[0] |= TIMER_A_CCTLN_CCIE;

   return i2c_state;
}

int i2cTransmit(char* buffer_pointer, int length)
{
    int i = 0;
    bytes_to_use = length;

    while (i < length)
    {
        if(!queueIsFull(head_tx, tail_tx))
        {
            addToQueue(*(buffer_pointer + i), &head_tx, tx_buffer);
        }
        i++;
    }

    //Wait for bus to be available
    while(EUSCI_B0->STATW & EUSCI_B_STATW_BBUSY);

    //Sets ISR sources
    TIMER_A0 -> CCTL[0] &= ~TIMER_A_CCTLN_CCIE;
    EUSCI_B0->IE |= EUSCI_B_IE_TXIE;
    EUSCI_B0->IE &= ~EUSCI_B_IE_RXIE;

    //Sets transmit mode and starts communication
    i2c_state_transmission = I2C_SENDING;
    EUSCI_B0->CTLW0 |=  EUSCI_B_CTLW0_TR | EUSCI_B_CTLW0_TXSTT;

    i2c_state = I2C_STATE_BUSY;

    while (i2c_state == I2C_STATE_BUSY);
    while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTP);
    i2c_state_transmission = I2C_IDLE;

    //Reset ISR sources
    EUSCI_B0->IE &= ~EUSCI_B_IE_TXIE;
    TIMER_A0 -> CCTL[0] |= TIMER_A_CCTLN_CCIE;

    return i2c_state;
}


void EUSCIB0_IRQHandler(void)
{
    if ((EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0) && (i2c_state_transmission == I2C_SENDING))
    {
        if(bytes_to_use == 0)
        {
            //Sends stop to stop communication
            EUSCI_B0->IFG &= ~EUSCI_B_IFG_TXIFG0;
            EUSCI_B0->CTLW0 |=  EUSCI_B_CTLW0_TXSTP;
            i2c_state = I2C_STATE_NO_ERROR;
        }
        else
        {
            if(!queueIsEmpty(head_tx, tail_tx))
            {
                EUSCI_B0->TXBUF = getFromQueue(&tail_tx, tx_buffer);
            }
            bytes_to_use--;
        }
    }

    if ((EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG0) && (i2c_state_transmission == I2C_READING))
    {
        EUSCI_B0->IFG &= ~EUSCI_B_IFG_RXIFG0;
        if(!queueIsFull(head_rx, tail_rx))
        {
            addToQueue(EUSCI_B0->RXBUF, &head_rx, rx_buffer);
        }
        bytes_to_use--;

        if(bytes_to_use == 0)
        {
            i2c_state = I2C_STATE_NO_ERROR;
            //Sends stop to stop communication
            if(stop_set_in_receive != 1)
            {
                stop_set_in_receive = 1;
                EUSCI_B0->CTLW0 |=  EUSCI_B_CTLW0_TXSTP;
            }
        }
    }

    if (EUSCI_B0->IFG & EUSCI_B_IFG_NACKIFG)
    {
        nack_error++;
        i2c_state = I2C_STATE_NACK_ERROR;
    }
}