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.

MSP430FR2155: I2C slave interrupts: Multiple TX interrupts per single read

Part Number: MSP430FR2155

Hello,

I'm using a MSP430FR2155 to implement some basic I2C read/write functionality for my application. The MSP430 is configured to be a slave device. My setup consists of an Aardvark I2C device, configured as a master to read data from the MSP430. The issue I'm seeing is that when the master performs a read for a single byte, at the MSP430 side, I receive two TX interrupts. I was expecting a single interrupt for every read performed by the master. I observe the following interrupts when the master performs a read of a single byte:

START, TX0, STOP, TX0, 9TH_BIT

If the master were to perform a 4-byte read, the following interrupts would happen:

START, TX0, TX0, TX0, TX0, STOP, TX0, 9TH

So it seems that there's an extra TX0 interrupt that happens AFTER the STOP. Could someone with knowledge on this subject matter kindly point out the difference between the initial interrupt(s) and the one that happens after the STOP? Appreciate any leads to where I can get the information (code, documentation, etc..) Thank.

  • Hi Minh,

    Do you clear the TX0 flag? And does this test in our example code?

    https://dev.ti.com/tirex/explore/node?node=AGr34Hr5Qoei3oHkYRm5.A__IOGqZri__LATEST

    Thanks!

    Best Regards

    Johnson

  • Hi Johnson,

    Thank you for responding to my question. I do clear the TX0 flag in the interrupt routine. I'm posting the gist of my code at the end of this post. But basically, the master sends a certain command for the MSP430 to execute. The MSP430 runs the requested command, then store a 4-byte response into an array gLastCommandStatus. The master can read those 4 bytes back by reading one byte at a time, or 4 bytes block. I keep track of what byte to send next using gLastCommandIndex. When the master attempts to read beyond that 4 bytes, an invalid byte is returned.

    With the observed behavior of START, TX0, STOP, TX0, 9TH_BIT in the TX0 interrupt, I choose to consider that an invalid read, and this makes it work. But I know that the second TX0 interrupt CAN arrive before the STOP interrupt (I have seen this using a Raspbery Pi as a master); and this will mess up the logic, causing one status byte to be skipped for every master read.

    I don't have a second MSP430 to try the example you pointed out, so have to rely on another source for the master (Raspberry pi or Aardvark). But if that were to happen, would I expect just one TX0 interrupt for every read from the master MSP430?

    Setup the I2C port:

    EUSCI_B_I2C_initSlaveParam param = {0};
    param.slaveAddress = MSP430_SLAVE_ADDRESS;
    param.slaveAddressOffset = EUSCI_B_I2C_OWN_ADDRESS_OFFSET0;
    param.slaveOwnAddressEnable = EUSCI_B_I2C_OWN_ADDRESS_ENABLE;
    EUSCI_B_I2C_initSlave(EUSCI_B1_BASE, &param);

    EUSCI_B_I2C_enable (EUSCI_B1_BASE);
    EUSCI_B_I2C_clearInterrupt(EUSCI_B1_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0 +
                                     EUSCI_B_I2C_TRANSMIT_INTERRUPT0 +
                                     EUSCI_B_I2C_BIT9_POSITION_INTERRUPT +
                                     EUSCI_B_I2C_START_INTERRUPT +
                                     EUSCI_B_I2C_STOP_INTERRUPT);
    EUSCI_B_I2C_enableInterrupt(EUSCI_B1_BASE,
                                EUSCI_B_I2C_RECEIVE_INTERRUPT0 +
                                EUSCI_B_I2C_TRANSMIT_INTERRUPT0 +
                                EUSCI_B_I2C_BIT9_POSITION_INTERRUPT +
                                EUSCI_B_I2C_START_INTERRUPT +
                                EUSCI_B_I2C_STOP_INTERRUPT);

    // Enable I2C Module to start operations
    EUSCI_B_I2C_enable(EUSCI_B1_BASE);

    Interrupt routine:

    void USCIB1_ISR(void)
    {
        uint8_t rxByte;

        switch(__even_in_range(UCB1IV, USCI_I2C_UCBIT9IFG))
        {
            case USCI_NONE: // No interrupts break;
                break;

            case USCI_I2C_UCALIFG: // Arbitration lost
                SendLine ("ArbiLost", true);  // send to uart
                break;

            case USCI_I2C_UCNACKIFG: // NAK received (master only)
                SendLine ("NAK", true);
                break;

            case USCI_I2C_UCSTTIFG: // START condition detected with own address (slave mode only)
                SendLine ("START", true);

                // Master wants to talk
                gI2cState = I2C_STATE_MASTER_REQUEST;
                break;

            case USCI_I2C_UCSTPIFG: // STOP condition detected (master & slave mode)
                SendLine ("STOP", true);
                UCB0IFG &= ~UCSTPIFG; // Clear stop condition int flag
                gStartConditionCount = 0;
                gStopCondition = 1;
                break;

            case USCI_I2C_UCRXIFG3: // RXIFG3
                break;

            case USCI_I2C_UCTXIFG3: // TXIFG3
                break;

            case USCI_I2C_UCRXIFG2: // RXIFG2
                break;

            case USCI_I2C_UCTXIFG2: // TXIFG2
                break;

            case USCI_I2C_UCRXIFG1: // RXIFG1
                break;

            case USCI_I2C_UCTXIFG1: // TXIFG1
                break;

            case USCI_I2C_UCRXIFG0: // RXIFG0
                SendLine ("Rx0", true);


                // Received a byte
                rxByte = EUSCI_B_I2C_slaveGetData (EUSCI_B1_BASE);

                PutRxQ (rxByte);
                break;

            case USCI_I2C_UCTXIFG0: // TXIFG0
                SendLine ("Tx0", true);


                if (gI2cState != I2C_STATE_IDLE)
                {
                    // For some reason, there are two interrupt hits per byte being requested by master.
                    // So the index has to accommodate.

                    if (gLastCommandIndex < 4)
                    {

                        EUSCI_B_I2C_slavePutData(EUSCI_B1_BASE, gLastCommandStatus[gLastCommandIndex]);
                        if (gStopCondition == 0)
                        {
                            SendLine ("INC", true);
                            gLastCommandIndex++;
                        }
                        else
                        {
                            SendLine ("NOSTOP", true);
                            EUSCI_B_I2C_slavePutData(EUSCI_B1_BASE, RC_NO_RETURN_CODE); // No valid return code read
                        }
                    }
                    else
                    {
                        SendLine ("NOCODE", true);
                        EUSCI_B_I2C_slavePutData(EUSCI_B1_BASE, RC_NO_RETURN_CODE); // No valid return code read
                    }
                }
                else
                {
                    SendLine ("NOTREADY", true);
                    EUSCI_B_I2C_slavePutData(EUSCI_B0_BASE, RC_RETURN_CODE_NOT_READY); // Not ready. Host should try to read again
                }
                UCB0IFG &= ~UCTXIFG0; // Clear TX0 condition int flag
                break;

            case USCI_I2C_UCBCNTIFG: // Byte count limit reached (UCBxTBCNT)
                SendLine ("CNT", true);
                break;

            case USCI_I2C_UCCLTOIFG: // Clock low timeout - clock held low too long
                SendLine ("CLK", true);
                break;

            case USCI_I2C_UCBIT9IFG: // Generated on 9th bit of a transmit (for debugging)
                SendLine ("9TH", true);
                gI2cState = I2C_STATE_IDLE;
                gStopCondition = 0;

                            gLastCommandIndex = 0;
                break;

            default:
                break;
    }

    Thanks,

    Minh

  • It bugs me that you explicitly clear TXIFG, late. Reading the IV register clears the associated flag so there should be no need to clear it again. Worse, after you write data to TXBUF, TXIFG will be set again once that data is transferred to the shift register. Which means that there is a good chance you will clear this interrupt flag before it can cause an interrupt. At best you have a race condition.

**Attention** This is a public forum