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.

CCS/MSP432P401R: MSP432 LCD I2C communication stops (waiting on tx interrupt that never occurs)

Part Number: MSP432P401R

Tool/software: Code Composer Studio

Hi all,

The problem with the i2c driver is I can't do a write after a single byte read.
I've tested and can read 2, 4, up to 32 bytes after a write, no problem, but if I do a read 1 byte, the next write waits for a transmit interrupt that never occurs.
I can clear the error by doing another write followed by  then write then reading more than 1 byte - which sometimes fails and sometimes does not, and sometimes this takes two write-read cycles to clear.

Using bus pirate to write / read the i2c bus or single byte reads is not a problem (i.e. generating independent ground truth), which more or less leads me to conclude it is a problem with the 432 chip or with the driverlib.

Using this forum, I see other people have had the same or similar problems- that appear unresolved, which leads me to conclude that is just might be a real problem and not me.

Any help - in either direction - from you to me or from me to you?  I can run tests, I can send you code, whatever...

thx,

bob s.

  • Bob,
    If you could provide an example that would be great. Otherwise, I will convert the examples on line in which the master writes two bytes and then reads 10 - swap to read one byte then write 10.

    Regards,
    Chris
  • I used the ti examples i2c_master* as templates, changed the B-Base config to match my card (B2), and substituted *WithTimeout for the calls that locked up. I'm using the core freq of 48Mhz, and a i2c rate of 100Khz.

    The code I've written is part of a larger project, the 432 card is bespoke, and I tailored the examples to the I2C device that is onboard, the Linear Technologies LTC2945.

    I'll cut and paste the pieces of code and upload them, perhaps you can see something I missed.
    What is not included below are DelayMs(), DumpBuffer(), and putUsart()

    The snippet has paths to explore what can be done, one path explores the alternative driver posted by an ti employee, and there are some obviously wrong things such as read w/o a write - which I can get bus pirate to do but not the standard ti driver, although the alternative driver gets it mostly right for a read (by doing a write first) but has other protocol issues (it completes the handshake before completing the reads).

    I've found a workaround to my problem -> if I get a missing tx interrupt error I re-call init and the next transmit followed by read and that usually works. I'm not sure what step in init resets the hardware.

    ----


    /* I2C Master Configuration Parameter */
    const eUSCI_I2C_MasterConfig i2cConfig48 =
    {
    EUSCI_B_I2C_CLOCKSOURCE_SMCLK, // SMCLK Clock Source
    48000000, // SMCLK = 48MHz
    EUSCI_B_I2C_SET_DATA_RATE_100KBPS, // Desired I2C Clock of 100khz
    0, // No byte counter threshold
    EUSCI_B_I2C_NO_AUTO_STOP // No Autostop
    };
    /*
    * -----------------------------------------------------------------------------
    */
    int i2c_init(void)
    {
    int status =0;
    char txbuf[2];
    char rxbuf[32];

    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3, GPIO_PIN6 | GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);
    if (g_coreMhz == 48)
    {
    /* Initializing I2C Master to SMCLK at with no autostop */
    MAP_I2C_initMaster(EUSCI_B2_BASE, &i2cConfig48);
    }
    else
    {
    if (g_coreMhz == 24)
    {
    /* Initializing I2C Master to SMCLK at with no autostop */
    MAP_I2C_initMaster(EUSCI_B2_BASE, &i2cConfig24);
    }
    else
    {
    /*
    * should never reach here, because frequency is same param passed into usart
    */
    status = -1;
    strcpy(g_info,"Invalid core frequence, via i2c_init()\r\n");
    InABadPlace(g_info);
    }
    }
    /* Set Master in transmit mode */
    MAP_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_TRANSMIT_MODE);

    /* Enable I2C Module to start operations */
    MAP_I2C_enableModule(EUSCI_B2_BASE);

    /* Enable and clear the interrupt flag */
    MAP_I2C_clearInterruptFlag(EUSCI_B2_BASE,
    EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    /*
    * Test communication to i2c power monitor
    */
    txbuf[0] = 0;
    txbuf[1] = 5;
    #ifdef I2CTEST
    status = i2c_put_get_bis(PM_SLAVE_ADDRESS,txbuf,2,rxbuf,32);
    #else
    status = i2c_put_get(PM_SLAVE_ADDRESS,txbuf,2,rxbuf,32);
    #endif
    return status;
    } // end i2c_init

    /*
    * -----------------------------------------------------------------------------
    */
    int i2c_put_get(int saddr,unsigned char *tx, int txcnt,unsigned char *rx, int rxcnt)
    {
    int status =0; // return status
    int ii; // iterator
    int tx_f; // transmit flag
    static int last_addr = -1;
    bool not_tmo_f;


    if ((saddr == -1 ) && (last_addr == -1))
    {
    putUsart("Start address not set\r\n"); // in a bad place. lock up code.
    status = -1;
    return status;
    }

    tx_f = 0;
    stopSent = false; // clear global mutex
    if (txcnt > 0)
    {
    TXByteCtr = txcnt -1; // set count of bytes to be transmtted, first sent now
    tx_f = 1; // yes, transmitting
    xferIndex = 1; // counts up to TXByteCtr on transmit and up to rxcnt on receive
    //Enable master receive interrupt
    MAP_I2C_enableInterrupt(EUSCI_B2_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    }

    RXByteCnt = rxcnt; // global for interrupt handler

    MAP_I2C_setSlaveAddress(EUSCI_B2_BASE, saddr); /* Specify slave address */

    if (tx_f)
    {
    /* Making sure the last transaction has been completely sent out */
    ii = 0;
    while (MAP_I2C_masterIsStopSent(EUSCI_B2_BASE) == EUSCI_B_I2C_SENDING_STOP)
    {
    ii++;
    DelayMs(100);
    if (ii == 50)
    {
    status = -2;
    strcpy(g_info,"i2c stop failure.\r\n");
    }
    }
    /* Send start and the first byte of the transmit buffer. We have to send
    * two bytes to clean out whatever is in the buffer from a previous send
    * (the above comment is from the example: i2c_master_rw_repeated_start-master)
    */
    MAP_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
    MAP_I2C_clearInterruptFlag(EUSCI_B2_BASE,
    EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    MAP_I2C_enableInterrupt(EUSCI_B2_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    MAP_Interrupt_enableInterrupt(INT_EUSCIB2);
    //MAP_I2C_masterSendMultiByteStart(EUSCI_B2_BASE, I2C_TXData[0]); // this is why xferIndex starts at index 1.
    /*
    * timeout is not a "time" out, is a count down.
    */
    not_tmo_f = MAP_I2C_masterSendMultiByteStartWithTimeout(EUSCI_B2_BASE,I2C_TXData[0],1000);
    if (!not_tmo_f) // double negative == true
    {
    sprintf(g_info,"MAP_I2C_masterSendMultiByteStartWithTimeout timed out\r\n");
    putUsart(g_info); // is this a real error? Try to receive
    status = -1;
    return status; // exit early
    }
    else
    {
    MAP_I2C_masterSendMultiByteNext(EUSCI_B2_BASE, I2C_TXData[0]);
    }
    }
    else // setup for receive w/o transmit
    {
    memset(I2C_RXData, 0x00, MAXBUF);
    MAP_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_MODE);
    xferIndex = 0;
    MAP_I2C_masterReceiveStart(EUSCI_B2_BASE);
    MAP_I2C_enableInterrupt(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    }
    /*
    * Note: the tx and rx occurs inside the interrupt handler
    */
    // MAP_PCM_gotoLPM0(); // LPM works (was tested 2/17/2017), in case low power mode is needed
    for (ii=0; ii<50; ii++) // loop for a while waiting for flag to be set
    {
    if (stopSent)
    break;

    DelayMs(100);
    }
    if (!stopSent)
    {
    sprintf(g_info,"expected i2c interrupt not received\r\n");
    putUsart(g_info);
    //status = -2; // is this a real error? Try to receive...
    }
    if (status ==0)
    {
    if (rxcnt >0)
    {
    if (rxcnt != xferIndex)
    {
    sprintf(g_info,"count of i2c data received: %d not equal to requested: %d\r\n",xferIndex,rxcnt);
    putUsart(g_info);
    status = -3;
    }
    else
    {
    dumpBuffer(I2C_RXData,xferIndex);
    }
    }
    }
    stopSent = false; // clear global

    if ((status ==0) &&(saddr != -1))
    {
    last_addr = saddr; // now allow read w/o write
    }
    return status;
    } // end i2c_put_get
    void EUSCIB2_IRQHandler(void)
    {
    uint_fast16_t status;

    // note: xferIndex set to 0 here, then contains length of data received
    // note: stopSent is mutex for outside of interrupt

    #ifdef I2CTEST
    return euscib2IntHandler(); // test handler
    #endif

    status = MAP_I2C_getEnabledInterruptStatus(EUSCI_B2_BASE);
    MAP_I2C_clearInterruptFlag(EUSCI_B2_BASE, status);

    /* If we reached the transmit interrupt, it means we are at index 1 of
    * the transmit buffer. When doing a repeated start, before we reach the
    * last byte we will need to change the mode to receive mode, set the start
    * condition send bit, and then load the final byte into the TXBUF.
    */
    if (status & EUSCI_B_I2C_TRANSMIT_INTERRUPT0)
    {
    if (TXByteCtr) /* if next transmission is last byte or more to go */
    {
    MAP_I2C_masterSendMultiByteNext(EUSCI_B2_BASE, I2C_TXData[xferIndex++]); // necessary for multibyte start
    TXByteCtr--;
    }
    else
    {
    MAP_I2C_masterSendMultiByteStop(EUSCI_B0_BASE); // if only 1 byte sent, or last byte
    MAP_I2C_disableInterrupt(EUSCI_B2_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    if (RXByteCnt) // transition to receive
    {
    MAP_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_MODE);
    xferIndex = 0;
    MAP_I2C_masterReceiveStart(EUSCI_B2_BASE);
    MAP_I2C_enableInterrupt(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    } // end if transition to receive

    stopSent = true; // if no read after write then signal done

    } // end else done transmitting
    } // end if transmit interrupt

    /* Receives bytes into the receive buffer. If we have received all bytes,
    * then send a STOP condition
    */
    if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0)
    {
    if(xferIndex == RXByteCnt - 2) // if next to last byte
    {
    MAP_I2C_masterReceiveMultiByteStop(EUSCI_B2_BASE); // the "whoa" command?
    I2C_RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B2_BASE);
    }
    else
    {
    if(xferIndex == RXByteCnt - 1) // if last byte
    {
    MAP_I2C_masterReceiveMultiByteStop(EUSCI_B2_BASE); // the "whoa" command?
    I2C_RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B2_BASE);
    MAP_I2C_disableInterrupt(EUSCI_B2_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    MAP_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
    stopSent = true; // set mutex
    MAP_Interrupt_disableSleepOnIsrExit(); // low power until commanded
    }
    else // else not last or next to last byte
    {
    I2C_RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B2_BASE);
    } // end else not last or next to last
    } // end else not next to last byte
    } // end if receive interrupt
    }
  • If I may ask a followup question:
    Q: How do you test your driver library?
    Simply rerunning the examples for your driverlib does not test boundary conditions.
  • I just found a bug (my own) on the transmit side - always transmitting 0 and not the intended data, however this does not affect the problem I'm seeing on the receive side.

  • Perhaps a good way for you to test this would be to use the TI example project named "i2c_master_rw_repeated_start-master_code"
    and then reduce the constant NUM_OF_REC_BYTES from 10 to 1.

    Since my code is based on your code, if you do not get a code lock up then would point to my code and not yours.
  • Thanks Robert.  I still need to digest the earlier posts.  I have put together an example based upon the example that you cite but I need to touch base with the designers because there appears to be an issue in knowing when to set the stop if only one byte is being received.  You will find a 'hack' in my code to try and time the setting of the stop within the receive byte per the TRM ( Figure 24-13).  Please let me know if you have any questions about the code.

    Best Regards,

    Chris

    i2c_master_rw_repeated_start-master_code_edits.c
    /*
     * -------------------------------------------
     *    MSP432 DriverLib - v3_50_00_02 
     * -------------------------------------------
     *
     * --COPYRIGHT--,BSD,BSD
     * Copyright (c) 2016, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * --/COPYRIGHT--*/
    /******************************************************************************
     *  MSP432 I2C - EUSCI_B0_BASE I2C Master TX  bytes to MSP432 Slave - Repeated Start
     *
     *  Description: This demo connects two MSP432 's via the I2C bus. The master
     *  transmits to the slave. This is the MASTER CODE. It continuously
     *  transmits an array of data and demonstrates how to implement an I2C
     *  master transmitter sending multiple bytes followed by a repeated start,
     *  followed by a read of multiple bytes.  This is a common operation for
     *  reading register values from I2C slave devices such as sensors. The
     *  transaction for the I2C that is written looks as follows:
     *
     *  ________________________________________________________________
     *  |  Start   |      |      |  Start   |                   |       |
     *  | 0x48Addr | 0x04 | 0x00 | 0x48Addr |  <10 Byte Read>   | Stop  |
     *  |    W     |      |      |    R     |                   |       |
     *  |__________|______|______|__________|___________________|_______|
     *
     *  ACLK = n/a, MCLK = HSMCLK = SMCLK = BRCLK = default DCO = ~8.0MHz
     *
     *                                /|\  /|\
     *                MSP432P401      10k  10k      MSP432P401
     *                   slave         |    |         master
     *             -----------------   |    |   -----------------
     *            |     P1.6/UCB0SDA|<-|----+->|P1.6/UCB0SDA     |
     *            |                 |  |       |                 |
     *            |                 |  |       |                 |
     *            |     P1.7/UCB0SCL|<-+------>|P1.7/UCB0SCL     |
     *            |                 |          |                 |
     *
     * Author: Timothy Logan
     *****************************************************************************/
    /* DriverLib Defines */
    #include <ti/devices/msp432p4xx/driverlib/driverlib.h>
    
    /* Standard Defines */
    #include <stdint.h>
    
    #include <stdbool.h>
    #include <string.h>
    
    /* Slave Address for I2C Slave */
    #define SLAVE_ADDRESS       0x48
    #define NUM_OF_TX_BYTES    2
    /*
     * minimum number is 2, otherwise special handling is needed.
     */
    #define NUM_OF_RX_BYTES    2
    //#define NUM_OF_RX_BYTES_IS_ONE
    
    /* Variables */
    const uint8_t TXData[NUM_OF_TX_BYTES] = {NUM_OF_TX_BYTES, NUM_OF_RX_BYTES};
    static uint8_t RXData[NUM_OF_RX_BYTES];
    static volatile uint32_t xferIndex;
    static volatile bool stopSent;
    
    /* I2C Master Configuration Parameter */
    const eUSCI_I2C_MasterConfig i2cConfig =
    {
            EUSCI_B_I2C_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
            8000000,                                // SMCLK = 8MHz
            EUSCI_B_I2C_SET_DATA_RATE_100KBPS,      // Desired I2C Clock of 100khz
            0,                                      // No byte counter threshold
            EUSCI_B_I2C_NO_AUTO_STOP                // No Autostop
    };
    
    int main(void)
    {
        volatile uint32_t ii;
    
        /* Disabling the Watchdog  */
        MAP_WDT_A_holdTimer();
    
        MAP_FPU_enableModule();
    
        /* Set the core voltage level to VCORE1 */
        MAP_PCM_setCoreVoltageLevel(PCM_VCORE0);
    
        /* Set 2 flash wait states for Flash bank 0 and 1*/
        MAP_FlashCtl_setWaitState(FLASH_BANK0, 0);
        MAP_FlashCtl_setWaitState(FLASH_BANK1, 0);
    
        /* Initializes Clock System */
        MAP_CS_setDCOFrequency(8000000);  //8Mhz
        MAP_CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
        MAP_CS_initClockSignal(CS_HSMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);
        MAP_CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);
        MAP_CS_initClockSignal(CS_ACLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
        MAP_CS_initClockSignal(CS_BCLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
    
        /* Select Port 1 for I2C - Set Pin 6, 7 to input Primary Module Function,
         *   (UCB0SIMO/UCB0SDA, UCB0SOMI/UCB0SCL).
         */
        MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
                GPIO_PIN6 + GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);
        stopSent = false;
        memset(RXData, 0x00, NUM_OF_RX_BYTES);
    
        /* Initializing I2C Master to SMCLK at 100khz with no autostop */
        MAP_I2C_initMaster(EUSCI_B0_BASE, &i2cConfig);
    
        /* Specify slave address */
        MAP_I2C_setSlaveAddress(EUSCI_B0_BASE, SLAVE_ADDRESS);
    
        /* Set Master in transmit mode */
        MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
    
        /* Enable I2C Module to start operations */
        MAP_I2C_enableModule(EUSCI_B0_BASE);
    
        /* Enable and clear the interrupt flag */
        MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE,
                EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_RECEIVE_INTERRUPT0);
        //Enable master Receive interrupt
        /*
         *
         */
    //    MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
        MAP_Interrupt_enableSleepOnIsrExit();
        MAP_Interrupt_enableInterrupt(INT_EUSCIB0);
    
        while (1)
        {
            /* Making sure the last transaction has been completely sent out */
    //        while (MAP_I2C_masterIsStopSent(EUSCI_B0_BASE) == EUSCI_B_I2C_SENDING_STOP);
            /*
             * Set and reset the eUSCI
             */
    //        MAP_I2C_disableModule(EUSCI_B0_BASE);
    //        MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE, 0xFFFFFFFFFFFFFFFF);
    //        MAP_I2C_enableModule(EUSCI_B0_BASE);
    
            /* Send start and the first byte of the transmit buffer. We have to send
             * two bytes to clean out whatever is in the buffer from a previous
             * send  */
            MAP_I2C_masterSendStart(EUSCI_B0_BASE);
    //        MAP_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, TXData[0]);
    //        MAP_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, TXData[0]);
    
            MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    
            /* While the stop condition hasn't been sent out... */
            while(!stopSent)
            {
                MAP_PCM_gotoLPM0InterruptSafe();
            }
            stopSent = false;
        }
    }
    
    /*******************************************************************************
     * eUSCIB0 ISR. The repeated start and transmit/receive operations happen
     * within this ISR.
     *******************************************************************************/
    void EUSCIB0_IRQHandler(void)
    {
        uint_fast16_t status;
    
        status = MAP_I2C_getEnabledInterruptStatus(EUSCI_B0_BASE);
        MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE, status);
    
        /* If we reached the transmit interrupt, it means we are at index 1 of
         * the transmit buffer. When doing a repeated start, before we reach the
         * last byte we will need to change the mode to receive mode, set the start
         * condition send bit, and then load the final byte into the TXBUF.
         */
        if (status & EUSCI_B_I2C_TRANSMIT_INTERRUPT0)
        {
            MAP_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, TXData[xferIndex++]);
            if(xferIndex == NUM_OF_TX_BYTES)
            {
                MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
                /*
                 * Debug to get to work
                 * wait until IFG is set before continuing on
                 */
                while
                    (!BITBAND_PERI(EUSCI_B_CMSIS(EUSCI_B0_BASE)->IFG, EUSCI_B_IFG_TXIFG0_OFS))
                    ;
                MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_MODE);
                xferIndex = 0;
                MAP_I2C_masterReceiveStart(EUSCI_B0_BASE);
    #ifdef NUM_OF_RX_BYTES_IS_ONE
                /*
                 * Once the start is complete, the recieve will happen automatically
                 * during this receive the stop condition must be set.  Waiting for
                 * start bit to be automatically cleared is too short and waiting for
                 * rx ifg is too short (and not recommended).
                 */
                while
                    (BITBAND_PERI(EUSCI_B_CMSIS(EUSCI_B0_BASE)->CTLW0, EUSCI_B_CTLW0_TXSTT))
                    ;
    
                __delay_cycles(1000);
                /*
                 * top is being set during reception of last byte
                 * read byte so that next byte can be read
                 */
                MAP_I2C_masterReceiveMultiByteStop(EUSCI_B0_BASE);
                MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_STOP_INTERRUPT);
    #else
                MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    #endif
            }
        }
    
        /* Receives bytes into the receive buffer. If we have received all bytes,
         * send a STOP condition */
    #ifndef NUM_OF_RX_BYTES_IS_ONE
        if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0)
        {
            /*
             * This does not make any sense when NUM_OF_RX_BYTES is 1
             */
            if(xferIndex == NUM_OF_RX_BYTES - 2)
            {
                /*
                 * Let's try triggering last byte from STOP instead of RXIFG
                 */
                MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
                MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_STOP_INTERRUPT);
                /*
                 * switch order so that stop is being set during reception of last byte
                 * read byte so that next byte can be read
                 */
                MAP_I2C_masterReceiveMultiByteStop(EUSCI_B0_BASE);
                RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
            }
            else
            {
                RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
            }
        }
    #endif
        /*
         * Add stop handler
         */
        if (status & EUSCI_B_I2C_STOP_INTERRUPT)
        {
            RXData[xferIndex] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
            MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_STOP_INTERRUPT);
            MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
            xferIndex = 0;
            stopSent = true;
            MAP_Interrupt_disableSleepOnIsrExit();
        }
    }
        
    

    i2c_master_rw_repeated_start-slave_code_edits.c
    /*
     * -------------------------------------------
     *    MSP432 DriverLib - v3_50_00_02 
     * -------------------------------------------
     *
     * --COPYRIGHT--,BSD,BSD
     * Copyright (c) 2016, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * --/COPYRIGHT--*/
    /******************************************************************************
     *  MSP432 I2C - EUSCI_B0_BASE I2C Master TX  bytes to MSP432 Slave - Repeated Start
     *
     *  Description: This demo connects two MSP432 's via the I2C bus. The master
     *  transmits to the slave. This is the SLAVE CODE. It continuously
     *  transmits an array of data and demonstrates how to implement an I2C
     *  master transmitter sending multiple bytes followed by a repeated start,
     *  followed by a read of multiple bytes.  This is a common operation for
     *  reading register values from I2C slave devices such as sensors. The
     *  transaction for the I2C that is written looks as follows:
     *
     *  ________________________________________________________________
     *  |  Start   |      |      |  Start   |                   |       |
     *  | 0x48Addr | 0x04 | 0x00 | 0x48Addr |  <10 Byte Read>   | Stop  |
     *  |    W     |      |      |    R     |                   |       |
     *  |__________|______|______|__________|___________________|_______|
     *
     *  ACLK = n/a, MCLK = HSMCLK = SMCLK = BRCLK = default DCO = ~3.0MHz
     *
     *                                /|\  /|\
     *                MSP432P401      10k  10k      MSP432P401
     *                   slave         |    |         master
     *             -----------------   |    |   -----------------
     *            |     P1.6/UCB0SDA|<-|----+->|P1.6/UCB0SDA     |
     *            |                 |  |       |                 |
     *            |                 |  |       |                 |
     *            |     P1.7/UCB0SCL|<-+------>|P1.7/UCB0SCL     |
     *            |                 |          |                 |
     *
     * Author: CTS
     *****************************************************************************/
    /* DriverLib Includes */
    #include <ti/devices/msp432p4xx/driverlib/driverlib.h>
    
    /* Standard Includes */
    #include <stdint.h>
    
    #include <stdbool.h>
    
    /* Application Defines */
    #define SLAVE_ADDRESS       0x48
    #define NUM_OF_RX_BYTES        2
    #define NUM_OF_TX_BYTES        10
    
    /* Application Variables */
    static volatile uint8_t RXData[NUM_OF_RX_BYTES];
    static volatile uint32_t xferIndex, txferMax;
    const uint32_t TXData[NUM_OF_TX_BYTES + 1] =
    { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x10 };
    
    int main(void)
    {
        /* Disabling the Watchdog  */
        MAP_WDT_A_holdTimer();
        xferIndex = 0;
    
        /* Select Port 1 for I2C - Set Pin 6, 7 to input Primary Module Function,
         *   (UCB0SIMO/UCB0SDA, UCB0SOMI/UCB0SCL).
         */
        MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
                GPIO_PIN6 + GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);
    
        P1->OUT |= (BIT6+BIT7);  // lazy pullups
        P1->REN |= (BIT6+BIT7);
    
        /* eUSCI I2C Slave Configuration */
        MAP_I2C_initSlave(EUSCI_B0_BASE, SLAVE_ADDRESS, EUSCI_B_I2C_OWN_ADDRESS_OFFSET0,
                EUSCI_B_I2C_OWN_ADDRESS_ENABLE);
    
        /* Enable the module and enable interrupts */
        MAP_I2C_enableModule(EUSCI_B0_BASE);
        MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
        MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
        MAP_Interrupt_enableInterrupt(INT_EUSCIB0);
        MAP_Interrupt_enableSleepOnIsrExit();
        MAP_Interrupt_enableMaster();
    
        /* Sleeping while not in use */
        while (1)
        {
            MAP_PCM_gotoLPM0();
        }
    }
    
    /*******************************************************************************
     * eUSCIB0 ISR. The repeated start and transmit/receive operations happen
     * within this ISR.
     ******************************************************************************/
    void EUSCIB0_IRQHandler(void)
    {
        uint_fast16_t status;
    
        status = MAP_I2C_getEnabledInterruptStatus(EUSCI_B0_BASE);
        MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE, status);
    
        /* RXIFG */
        if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0)
        {
            RXData[xferIndex++] = MAP_I2C_slaveGetData(EUSCI_B0_BASE);
    
            /* Resetting the index if we are at the end */
            if (xferIndex == NUM_OF_RX_BYTES)
            {
                txferMax = RXData[NUM_OF_RX_BYTES-1];
                xferIndex = 0;
                MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
                MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_START_INTERRUPT);
            }
        }
    
        /* TXIFG */
        if (status & EUSCI_B_I2C_TRANSMIT_INTERRUPT0)
        {
            MAP_I2C_slavePutData(EUSCI_B0_BASE, TXData[xferIndex++]);
    
            /* Resetting the index if we are at the end */
            if (xferIndex == txferMax)
            {
                xferIndex = 0;
                MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
                MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
            }
        }
    
        /* STIFG */
        if (status & EUSCI_B_I2C_START_INTERRUPT)
        {
            MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_START_INTERRUPT);
            MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
        }
    }
    

  • Hi, Chris,

    Thank you for acknowledging the issue.

     In the example you sent, the "stop-interrupt" call tmade in the interrupt handler occurs at the next-to-last byte read.

    My issue is, for a single byte read, there is NO "next-to-last" byte.  

    Am I understanding the code and your explanation correctly?

    If I modify my code to enable EUSCI_B_I2C_STOP_INTERRUPT, and make the stop-interrupt call on the last byte, will this solve the problem as is,

    or do I need to make a dummy read to actually trigger the stop interrupt?

    bob s.

  • My followup concern is that a a read (beyond the what the spec allows for a To-Be-Determined slave device) might cause problems for that slave device.
  • Bob,
    In the code example, if you want to only read one byte you must change both the NUM_OF_RX_BYTES to 1 and uncomment the definition of NUM_OF_RX_BYTES_IS_ONE (lines 83,84). This will remove the next-to-last byte code and simply send the start, send the stop and then read the RX buf in the stop isr. The trick is how long to wait after sending the start before sending the stop and I am trying to work on that definition. Please let me know if I have missed something.

    Regards,
    Chris
  • Thank you for clearing this up.
    I will wait for your definition of how long to wait between stop and start.
  • I'm impatient.
    I coded up your solution, using my slave device address and B2 configuration for a multibyte read (the non-anomaly case of read > 1), and the handler locks up in the first while statement after the last xmit. I'm going to bypass the while loops and try again.

    This never is asserted ->
    while
    (!BITBAND_PERI(EUSCI_B_CMSIS(EUSCI_B2_BASE)->IFG, EUSCI_B_IFG_TXIFG0_OFS))
    ;
  • 1. The first while loop in the revised interrupt handler hangs. So I commented that out and retried.
    2. The transmit+read after read 1byte doesn't hang anymore but the values read back aren't valid per the slave spec, they are all 0xff's.
    Q: Why did you switch from multibytestart to start?
  • Bob,
    I removed the multibytestart because it is appearing to corrupt the first byte being sent.

    /* Send start and the first byte of the transmit buffer. We have to send
    * two bytes to clean out whatever is in the buffer from a previous
    * send */
    MAP_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, TXData[0]);
    MAP_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, TXData[0]);


    /* Enabling transfer interrupt after stop has been sent */
    MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    In my adaptation I am simply sending the start and then handling the data transfer within the ISR.

    /* Send start and the first byte of the transmit buffer. We have to send
    * two bytes to clean out whatever is in the buffer from a previous
    * send */
    MAP_I2C_masterSendStart(EUSCI_B0_BASE);
    // MAP_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, TXData[0]);
    // MAP_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, TXData[0]);

    MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    To your earlier post, data is moved to the TX buffer in the ISR. When the last byte is loaded into the TX buf the interrupt is disabled, then the code waits (polls TXIFG) before changing the mode and sending the restart.

    MAP_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, TXData[xferIndex++]);
    if(xferIndex == NUM_OF_TX_BYTES)
    {
    MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    /*
    * Debug to get to work
    * wait until IFG is set before continuing on
    */
    while
    (!BITBAND_PERI(EUSCI_B_CMSIS(EUSCI_B0_BASE)->IFG, EUSCI_B_IFG_TXIFG0_OFS))
    ;
    MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_MODE);
    xferIndex = 0;
    MAP_I2C_masterReceiveStart(EUSCI_B0_BASE);

    I found that if you did not wait the last byte would be corrupted. I did not encounter an issue polling the IFG. Which revision of silicon are you using?

    Chris
  • Rev C.

    When I do a tx of 2 bytes, using multibyte start, i.e.: <address> <register_id> <data>,
    and also use multibyte start, the data word when read back does not appear to have be corrupted.
    However, when I tested SendStart followed by multibyte next, the data appeared corrupted on readback. Interesting.

    I have not done any longer multiword xmits because the protocol for my slave is of this form: <address> <register_id> <data>, and
    not all registers are w/r settable, some are status and don't change with writes.
  • Followup: I spent today coding and testing variations to see what affects what, and I found:
    1. adding this statement MAP_I2C_masterSendMultiByteStop(EUSCI_B2_BASE);
    at the completion of transmit to make the protocol handshake look correct causes the following multiword read to fail, unless re-init is called. This call not in your code but is in the example "master with multibyte master code"
    Removing the stop transmit call allows the read to succeed every call.
    2. The coding changes you sent (with polling and delay on receive 1) allows the read single byte to not cause the next transmit to fail,
    this succeeds multiple calls in a row. However, the data returned in the read is consistently wrong (when compared to a read 2 bytes at
    that register id). At this point, I don't remember if the earlier version I was using returned good data because I was focusing on the next call's failure. I'm burnt out and will try to regress the single byte read code tomorrow.
  • Followup to my followup. I tried one last run before giving up for the day, and set a breakpoint on the single byte read.
    The extra time by hitting the breakpoint caused the read value to be good. I'm betting a delay after EUSCI_B_I2C_STOP_INTERRUPT and before the read will solve my problem. I'll revisit this tomorrow.
  • Hi,

    I have something usable now, which is basically a tailoring of your code + what I  was using from the other examples.

     I noticed you are using core freq 8Mhz, and I am using core 48 Mhz. This affects the value of the delays.

    Given that embedded devices should NEVER lock up, when you push your example to an official release, you might want to rewrite your wait loops.

    Here's what I've done that provides feedback if status never comes true, and this type of thing occurs in multiple spots in the driver:

                    for (ii=0; ii<5; ii++)

                     {

                       /*

                        * Not sure if it is an error if the bit never comes true but

                        * definitely don't want to lock up

                        */

                        __delay_cycles(1000);

                        if (BITBAND_PERI(EUSCI_B_CMSIS(EUSCI_B2_BASE)->CTLW0, EUSCI_B_CTLW0_TXSTT))

                        {

                           ;  // still waiting

                        }

                        else

                        {

                          match_f = true;   // ready

                          break;            // exit loop

                        }

                     }

                     if (!match_f)

                       i2c_tmo2_f = true;

**Attention** This is a public forum