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.

MSP432P401M: API to send NACK in llC.h file to Communicate with FDC2212 with I2C

Part Number: MSP432P401M

Hi Sir/Madam,

My customer is using MSP432P401M and FDC2212 for cap sensing.

With reference to FDC2212 datasheet, during I2C read, there is a need to send NACK and a STOP from MSP432. 

Could you advise if there will be EUSCI_B_I2C DriverLib commands/API to do NACK to FDC2212?

There is a API in MSP430 to send a NACK in IIC.h file. Is the API available for MSP432P401M?

 

Hope to hear from you soon. Thanks.

  • Hong,

    A NACK can be sent by setting the UCTXSTP bit. Which is set by, for example through a function such as I2C_masterReceiveSingleByte() or I2C_masterSendSingleByteWithTimeout(). 

    When you call one of these functions, the function is used by the master module to send a byte. The function sends START, Transmits the byte to the Slave and sends STOP. With the STOP, the UCTXSTP bit is set and a NACK is generated per TRM, see below:

    Please refer to both the Driverlib API documentation and the TRM. 

  • Hi Evan,

    Thanks for your kind explanation. Please help to check for the code from my customer.

    Please check the code in EUSCIB3_IRQHandler.

    #1. If do not add the line MAP_I2C_masterReceiveSingle, the I2C bus hang after read one time.

    #2. Add MAP_I2C_masterReceiveSingle, then bus do not hang after read caused the MSP send the NACK bit.

       But MAP_I2C_masterReceiveSingle will send a extra 8 bit clock to slave that caused data error when next read.

        if (iStatus & EUSCI_B_I2C_RECEIVE_INTERRUPT0)

               {

                   if (RXByteCtr == RXData[NUM_OF_PAGE_BYTES]) {

                       MAP_I2C_masterReceiveMultiByteStop(CAT24_I2C_BASE);

                       MAP_I2C_masterReceiveSingle(CAT24_I2C_BASE); // I2C Send NACK

                       //# MAP_I2C_masterReceiveSingleByte(CAT24_I2C_BASE); // I2C Bus hang

                       //# MAP_I2C_masterReceiveMultiByteNext(CAT24_I2C_BASE); // Same as MAP_I2C_masterReceiveSingle

                       MAP_I2C_disableInterrupt(CAT24_I2C_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);

                       MAP_I2C_setMode(CAT24_I2C_BASE, EUSCI_B_I2C_TRANSMIT_MODE);

                       RXByteCtr = 0;

                       CAT24_I2C_Mode = CAT24_I2C_IDLE;

                       #if (!FW_RUN_MODE)

                       MAP_Interrupt_disableSleepOnIsrExit();

                       #endif

                   } else if (RXByteCtr <= RXData[NUM_OF_PAGE_BYTES] - 1) {

                       RXData[RXByteCtr++] = MAP_I2C_masterReceiveMultiByteNext(CAT24_I2C_BASE);

                   }

               }

    If code change to as follow, it do not send extra 8 bit clock to slave.

    But the I2C bus will hang after read one time.

        if (iStatus & EUSCI_B_I2C_RECEIVE_INTERRUPT0)

               {

                   if (RXByteCtr == RXData[NUM_OF_PAGE_BYTES] - 1) {

                       MAP_I2C_masterReceiveMultiByteStop(CAT24_I2C_BASE);

                       MAP_I2C_masterReceiveSingle(CAT24_I2C_BASE); // I2C Send NACK

                       //# MAP_I2C_masterReceiveSingleByte(CAT24_I2C_BASE); // I2C Bus hang

                       //# MAP_I2C_masterReceiveMultiByteNext(CAT24_I2C_BASE); // Same as MAP_I2C_masterReceiveSingle

                       MAP_I2C_disableInterrupt(CAT24_I2C_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);

                       MAP_I2C_setMode(CAT24_I2C_BASE, EUSCI_B_I2C_TRANSMIT_MODE);

                       RXByteCtr = 0;

                       CAT24_I2C_Mode = CAT24_I2C_IDLE;

                       #if (!FW_RUN_MODE)

                       MAP_Interrupt_disableSleepOnIsrExit();

                       #endif

                   } else if (RXByteCtr <= RXData[NUM_OF_PAGE_BYTES] - 2) {

                       RXData[RXByteCtr++] = MAP_I2C_masterReceiveMultiByteNext(CAT24_I2C_BASE);

                   }

               }

    If follow TI example code in the i2c_master_rw_repeated_start-master_code.c,

    It is just a workaround that replace the error data with new one.

    If read data is more than 3 bytes, it can work.

    If reading 2 bytes, the code will cause I2C bus hang.

    If reading only one data, it cannot work caused by not send stop bit.

    /* 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(CAT24_I2C_BASE, TXData[TXByteCtr]);

    MAP_I2C_masterSendMultiByteNext(CAT24_I2C_BASE, TXData[TXByteCtr++]);

    /* Receives bytes into the receive buffer. If we have received all bytes,

                * send a STOP condition */

               if (iStatus & EUSCI_B_I2C_RECEIVE_INTERRUPT0)

               {

                   if (RXByteCtr == RXData[NUM_OF_PAGE_BYTES] - 1) {

                       RXData[RXByteCtr++] = MAP_I2C_masterReceiveMultiByteNext(CAT24_I2C_BASE);

                       MAP_I2C_disableInterrupt(CAT24_I2C_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);

                       MAP_I2C_setMode(CAT24_I2C_BASE, EUSCI_B_I2C_TRANSMIT_MODE);

                       RXByteCtr = 0;

                       CAT24_I2C_Mode = CAT24_I2C_IDLE;

                       #if (!FW_RUN_MODE)

                       MAP_Interrupt_disableSleepOnIsrExit();

                       #endif

                   } if (RXByteCtr == RXData[NUM_OF_PAGE_BYTES] - 2) {

                       MAP_I2C_masterReceiveMultiByteStop(CAT24_I2C_BASE);

                       RXData[RXByteCtr++] = MAP_I2C_masterReceiveMultiByteNext(CAT24_I2C_BASE);

                   } else {

                       RXData[RXByteCtr++] = MAP_I2C_masterReceiveMultiByteNext(CAT24_I2C_BASE);

                   }

           }

    Thanks for your kind support.

    1715.i2c_master_rw_repeated_start-master_code.c
    /*
     * -------------------------------------------
     *    MSP432 DriverLib - v4_00_00_11 
     * -------------------------------------------
     *
     * --COPYRIGHT--,BSD,BSD
     * Copyright (c) 2017, 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 = ~3.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_REC_BYTES    10
    
    /* Variables */
    const uint8_t TXData[2] = {0x04, 0x00};
    static uint8_t RXData[NUM_OF_REC_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
            3000000,                                // SMCLK = 3MHz
            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();
    
        /* 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_REC_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);
    
            /* 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);
    
            /* 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[1]);
            MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
            MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_MODE);
            xferIndex = 0;
            MAP_I2C_masterReceiveStart(EUSCI_B0_BASE);
            MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    
        }
    
        /* Receives bytes into the receive buffer. If we have received all bytes,
         * send a STOP condition */
        if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0)
        {
            if(xferIndex == NUM_OF_REC_BYTES - 2)
            {
                MAP_I2C_masterReceiveMultiByteStop(EUSCI_B0_BASE);
                RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
            }
            else if(xferIndex == NUM_OF_REC_BYTES - 1)
            {
                RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
                MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
                MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
                xferIndex = 0;
                stopSent = true;
                MAP_Interrupt_disableSleepOnIsrExit();
            }
            else
            {
                RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
            }
    
        }
    }
        
    

  • Hong,


    I can look into this a bit deeper later today, but in the effort of making sure that your customer isn't trying to re-create the wheel, have they looked at the firmware of TI Designs for the FDC device using an MSP430FR5969? The Driverlib code is very similar to what would be implemented on an MSP432.


    I say this because it seems they are trying to make the FDC device work with generic MSP432 example code and not the example code that the device they want to interface with has.

  • Hong,

    Within the firmware that is included on that TIDA-00466, there is an I2C.c file that includes various routines that are specifically written for the FDC device. Specifically, there are two functions, i2c_readByte() and i2c_readWord() that I think would be very helpful in the context of your customer to help understand the logic necessary for this communication. in i2c_readWord() there is this snippet of code:

        while(1)
        {
            isrStatus = EUSCI_B_I2C_getInterruptStatus(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    
            if(isrStatus == EUSCI_B_I2C_RECEIVE_INTERRUPT0)
        	{
            	if(readCounter < 1)
            	{
    				pData[readCounter] = EUSCI_B_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
    				readCounter++;
    				if(readCounter == 1)
    				{
    	        		pData[readCounter] = EUSCI_B_I2C_masterReceiveMultiByteFinish(EUSCI_B0_BASE);
    					break;
    				}
            	}
        	}
        }

    The above isn't exactly what your customer is looking to do with regards to the outer bounds of the code, but logically with the i2c, this is exactly what they are looking to do as far as receiving multiple bytes.

    With regards to receiving a single byte, this is only done in the instance of the FDC device to read it's device ID in the TIDesign I provided and ultimately can be enabled in a separate funciton (i2c_readByte included in the i2c.c file in the TID download. Can you check if your customer has looked into this TI Design? I think most of his/her questions could be answered by this, but if not, I'm still willing to help more!

  • Hi Evan,

    Thanks for your kind support.

    My customer changed the code that follow your provided as follow.

    if (iStatus & EUSCI_B_I2C_RECEIVE_INTERRUPT0)
    {
    if (RXByteCtr == RXData[NUM_OF_PAGE_BYTES] - 1) {
    RXData[RXByteCtr++] = MAP_I2C_masterReceiveMultiByteFinish(CAT24_I2C_BASE);
    MAP_I2C_disableInterrupt(CAT24_I2C_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    MAP_I2C_setMode(CAT24_I2C_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
    RXByteCtr = 0;
    CAT24_I2C_Mode = CAT24_I2C_IDLE;
    #if (!FW_RUN_MODE)
    MAP_Interrupt_disableSleepOnIsrExit();
    #endif
    } else {
    RXData[RXByteCtr++] = MAP_I2C_masterReceiveMultiByteNext(CAT24_I2C_BASE);
    }
    }

    But the bus still hang after one time read in the driverlib.

    uint8_t I2C_masterReceiveMultiByteFinish(uint32_t moduleInstance)
    {
    //Send stop condition.
    BITBAND_PERI(EUSCI_B_CMSIS(moduleInstance)->rCTLW0.r,UCTXSTP_OFS) = 1;

    //Wait for Stop to finish
    while (BITBAND_PERI(EUSCI_B_CMSIS(moduleInstance)->rCTLW0.r, UCTXSTP_OFS))
    {
    // Wait for RX buffer
    while (!BITBAND_PERI(EUSCI_B_CMSIS(moduleInstance)->rIFG, UCRXIFG_OFS)) <= Hang at this line
    ;
    }

    /* Capture data from receive buffer after setting stop bit due to
    MSP430 I2C critical timing. */
    return EUSCI_B_CMSIS(moduleInstance)->rRXBUF.b.bRXBUF;
    }

    Please help to take a look. Thank you very much.
  • Based on my understanding, you are getting hung up waiting for the RX Buffer and this is undesirable. What happens when you use MAP_I2C_masterReceiveMultiByteStop(CAT24_I2C_BASE); instead of multiByteFinish?

    Can you tell me what version of driverlib they are using?
  • Hong Tay,
    I'm going to close this thread due to innactivity. If you have another question unrelated to the topic above, please post another thread, if you have any more questions related to this, feel free to post here and thread will reopen.

**Attention** This is a public forum