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/MSP-EXP430FR6989: MSP430FR6989

Part Number: MSP-EXP430FR6989
Other Parts Discussed in Thread: MSP430FR6989, BOOSTXL-BATPAKMKII

Tool/software: Code Composer Studio

This screen capture shows the sequence of operation o the I2C between the PCF8523 and the TI MCU

Slave address is 0x68 << 1 (D0 for write D1 for Read ) 

We are reading register control 3 from the PCF 8523  

We have write on slave 0x68 the register address to read 0x02 an ACK is replied by device

then we send a Read  which is replied with ACK as well, then on the I2c bus we see the content of this register 0xE0 which is consistent with what is expected from the PCF8523 Datasheet. 

the NAK at the end of this transfer is the issue. I was expecting to see a ACK at this time. 

Could you give some guidance to solve this issue ?

REPORT_TI.zip

Hi,

Our project, among other modules, uses the I2C Module. 

The device we are designing, is using an NXP PCF8523 external RTC.

The hardware connections between the NXP PCF8523 and the Launchpad board have been done as follows:

  1. P4.1 SCL to SCL PCF8523 
  2. P4.0 SDA to SDA PCF8523
  3. VCC from PCF8523 to TI Board
  4. GND from PCF8523 to TI Board

We use the source code based on the supplied example code BOOSTXL-BATPAKMKII_FuelGauge_MSP430FR6989

From this base project we stripped everything that is not I2C related the resulting project is called REPORT_TI.

The main program is as follows

int main(void) {


// Halt the watchdog timer
WDT_A_hold(WDT_A_BASE);

/* Initialization */
GPIO_init();
CS_init();


/* Initialize I2C */
I2C_initGPIO();
I2C_init();



__delay_cycles(800000);


bool res;
char val;

// Read Control Register 1

while(1)

{

I2C_setslave(0x68);

res = I2C_read8(0x0, &val, 1000);

__delay_cycles(8000);

res = I2C_read8(0x2, &val, 1000);

__delay_cycles(8000);

res = res;

}

}


/* Initializes Clock System */

void CS_init() {

// Set PJ.4 and PJ.5 as Secondary Module Function Input, LFXT.

GPIO_setAsPeripheralModuleFunctionInputPin(
GPIO_PORT_PJ,
GPIO_PIN4 + GPIO_PIN5,
GPIO_PRIMARY_MODULE_FUNCTION
);

CS_setExternalClockSource(32768, 0);
// Intializes the XT1 crystal oscillator
CS_turnOnLFXT(CS_LFXT_DRIVE_3);

/* Initializes Clock System DCO = 8MHz */
CS_setDCOFreq(CS_DCORSEL_0, CS_DCOFSEL_6);
CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
CS_initClockSignal(CS_ACLK, CS_LFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);
}


