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.

MSP430F5502: MSP430 I2C does not ack correctly during a multi-byte read operation

Part Number: MSP430F5502

Hi,

I seem to be having a similar issue to what a.h. was seeing in this thread:

I am reading several values repeatedly from a BNO055 and occasionally the MSP430 does not send an ack, and just starts repeatedly sending clock data. I am not seeing any issues to relate this to voltage drop however.

I am reading these at 20 Hz and I see a failure every few minutes. Is there a known workaround for this bug? It was my understanding that nothing needs to be done in receive mode to trigger sending of the ack. Is this correct?

Here is the transaction that is failing:

Here it is more zoomed in on the failed byte:

Here is the same transaction when it is successful:

And zoomed in on one of the bytes:

I have attached my i2c code.

7268.i2c_driver.c
#include "i2c_driver.h"
#include "Boards/hal.h"
#include "driverlib.h"

#ifdef I2C_USCI_INT_VECTOR

volatile bool i2cTransactionInProgress = false;
const uint8_t* i2cTxBuffer;
uint8_t* i2cRxBuffer;
volatile unsigned int writeLength;
volatile unsigned int readLength;
volatile bool* statusFlag;

void initI2C(void)
{
    GPIO_setAsPeripheralModuleFunctionInputPin(I2C_PORT, I2C_SCL);
    GPIO_setAsPeripheralModuleFunctionInputPin(I2C_PORT, I2C_SDA);

    USCI_B_I2C_initMasterParam i2cParams = {0};

    i2cParams.dataRate = USCI_B_I2C_SET_DATA_RATE_400KBPS;
    i2cParams.i2cClk = UCS_getSMCLK();
    i2cParams.selectClockSource = USCI_B_I2C_CLOCKSOURCE_SMCLK;

    USCI_B_I2C_initMaster(I2C_USCI_MODULE, &i2cParams);
    USCI_B_I2C_enableInterrupt(I2C_USCI_MODULE, USCI_B_I2C_NAK_INTERRUPT);
}

bool isI2CBusy(void) { return i2cTransactionInProgress; }

int startI2CReadTransaction(uint8_t* receiveBuffer, uint8_t slaveAddress,
                            uint8_t regAddress, unsigned int length,
                            volatile bool* completedFlag)
{
    if (isI2CBusy())
    {
        return -1;
    }
    i2cTransactionInProgress = true;
    statusFlag = completedFlag;

    *statusFlag = false;

    readLength = length;
    i2cRxBuffer = receiveBuffer;

    USCI_B_I2C_setSlaveAddress(I2C_USCI_MODULE, slaveAddress);
    USCI_B_I2C_setMode(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_MODE);
    USCI_B_I2C_enable(I2C_USCI_MODULE);
    USCI_B_I2C_disableInterrupt(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_INTERRUPT);
    USCI_B_I2C_clearInterrupt(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_INTERRUPT);

    USCI_B_I2C_masterSendMultiByteStart(I2C_USCI_MODULE, regAddress);

    // Wait for transmit flag to be set
    while (!USCI_B_I2C_getInterruptStatus(I2C_USCI_MODULE,
                                          USCI_B_I2C_TRANSMIT_INTERRUPT))
    {
    }

    USCI_B_I2C_masterReceiveMultiByteStart(I2C_USCI_MODULE);

    USCI_B_I2C_enableInterrupt(I2C_USCI_MODULE, USCI_B_I2C_RECEIVE_INTERRUPT);
    return 0;
}

int startI2CWriteTransaction(const uint8_t* transmitBuffer,
                             uint8_t slaveAddress, uint8_t regAddress,
                             unsigned int length)
{
    if (isI2CBusy())
    {
        return -1;
    }

    i2cTransactionInProgress = true;

    i2cTxBuffer = transmitBuffer;
    writeLength = length;

    USCI_B_I2C_setSlaveAddress(I2C_USCI_MODULE, slaveAddress);
    USCI_B_I2C_setMode(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_MODE);
    USCI_B_I2C_enable(I2C_USCI_MODULE);

    // Enable interrupts here and handle the rest of the transaction using them
    // to free up the processor for other tasks
    USCI_B_I2C_clearInterrupt(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_INTERRUPT);
    USCI_B_I2C_enableInterrupt(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_INTERRUPT);

    // This function sends a start command, polls the TX IFG, and then writes
    // the byte to the TX register
    USCI_B_I2C_masterSendMultiByteStart(I2C_USCI_MODULE, regAddress);
    return 0;
}