/* Initializes GPIO */
void GPIO_init()
{
/* Terminate all GPIO pins to Output LOW to minimize power consumption */
GPIO_setAsOutputPin(GPIO_PORT_PA, GPIO_PIN_ALL16);
GPIO_setAsOutputPin(GPIO_PORT_PB, GPIO_PIN_ALL16);
GPIO_setAsOutputPin(GPIO_PORT_PC, GPIO_PIN_ALL16);
GPIO_setAsOutputPin(GPIO_PORT_PD, GPIO_PIN_ALL16);
GPIO_setAsOutputPin(GPIO_PORT_PE, GPIO_PIN_ALL16);
GPIO_setAsOutputPin(GPIO_PORT_PF, GPIO_PIN_ALL16);
GPIO_setOutputLowOnPin(GPIO_PORT_PA, GPIO_PIN_ALL16);
GPIO_setOutputLowOnPin(GPIO_PORT_PB, GPIO_PIN_ALL16);
GPIO_setOutputLowOnPin(GPIO_PORT_PC, GPIO_PIN_ALL16);
GPIO_setOutputLowOnPin(GPIO_PORT_PD, GPIO_PIN_ALL16);
GPIO_setOutputLowOnPin(GPIO_PORT_PE, GPIO_PIN_ALL16);
GPIO_setOutputLowOnPin(GPIO_PORT_PF, GPIO_PIN_ALL16);


// Disable the GPIO power-on default high-impedance mode
// to activate previously configured port settings
PMM_unlockLPM5();
}

  • What do you observe when it runs?

    Does your RTC's breakout board include the I2C pullups? The Launchpad doesn't supply them.

  • Hello Jean Pierre,

    This is expected behavior/  The NACK is created by the master when it sets the stop bit.

    You can read more in the MSP430FR6989 users guide.

  • Dennis, 

    Thank you so much for pointing this to me. 

    This is certainly something I should have known and was right there in the manual if only I had read it correctly. 

    This issue being behind me now I am faced with another that should be trivial. 

    Let me explain:

    I am using the I2C bus to communicate with a PCF8523 RTC module. 

    I can read and write individual  registers.

    the registers that keeping date a time are recommended to be read as an array. 

    I then extended the code sample I got from HAL_i2C.[c,h]  

    read and write arrays of registers.

    This however does not work for me. 

    I am certainly doing something very stupid and wrong but so far I have not found it. 

    I worked around this issue for today by reading and writing those registers individually 

    It would be nice, however,  to get this fixed and understood ( probably  understood first fixed second :-))

    If you have few cycles free and could point me in the right direction I would be, sincerely,   grateful.

    I have yet another battle to win ( for some other day)  and it is related with the #pragma PERSISTENT.

    But one battle at a time :-)

    Thank you again for your very kind reply

    /***************************************************************************//**

     * @brief  Reads array of data from the slave device

     * @param array the address of the array where to store the data

     *              the first element of the array is the address of the first

     *              element to read from slave device

     * @param numItems the number of items to retrieve from the slave device.

     * @return boolean indicating success or failure

     *

     ******************************************************************************/

    bool I2C_writeArray(unsigned char *array,

                        unsigned int numItems,

                        unsigned int timeout);

    /***************************************************************************//**

     * @brief  Reads array of data from the slave device

     * @param array the address of the array where to store the data

     *              the first element of the array is the address of the first

     *              element to read from slave device

     * @param numItems the number of items to retrieve from the slave device.

     * @return boolean indicating success or failure

     *

     ******************************************************************************/

    bool I2C_readArray(unsigned char *array,

                       unsigned int numItems,

                       unsigned int timeout);

    HAL_I2C.h

    3364.HAL_I2C.c
    /* --COPYRIGHT--,BSD
     * Copyright (c) 2015, 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--*/
    //****************************************************************************
    //
    // HAL_I2C.c - Hardware abstraction layer for I2C with MSP430
    //
    //****************************************************************************
    
    #include <driverlib.h>
    #include "HAL_I2C.h"
    
    
    /*
     * I2C Master Configuration Parameter
     */
    EUSCI_B_I2C_initMasterParam i2cParam =
    {
            EUSCI_B_I2C_CLOCKSOURCE_SMCLK,          /* SMCLK Clock Source */
    		8000000,                                /* SMCLK = 8MHz */
            EUSCI_B_I2C_SET_DATA_RATE_400KBPS,      /* Desired I2C Clock of 400khz */
            0,                                      /* No byte counter threshold */
            EUSCI_B_I2C_NO_AUTO_STOP                /* No Autostop */
    };
    
    /***************************************************************************//**
     * @brief  Configures GPIO for I2C
     * @param  none
     * @return none
     ******************************************************************************/
    void I2C_initGPIO(void)
    {
        /*
         * Select I2C function for I2C_SCL
         */
        GPIO_setAsPeripheralModuleFunctionOutputPin(I2C_SCL_PORT,
                                                    I2C_SCL_PIN,
                                                    I2C_SELECT_FUNCTION);
    
        /*
         * Select I2C function for I2C_SDA
         */
        GPIO_setAsPeripheralModuleFunctionOutputPin(I2C_SDA_PORT,
                                                    I2C_SDA_PIN,
                                                    I2C_SELECT_FUNCTION);
        return;
    }
    
    
    /***************************************************************************//**
     * @brief  Configures I2C
     * @param  none
     * @return none
     ******************************************************************************/
    void I2C_init(void)
    {
        /*
         * Initialize USCI_B0 and I2C Master to communicate with slave devices
         */
        EUSCI_B_I2C_initMaster(I2C_BASE,
                               &i2cParam);
    
        /*
         * Disable I2C module to make changes
         */
        EUSCI_B_I2C_disable(I2C_BASE);
    
        /*
         * Enable I2C Module to start operations
         */
        EUSCI_B_I2C_enable(I2C_BASE);
    
        return;
    }
    
    
    /***************************************************************************//**
     * @brief  Writes data to the slave
     * @param  pointer  Address of register you want to modify
     * @param  writeByte Data to be written to the specified register
     * @return none
     ******************************************************************************/
    bool I2C_write8 (unsigned char pointer,
                     unsigned char writeByte,
                     unsigned int timeout)
    {
        /*
         * Set master to transmit mode PL
         */
    	EUSCI_B_I2C_setMode(I2C_BASE,
    	                    EUSCI_B_I2C_TRANSMIT_MODE);
    
        /*
         * Clear any existing interrupt flag PL
         */
    	EUSCI_B_I2C_clearInterrupt(I2C_BASE,
    	                           EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    
        /*
         * Initiate start and send first character
         */
        if (!EUSCI_B_I2C_masterSendMultiByteStartWithTimeout(I2C_BASE,
                                                             pointer,
                                                             timeout))
        {
        	return false;
        }
    
        if (!EUSCI_B_I2C_masterSendMultiByteFinishWithTimeout(I2C_BASE,
                                                              writeByte,
                                                              timeout))
        {
        	return false;
        }
    
        return true;
    }
    
    
    /***************************************************************************//**
     * @brief  Writes data to the slave
     * @param  pointer  Address of register you want to modify
     * @param  writeWord Data to be written to the specified register
     * @return none
     ******************************************************************************/
    bool I2C_write16 (unsigned char pointer,
                      unsigned short writeWord,
                      unsigned int timeout)
    {
        /*
         * Set master to transmit mode PL
         */
    	EUSCI_B_I2C_setMode(I2C_BASE,
    	                    EUSCI_B_I2C_TRANSMIT_MODE);
    
        /*
         * Clear any existing interrupt flag PL
         */
    	EUSCI_B_I2C_clearInterrupt(I2C_BASE,
    	                           EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    
    
    
        /*
         * Initiate start and send first character
         */
        if (!EUSCI_B_I2C_masterSendMultiByteStartWithTimeout(I2C_BASE,
                                                             pointer,
                                                             timeout))
        {
        	return false;
        }
    
        /*
         * Send the MSB of writeByte to slave
         */
        if (!EUSCI_B_I2C_masterSendMultiByteNextWithTimeout(I2C_BASE,
                                                            (unsigned char)(writeWord & 0xFF),
                                                            timeout))
        {
        	return false;
        }
    
        if (!EUSCI_B_I2C_masterSendMultiByteFinishWithTimeout(I2C_BASE,
            (unsigned char)(writeWord>>8), timeout))
        {
        	return false;
        }
    
        return true;
    }
    
    
    /***************************************************************************//**
     * @brief  Reads data from the slave
     * @param  pointer Address of register to read from
     * @return Register contents
     ******************************************************************************/
    bool I2C_read8(unsigned char pointer,
                   char * result,
                   unsigned int timeout)
    {
        volatile int val = 0;
        volatile int valScratch = 0;
    
        /*
         * Set master to transmit mode PL
         */
        EUSCI_B_I2C_setMode(I2C_BASE,
            EUSCI_B_I2C_TRANSMIT_MODE);
    
        /*
         * Clear any existing interrupt flag PL
         */
        EUSCI_B_I2C_clearInterrupt(I2C_BASE,
            EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    
        /*
         * Initiate start and send first character
         */
        if (!EUSCI_B_I2C_masterSendSingleByteWithTimeout(I2C_BASE,
            pointer, timeout))
            return 0;
    
    
        *result = EUSCI_B_I2C_masterReceiveSingleByte(I2C_BASE);
    
        return 1;
    
    }
    
    /***************************************************************************//**
     * @brief  Reads data from the slave
     * @param  pointer Address of register to read from
     * @return Register contents
     ******************************************************************************/
    bool I2C_read16(unsigned char pointer,
                    short * result,
                    unsigned int timeout)
    {
        uint8_t val = 0;
        uint8_t valScratch = 0;
        short r = 0;
    
        /*
         * Set master to transmit mode PL
         */
        EUSCI_B_I2C_setMode(I2C_BASE,
                            EUSCI_B_I2C_TRANSMIT_MODE);
    
        /*
         * Clear any existing interrupt flag PL
         */
        EUSCI_B_I2C_clearInterrupt(I2C_BASE,
                                   EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    
        /*
         * Initiate start and send first character
         */
        if (!EUSCI_B_I2C_masterSendSingleByteWithTimeout(I2C_BASE,
                                                         pointer,
                                                         timeout))
        {
        	return false;
        }
    
        /*
         * Generate Start condition and set it to receive mode.
         * This sends out the slave address and continues to read
         * until you issue a STOP
         */
        EUSCI_B_I2C_masterReceiveStart(I2C_BASE);
    
        /*
         * Wait for RX buffer to fill
         */
        while(!(EUSCI_B_I2C_getInterruptStatus(I2C_BASE,
                                               EUSCI_B_I2C_RECEIVE_INTERRUPT0)));
    
        /*
         * Read from I2C RX register
         */
        valScratch = EUSCI_B_I2C_masterReceiveMultiByteNext(I2C_BASE);
    
        /*
         * Receive second byte then send STOP condition
         */
        if (!EUSCI_B_I2C_masterReceiveMultiByteFinishWithTimeout(I2C_BASE,
                                                                 &val,
                                                                 timeout))
        {
        	return false;
        }
    
        /*
         * Shift val to top MSB
         */
        r = (val << 8);
    
        /*
         * Read from I2C RX Register and write to LSB of r
         */
        r |= valScratch;
    
        /*
         * Return  value
         */
        *result = r;
    
        return true;
    }
    /***************************************************************************//**
     * @brief  Read Array of data from the slave
     * @param array A pointer to the array of bytes to receive the data
     * @param numItems a total number of bytes to be received
     * @param timeout maximum amount of time to receive data from the slave
     * @return a boolean value indicating success or failure
     ******************************************************************************/
    bool I2C_readArray(unsigned char *array,
                       unsigned int numItems,
                       unsigned int timeout)
    {
        uint8_t arrayIndex;
        unsigned int timeoutCounter = timeout;
    
        /*
         * Retrieve address of the first
         * Register to write
         */
        unsigned char pointer = array[0];
    
        /*
         * Set master to transmit mode PL
         */
        EUSCI_B_I2C_setMode(I2C_BASE,
                            EUSCI_B_I2C_TRANSMIT_MODE);
    
        /*
         * Clear any existing interrupt flag PL
         */
        EUSCI_B_I2C_clearInterrupt(I2C_BASE,
                                   EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    
    
        /*
         * Initiate start and send first character
         */
        if (!EUSCI_B_I2C_masterSendSingleByteWithTimeout(I2C_BASE,
                                                         pointer,
                                                         timeout))
        {
                return false;
        }
    
        /*
         * Generate Start condition and set it to receive mode.
         * This sends out the slave address and continues to read
         * until you issue a STOP
         */
         EUSCI_B_I2C_masterReceiveStart(I2C_BASE);
    
        /*
         * Wait for RX buffer to fill
         */
        while(!(EUSCI_B_I2C_getInterruptStatus(I2C_BASE,
                                               EUSCI_B_I2C_RECEIVE_INTERRUPT0)));
    
    
        /*
         * Initiate start and send first character
         */
        if (!EUSCI_B_I2C_masterSendSingleByteWithTimeout(I2C_BASE,
                                                         pointer,
                                                         timeout))
        {
                return false;
        }
    
        /*
         * Read the numItems bytes from the Slave
         */
        for (arrayIndex = 1 ; arrayIndex < (numItems -1) ; arrayIndex++ )
        {
            /*
             * Read from I2C registers
             */
            array[arrayIndex] = EUSCI_B_I2C_masterReceiveMultiByteNext(I2C_BASE);
        }
    
        if (!EUSCI_B_I2C_masterReceiveMultiByteFinishWithTimeout(I2C_BASE,
                                                                 (uint8_t *)array[arrayIndex],
                                                                 timeout))
        {
            return false;
        }
    
        return true;
    
    }
    
    
    
    
    
    
    /***************************************************************************//**
     * @brief  Write Array of data to the slave
     * @param
     * @return
     ******************************************************************************/
    bool I2C_writeArray(unsigned char *array,
                        unsigned int numItems,
                        unsigned int timeout)
    {
        uint8_t arrayIndex;
        unsigned int timeoutCounter = timeout;
        /*
         * Retrieve address of the first
         * Register to write
         */
        unsigned char pointer = array[0];
    
        /*
         * Set master to transmit mode PL
         */
        EUSCI_B_I2C_setMode(I2C_BASE,
                            EUSCI_B_I2C_TRANSMIT_MODE);
    
        /*
         * Clear any existing interrupt flag PL
         */
        EUSCI_B_I2C_clearInterrupt(I2C_BASE,
                                   EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    
    
        if (!EUSCI_B_I2C_masterSendMultiByteStartWithTimeout(I2C_BASE,
                                                        pointer,
                                                        timeout))
        {
            return false;
        }
    
        for (arrayIndex = 1 ; arrayIndex < (numItems -1) ; arrayIndex++ )
        {
            if (!EUSCI_B_I2C_masterSendMultiByteNextWithTimeout(I2C_BASE,
                                                           array[arrayIndex],
                                                           timeout))
            {
                return false;
            }
        }
        if (!EUSCI_B_I2C_masterSendMultiByteNextWithTimeout(I2C_BASE,
                                                            array[numItems],
                                                            timeout))
        {
            return false;
        }
    
        while( EUSCI_B_I2C_isBusBusy(I2C_BASE) && --timeoutCounter);
    
        return true;
    }
    
    
    
    /***************************************************************************//**
     * @brief  set slave address
     * @param  slaveAdr
     * @return none
     ******************************************************************************/
    void I2C_setslave(unsigned short slaveAdr)
    {
        /* Specify slave address for I2C */
    	EUSCI_B_I2C_setSlaveAddress(I2C_BASE,
            slaveAdr);
    
        /* Enable and clear the interrupt flag */
    	EUSCI_B_I2C_clearInterrupt(I2C_BASE,
            EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_RECEIVE_INTERRUPT0);
        return;
    }
    

  • On (.c) line 380, after switching to Receive mode, you're trying to send the pointer byte again, which won't succeed -- it will spin waiting for TXIFG, then time out. [Ref User Guide (SLAU367O) Fig 32]

    Remove that line (actually the entire if()). You may want to replace it with a Receive call to fill in array[0].

**Attention** This is a public forum