int I2CBlockingWriteTransaction(const uint8_t* transmitBuffer,
                                uint8_t slaveAddress, uint8_t regAddress,
                                unsigned int length)
{
    int rv;
    rv = startI2CWriteTransaction(transmitBuffer, slaveAddress, regAddress,
                                  length);
    while (isI2CBusy())
    {
    }
    return rv;
}

bool i2cISR(uint16_t usciModule, int ucbIv)
{
    switch (ucbIv)
    {
    case 0x02: // Arbitration Lost
        break;
    case 0x04: // Nack
        // A NAK was received from a slave device
        // TODO: We probably should handle NAKs somehow, KJL
        USCI_B_I2C_masterSendMultiByteStop(usciModule);
        i2cTransactionInProgress = false;
        break;
    case 0x06: // Start
        // Should not get here since the START interrupt is disabled and
        // for slaves only
        break;
    case 0x08: // Stop
        // Should not get here since the STOP interrupt is disabled and
        // for slaves only
        break;
    case 0x0A: // Data Received
        // Received data is ready to be read from UCBxRXBUF into the recieve
        // buffer

        // Send a stop command if the last byte is in the RX buffer
        if (readLength == 1)
        {
            USCI_B_I2C_masterReceiveMultiByteStop(usciModule);
        }
        *i2cRxBuffer = USCI_B_I2C_masterReceiveMultiByteNext(usciModule);
        i2cRxBuffer++;
        readLength--;
        if (readLength == 0)
        {
            i2cTransactionInProgress = false;
            *statusFlag = true;
            return true;
        }
        break;
    case 0x0C: // TX Buffer Empty
        // The I2C bus is ready to transmit data written into the UCBxTXBUF
        if (writeLength == 0) // There is no data left to be written
        {
            USCI_B_I2C_masterSendMultiByteStop(usciModule);
            i2cTransactionInProgress = false;
            return true;
        }
        else
        {
            USCI_B_I2C_masterSendMultiByteNext(usciModule, *i2cTxBuffer);
            writeLength--;
            i2cTxBuffer++;
        }
        break;
    }
    return false; // stay in LPM
}
#endif
usci_interrupts.c
#include "Boards/hal.h"
#include "SerialCommunications/spi.h"
#include "driverlib.h"
#include "i2c_driver.h"

#ifndef VS_CODE
#pragma vector = USCI_B1_VECTOR
__interrupt void USCI_B1_ISR(void)
#else
void USCI_B1_ISR(void)
#endif
{
#ifdef I2C_USCI_INT_VECTOR
    if (UCB1CTL0 & UCMODE_3 == UCMODE_3)
    {
        // USCI module is in I2C Mode
        if (i2cISR(USCI_B1_BASE, UCB1IV))
        {
            __bic_SR_register_on_exit(LPM0_bits);
        }
    }
    else
    {
        // USCI module is in SPI mode
        if (spiISR(USCI_B1_BASE, UCB1IV))
        {
            __bic_SR_register_on_exit(LPM0_bits);
        }
    }
#else
    if (spiISR(USCI_B1_BASE, UCB1IV))
    {
        __bic_SR_register_on_exit(LPM0_bits);
    }
#endif
}

#ifndef VS_CODE
#pragma vector = USCI_A1_VECTOR
__interrupt void USCI_A1_ISR(void)
#else
void USCI_A1_ISR(void)
#endif
{
    // USCI module is in SPI mode
    if (spiISR(USCI_A1_BASE, UCA1IV))
    {
        __bic_SR_register_on_exit(LPM0_bits);
    }
}

#ifdef MPU

#ifndef VS_CODE
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
#else
void USCI_B0_ISR(void)
#endif
{
#ifdef I2C_USCI_INT_VECTOR
    if (UCB1CTL0 & UCMODE_3 == UCMODE_3)
    {
        // USCI module is in I2C Mode
        if (i2cISR(USCI_B0_BASE, UCB0IV))
        {
            __bic_SR_register_on_exit(LPM0_bits);
        }
    }
    else
    {
        // USCI module is in SPI mode
        if (spiISR(USCI_B0_BASE, UCB0IV))
        {
            __bic_SR_register_on_exit(LPM0_bits);
        }
    }
#else
    if (spiISR(USCI_B0_BASE, UCB0IV))
    {
        __bic_SR_register_on_exit(LPM0_bits);
    }
#endif
}

#ifndef VS_CODE
#pragma vector = USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#else
void USCI_A0_ISR(void)
#endif
{
    // USCI module is in SPI mode
    if (spiISR(USCI_A0_BASE, UCA0IV))
    {
        __bic_SR_register_on_exit(LPM0_bits);
    }
}
#endif

**Attention** This is a public forum