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.

I2C problem

> In I2C protocol i am facing a problem regarding the mismatch in REG ADDRESS(8 bit) & Read/Write Register address(16 bit) because of which i am enable to perform Read/Write Operations.Here slave is a FRAM IC FM24V10.

My I2C code allows me to send only 8bit of REG ADDR, while the communication with FRAM requires 16 bit of REG ADDRESS(LSB and MSB).

Can you explain me a way to send 16 byte transfer of I2C data in register address.

I am posting a sample of my i2c code, please specify the changes I have to make it working.

                                                                             Write Operation

/*
 $License:
    Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
 $
 */
/******************************************************************************
 * $Id: msp430_i2c.h $
 *****************************************************************************/
/**
 *  @defgroup MSP430_System_Layer MSP430 System Layer
 *  @brief  MSP430 System Layer APIs.
 *          To interface with any platform, eMPL needs access to various
 *          system layer functions.
 *
 *  @{
 *      @file       msp430_i2c.c
 *      @brief      Serial communication functions needed by eMPL to
 *                  communicate to the MPU devices.
 *      @details    This driver assumes that eMPL is with a sub-master clock set
 *                  to 20MHz. The following MSP430s are supported:
 *
 *                  MSP430F5528
 *                  MSP430F5529
 */
#include <stdio.h> //only for testing
#include "msp430.h"
#include "msp430_i2c.h"
#include "msp430_clock.h"

#define I2C_TIMEOUT_MS  (2500)

#if !defined __MSP430F5438A__ && !defined __MSP430F5528__ && \
    !defined __MSP430F5529__ && !defined __MSP430F5229__
#error  The I2C driver does not support this MSP430.
#endif

#if defined I2C_B0
#define CTL0    UCB0CTL0
#define CTL1    UCB0CTL1
#define IE      UCB0IE
#define BR0     UCB0BR0
#define BR1     UCB0BR1
#define I2CSA   UCB0I2CSA
#define RXBUF   UCB0RXBUF
#define TXBUF   UCB0TXBUF
#define IFG     UCB0IFG
#define I2C_VEC USCI_B0_VECTOR
#define IV      UCB0IV
#elif defined I2C_B1
#define CTL0    UCB1CTL0
#define CTL1    UCB1CTL1
#define IE      UCB1IE
#define BR0     UCB1BR0
#define BR1     UCB1BR1
#define I2CSA   UCB1I2CSA
#define RXBUF   UCB1RXBUF
#define TXBUF   UCB1TXBUF
#define IFG     UCB1IFG
#define I2C_VEC USCI_B1_VECTOR
#define IV      UCB1IV
#else
#error  Define either I2C_B0 or I2C_B1 in your configuration.
#endif

typedef enum {
    STATE_WAITING,
    STATE_READING,
    STATE_WRITING
} msp430_i2c_state;

typedef struct {
    volatile msp430_i2c_state state;
    /* First slave register. */
    unsigned char slave_reg;
    /* 0 if slave register has not been written yet. */
    unsigned char slave_reg_written;
    unsigned char *data;
    unsigned short length;
    unsigned char enabled;
} msp430_i2c_info;

static msp430_i2c_info i2c = {
    .enabled = 0
};

#if defined __MSP430F5438A__
#if defined I2C_B0
#define I2C_MODE(void)  do {P3SEL |= 0x06;} while (0)
#define GPIO_MODE(void) do {P3SEL &= ~0x06;} while (0)
#define SET_SCL(void)   do {P3OUT |= 0x04;} while (0)
#define CLEAR_SCL(void) do {P3OUT &= ~0x04;} while (0)
#define SET_SDA(void)   do {P3OUT |= 0x02;} while (0)
#define CLEAR_SDA(void) do {P3OUT &= ~0x02;} while (0)
#else
#define I2C_MODE(void)  do {P5SEL |= 0x10; P3SEL |= 0x80;} while (0)
#define GPIO_MODE(void) do {P5SEL &= ~0x10; P3SEL &= ~0x80;} while (0)
#define SET_SCL(void)   do {P5OUT |= 0x10;} while (0)
#define CLEAR_SCL(void) do {P5OUT &= ~0x10;} while (0)
#define SET_SDA(void)   do {P3OUT |= 0x80;} while (0)
#define CLEAR_SDA(void) do {P3OUT &= ~0x80;} while (0)
#endif
#else
#if defined I2C_B0
#define I2C_MODE(void)  do {P3SEL |= 0x03;} while (0)
#define GPIO_MODE(void) do {P3SEL &= ~0x03;} while (0)
#define SET_SCL(void)   do {P3OUT |= 0x02;} while (0)
#define CLEAR_SCL(void) do {P3OUT &= ~0x02;} while (0)
#define SET_SDA(void)   do {P3OUT |= 0x01;} while (0)
#define CLEAR_SDA(void) do {P3OUT &= ~0x01;} while (0)
#else
#define I2C_MODE(void)  do {P4SEL |= 0x06;} while (0)
#define GPIO_MODE(void) do {P4SEL &= ~0x06;} while (0)
#define SET_SCL(void)   do {P4OUT |= 0x04;} while (0)
#define CLEAR_SCL(void) do {P4OUT &= ~0x04;} while (0)
#define SET_SDA(void)   do {P4OUT |= 0x02;} while (0)
#define CLEAR_SDA(void) do {P4OUT &= ~0x02;} while (0)
#endif
#endif

int msp430_i2c_enable(void)
{
    unsigned long smclk;
    unsigned short br;
    if (i2c.enabled)
        return 0;
    CTL1 |= UCSWRST;

    I2C_MODE();

    /* Set to synchronous master mode. */
    CTL0 = UCMST + UCMODE_3 + UCSYNC;

    /* Use sub-master clock. */
    CTL1 = UCSSEL_2 + UCSWRST;

    /* Set slave clock frequency to 400kHz. */
    msp430_get_smclk_freq(&smclk);
    br = smclk / 400000L;
    BR0 = (unsigned char)(br & 0xFF);
    BR1 = (unsigned char)((br >> 8) & 0xFF);

    CTL1 &= ~UCSWRST;

    /* Enable interrupts. */
    IE |= UCTXIE | UCRXIE | UCNACKIE;

    /* Initialize struct. */
    i2c.state = STATE_WAITING;
    i2c.slave_reg = 0;
    i2c.slave_reg_written = 0;
    i2c.data = 0;
    i2c.length = 0;
    i2c.enabled = 1;

    return 0;
}

int msp430_i2c_disable(void)
{
    if (!i2c.enabled)
        return 0;
    CTL1 |= UCSWRST;
    GPIO_MODE();
    SET_SCL();
    SET_SDA();
    i2c.enabled = 0;
    return 0;
}

int msp430_i2c_write(unsigned char slave_addr,
                     unsigned char reg_addr,
                     unsigned char length,
                     unsigned char const *data)
{
    unsigned long start, cur;
    if (!i2c.enabled)
    {
    	return -1;
    }
    if (!length)
        return 0;

    /* Populate struct. */
    i2c.state = STATE_WRITING;
    i2c.slave_reg = reg_addr;
    i2c.slave_reg_written = 0;
    i2c.data = (unsigned char*)data;
    i2c.length = length;

    I2CSA = slave_addr;
    CTL1 |= UCTR | UCTXSTT;

    msp430_get_clock_ms(&start);

    while (i2c.state != STATE_WAITING) {
        __bis_SR_register(LPM0_bits + GIE);
        msp430_get_clock_ms(&cur);

        if (cur >= (start + I2C_TIMEOUT_MS)) {

            CTL1 |= UCTXSTP;
            i2c.state = STATE_WAITING;
            msp430_i2c_disable();
            msp430_delay_ms(1);
            CLEAR_SCL();
            CLEAR_SDA();
            msp430_delay_ms(1);
            SET_SCL();
            SET_SDA();
            msp430_i2c_enable();

            return -1;
        }
    }

    return 0;
}

int msp430_i2c_read(unsigned char slave_addr,
                    unsigned char reg_addr,
                    unsigned char length,
                    unsigned char *data)
{
    unsigned long start, cur;
    if (!i2c.enabled)
        return -1;
    if (!length)
        return 0;

    /* Populate struct. */
    i2c.state = STATE_READING;
    i2c.slave_reg = reg_addr;
    i2c.slave_reg_written = 0;
    i2c.data = data;
    i2c.length = length;

    I2CSA = slave_addr;
    CTL1 |= UCTR | UCTXSTT;

    msp430_get_clock_ms(&start);
    while (i2c.state != STATE_WAITING) {
        __bis_SR_register(LPM0_bits + GIE);
        msp430_get_clock_ms(&cur);
        if (cur >= (start + I2C_TIMEOUT_MS)) {
            CTL1 |= UCTXSTP;
            i2c.state = STATE_WAITING;
            msp430_i2c_disable();
            msp430_delay_ms(1);
            CLEAR_SCL();
            CLEAR_SDA();
            msp430_delay_ms(1);
            SET_SCL();
            SET_SDA();
            msp430_i2c_enable();
            return -1;
        }
    }
    return 0;
}

#pragma vector = I2C_VEC
__interrupt void I2C_ISR(void)
{
    switch(__even_in_range(IV,12)) {
        case 4:     /* NAK interrupt. */
            i2c.state = STATE_WAITING;
            CTL1 |= UCTXSTP;
            break;
        case 10:    /* RX interrupt. */
            IFG &= ~UCRXIFG;
            if (--i2c.length) {
                /* If only one byte left, prepare stop signal. */
                if (i2c.length == 1)
                    CTL1 |= UCTXSTP;
            } else
                i2c.state = STATE_WAITING;
            /* Read RXBUF last because we don't want to release SCL until we're
             * sure we're ready.
             */
            *i2c.data++ = RXBUF;
            break;
        case 12:    /* TX interrupt. */
            IFG &= ~UCTXIFG;
            switch (i2c.state) {
            case STATE_WRITING:
                if (!i2c.slave_reg_written) {
                    i2c.slave_reg_written = 1;
                    TXBUF = i2c.slave_reg;
                } else if (i2c.length) {
                    /* Send next byte, increment pointer. */
                    char next = i2c.data[0];
                    i2c.data++;
                    i2c.length--;
                    /* Writing to TXBUF must always be the final operation. */
                    TXBUF = next;
                } else {
                    i2c.state = STATE_WAITING;
                    CTL1 |= UCTXSTP;
                }
                break;
            case STATE_READING:
                if (!i2c.slave_reg_written) {
                    i2c.slave_reg_written = 1;
                    TXBUF = i2c.slave_reg;
                } else {
                    /* Repeated start, switch to RX mode. */
                    CTL1 &= ~UCTR;
                    CTL1 |= UCTXSTT;

                    /* If single byte, prepare stop signal immediately. */
                    if (i2c.length == 1) {
                        /* Well, not IMMEDIATELY. First we need to make sure
                         * the start signal got sent.
                         */
                        while (CTL1 & UCTXSTT);
                        CTL1 |= UCTXSTP;
                    }
                }
                break;
            case STATE_WAITING:
            default:
                break;
            }
            break;
        case 0:     /* No interrupt. */
        case 2:     /* Arbitration lost interrupt. */
        case 6:     /* Start condition interrupt. */
        case 8:     /* Stop condition interrupt. */
        default:
            break;
    }
    __bic_SR_register_on_exit(LPM0_bits);
}
/*
 $License:
    Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
 $
 */
/******************************************************************************
 * $Id: msp430_i2c.h $
 *****************************************************************************/
/**
 *  @defgroup MSP430_System_Layer MSP430 System Layer
 *  @brief  MSP430 System Layer APIs.
 *          To interface with any platform, eMPL needs access to various
 *          system layer functions.
 *
 *  @{
 *      @file       msp430_i2c.h
 *      @brief      Serial communication functions needed by eMPL to
 *                  communicate to the MPU devices.
 *      @details    This driver assumes that eMPL is with a sub-master clock set
 *                  to 20MHz. The following MSP430s are supported:
 *
 *                  MSP430F5528
 *                  MSP430F5529
 */
#ifndef _MSP430_I2C_H_
#define _MSP430_I2C_H_

/**
 *  @brief	Set up the I2C port and configure the MSP430 as the master.
 *  @return	0 if successful.
 */
int msp430_i2c_enable(void);
/**
 *  @brief  Disable I2C communication.
 *  This function will disable the I2C hardware and should be called prior to
 *  entering low-power mode.
 *  @return 0 if successful.
 */
int msp430_i2c_disable(void);
/**
 *  @brief      Write to a device register.
 *
 *  @param[in]  slave_addr  Slave address of device.
 *  @param[in]  reg_addr	Slave register to be written to.
 *  @param[in]  length      Number of bytes to write.
 *  @param[out] data        Data to be written to register.
 *
 *  @return     0 if successful.
 */
int msp430_i2c_write(unsigned char slave_addr,
                     unsigned char reg_addr,
                     unsigned char length,
                     unsigned char const *data);
/**
 *  @brief      Read from a device.
 *
 *  @param[in]  slave_addr  Slave address of device.
 *  @param[in]  reg_addr	Slave register to be read from.
 *  @param[in]  length      Number of bytes to read.
 *  @param[out] data        Data from register.
 *
 *  @return     0 if successful.
 */
int msp430_i2c_read(unsigned char slave_addr,
                    unsigned char reg_addr,
                    unsigned char length,
                    unsigned char *data);

#endif  /* _MSP430_I2C_H_ */

/**
 * @}
 */

  • Hello Ashish,

    Why not just include a second register address definition inside of your structure and write subfunction?  Then alter your I2C_ISR to send the Address LSB after the Address MSB before moving on to the data bytes.  If you know what your code is doing, it shouldn't be too hard to change it to fit your needs.

    Regards,

    Ryan

  • For I2C, Address MSB and Address LSB are just two more data bytes. It’s your high-level code that needs to assemble a 16 bit int address (instead of the current 8 bit char address parameter) and n data bytes to 2+n data bytes to be sent.

    Simplest (but rather clumsy) way would be to give the MSB of the register address as address parameter, and the LSB as the first data byte, in front of the real data bytes. This way, no change on the ISR (which only expects one address byte to be sent)  or the write function needs to be made.

    Personally, I don’t like low-level stuff (I2C_write, ISR) that assumes certain target features that are outside the scope of the interface. You can see where this leads: many I2C slaves have an 8 bit register address, but some (like yours) have 16 bit and some have none at all. Yet the code “ass-umes” one register address byte and won’t work with all the other possible slaves.

  • First of all thank you to show me path 

    According to whatever you say i have modified my code ,C file & Corresponding header file.my code debug well with no errors ,But Unfortunately it stops and go into infinite loop & The information i am getting from ULP is:

    i : (ULP 2.1) Detected SW delay loop using empty loop. Recommend using a timer module instead

    Please tell me what is happening & What is the reason for this.

     Thanks in Advance

    #include <msp430f5529.h>
    
    #include <I2C.h>
    
    #include"stdio.h"
    
    
    /*
     * main.c
     */
    int main(void) {
        WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    /*  // printf("hello\n");
        P1DIR|=0x01;
        P1OUT&=0x00;
        P4DIR|=BIT7;
        P4OUT&=0x00;	*/
      //  printf("in\n");
        unsigned char configData=0x00;
        P3SEL |=0x03;
        UCB0_MasterI2C_init (I2C_7bit_addr, I2C_CLK_SMCLK, 40);
    				/*	configData = 0x04;
    					UCB0_I2C_write (0xa4, 0x80, &configData, 1);
    					configData=0x30;
    					UCB0_I2C_read (0xa5, 0x80, &configData, 1);
    
    					if(configData == 0x04)
    						P1OUT|=0x01;
    					else
    						 P4OUT|=BIT7;
    					//printf("Reading %c\n",configData);	*/
        		configData = 0xc3;
        		unsigned char data [2];
        		data[0]=0x10;
        		data[1]=0x10;
        		UCB0_I2C_write (0xa4, 0x40, data, 1);
        		configData=0xa5;
        	//	printf("write complete\n");
        		UCB0_I2C_read (0xa4, &configData,data,1);
        	//	printf(" config = %d\n",configData);
    
        		return 0;
    }
    

    /** 
     *	\page doc_page_placeholder Place title here
     *
     *  \section desc_sec Description
     *  Place description here 
     *
     *  \section intro_sec Introduction
     *  
     *	Describe this file
     *
     *
     * \section disclaimer_sec Disclaimer
     *
     * THIS PROGRAM IS PROVIDED "AS IS". TI MAKES NO WARRANTIES OR
     * REPRESENTATIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
     * INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
     * FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR
     * COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE.
     * TI DISCLAIMS ANY WARRANTY OF TITLE, QUIET ENJOYMENT, QUIET
     * POSSESSION, AND NON-INFRINGEMENT OF ANY THIRD PARTY
     * INTELLECTUAL PROPERTY RIGHTS WITH REGARD TO THE PROGRAM OR
     * YOUR USE OF THE PROGRAM.
     *
     * IN NO EVENT SHALL TI BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
     * CONSEQUENTIAL OR INDIRECT DAMAGES, HOWEVER CAUSED, ON ANY
     * THEORY OF LIABILITY AND WHETHER OR NOT TI HAS BEEN ADVISED
     * OF THE POSSIBILITY OF SUCH DAMAGES, ARISING IN ANY WAY OUT
     * OF THIS AGREEMENT, THE PROGRAM, OR YOUR USE OF THE PROGRAM.
     * EXCLUDED DAMAGES INCLUDE, BUT ARE NOT LIMITED TO, COST OF
     * REMOVAL OR REINSTALLATION, COMPUTER TIME, LABOR COSTS, LOSS
     * OF GOODWILL, LOSS OF PROFITS, LOSS OF SAVINGS, OR LOSS OF
     * USE OR INTERRUPTION OF BUSINESS. IN NO EVENT WILL TI'S
     * AGGREGATE LIABILITY UNDER THIS AGREEMENT OR ARISING OUT OF
     * YOUR USE OF THE PROGRAM EXCEED FIVE HUNDRED DOLLARS
     * (U.S.$500).
     *
     * Unless otherwise stated, the Program written and copyrighted
     * by Texas Instruments is distributed as "freeware".  You may,
     * only under TI's copyright in the Program, use and modify the
     * Program without any charge or restriction.  You may
     * distribute to third parties, provided that you transfer a
     * copy of this license to the third party and the third party
     * agrees to these terms by its first use of the Program. You
     * must reproduce the copyright notice and any other legend of
     * ownership on each copy or partial copy, of the Program.
     *
     * You acknowlege and agree that the Program contains
     * copyrighted material, trade secrets and other TI proprietary
     * information and is protected by copyright laws,
     * international copyright treaties, and trade secret laws, as
     * well as other intellectual property laws.  To protect TI's
     * rights in the Program, you agree not to decompile, reverse
     * engineer, disassemble or otherwise translate any object code
     * versions of the Program to a human-readable form.  You agree
     * that in no event will you alter, remove or destroy any
     * copyright notice included in the Program.  TI reserves all
     * rights not specifically granted under this license. Except
     * as specifically provided herein, nothing in this agreement
     * shall be construed as conferring by implication, estoppel,
     * or otherwise, upon you, any license or other right under any
     * TI patents, copyrights or trade secrets.
     *
     * You may not use the Program in non-TI devices.
     * 
     * The ECCN is EAR99. 
     * 
     */
    
    /** \file filename.h
     *
     *	@brief Describe File here
     *  @author Texas Instruments Inc.
     *	@date Aug 2012
     *	@version Version 0.1 - beta release
     *  @note Built with CCS Version 5.2.1.00018
    */
    #include "msp430f5529.h"
    #include "I2C.h"
    #include <stdio.h>
    
    /* ***************************************************************************
     * UCB0_MasterI2C_init
     *  Initialize the I2C module in Master mode
     *
     * \param addr_mode: 7/10-bit addressing mode (I2C_7bit_addr or I2C_10bit_addr)
     *        clock_src: Clock Source (I2C_CLK_UCLKI, I2C_CLK_ACLK, I2C_CLK_SMCLK)
     *        prescaler: I2C clock prescaler
     *
    */
    char UCB0_MasterI2C_init (unsigned char addr_mode, unsigned char clock_src, unsigned short prescaler)
    {
    	char comres = 0;
    
      	// Enable SW reset
      	UCB0CTL1 = UCSWRST;
      	
      	// I2C Single Master, synchronous mode, 7/10 bits
      	UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC + (addr_mode & (UCA10 | UCSLA10));
      	
      	 // Select Clock and hold SW reset 
      	UCB0CTL1 = (clock_src & UCSSEL_3) + UCSWRST;
      	
      	// set prescaler
      	UCB0BRW = prescaler;
      	
      	// Clear SW reset, resume operation
      	UCB0CTL1 &= ~UCSWRST;
      	
      	// Enable NACK interrupts
      	UCB0IE = UCNACKIE;
    
      	return(comres);
    }
    
    
    char UCB0_I2C_write(unsigned char slave_addr, short reg, unsigned char *data, unsigned char byteCount)
    {
    
    	unsigned char comres = 0;
    	//WAIT FOR PREVIOUS TRAFFIC TO CLEAR
    		while(UCB0STAT & UCBBUSY);
    
    	// LOAD THE DEVICE SLAVE ADDRESS
    		UCB0I2CSA = slave_addr;
    
    	// ENABLE TRANSMIT, GENERATE START BIT
    	UCB0CTL1 |= UCTR + UCTXSTT;
    
    	// NOW WAIT FOR START BIT TO COMPLETE
    	  	while(UCB0CTL1 & UCTXSTT);
    		
    
    	
    
    	// CHECK IF SLAVE ACK/NACK
    	  	if(UCB0IFG & UCNACKIFG)
    	  	{
    	  		// IF NACK, SET STOP BIT AND EXIT
    	  		UCB0CTL1 |= UCTXSTP;
    			return(USCI_I2C_STATUS_SLAVE_NACK);
    	  	}
    
      	
      	// LOAD THE REGISTER ADDRESS MSB
      	UCB0TXBUF = *data++;
    
    
       	// CHECK IF SLAVE ACK/NACK 	
      	if(UCB0IFG & UCNACKIFG)
      	{
      		// IF NACK, SET STOP BIT AND EXIT
      		UCB0CTL1 |= UCTXSTP;
    		return(USCI_I2C_STATUS_SLAVE_NACK);
      	}
      	// LOAD THE REGISTER ADDRESS LSB
      	  	UCB0TXBUF = *data++;
    
    
      	   	// CHECK IF SLAVE ACK/NACK
      	  	if(UCB0IFG & UCNACKIFG)
      	  	{
      	  		// IF NACK, SET STOP BIT AND EXIT
      	  		UCB0CTL1 |= UCTXSTP;
      			return(USCI_I2C_STATUS_SLAVE_NACK);
      	  	}
    
       	// NOW WRITE ONE OR MORE DATA BYTES
      	while(1)
      	{
      		/*
    	  	 // WAIT FOR NEXT INT AFTER REGISTER BYTE
    	  	while(!(UCB0IFG & UCTXIFG));
    	  	*/
    	  	
    	  	// IF NOT DATA TO FOLLOW, THEN WE ARE DONE
    	  	if(byteCount == 0 )
    	  	{
    	 		UCB0CTL1 |= UCTXSTP;
    			//UCB0IE &= ~UCTXIE;
    			return(comres);	
    	  	}
    	  	// IF MORE, SEND THE NEXT BYTE
    	  	else
    	  		UCB0TXBUF = reg;
    	  		byteCount--;
      	
      	}
    
    
    }
    char UCB0_I2C_read(unsigned char slave_addr,unsigned char *reg, unsigned char *data, unsigned char byteCount)
    {
    	unsigned char comres = 0;
    
    	//WAIT FOR PREVIOUS TRAFFIC TO CLEAR
    	while(UCB0STAT & UCBBUSY);
    		
    	// LOAD THE DEVICE SLAVE ADDRESS
    	UCB0I2CSA = slave_addr;
    
    	// ENABLE TRANSMIT, GENERATE START BIT                  
      	UCB0CTL1 |= UCTR + UCTXSTT;
      	while(UCB0CTL1 & UCTXSTT);
      	// CHECK IF SLAVE ACK/NACK
      	  	if(UCB0IFG & UCNACKIFG)
      	  	{
      	  		// IF NACK, SET STOP BIT AND EXIT
      	  		UCB0CTL1 |= UCTXSTP;
    
      			return(USCI_I2C_STATUS_SLAVE_NACK);
      	  	}
    
      	// LOAD THE REGISTER ADDRESS MSB
      	UCB0TXBUF = *data++;
    
      	
       	// CHECK IF SLAVE ACK/NACK 	
      	if(UCB0IFG & UCNACKIFG)
      	{
      		// IF NACK, SET STOP BIT AND EXIT
      		UCB0CTL1 |= UCTXSTP;
    
    		return(USCI_I2C_STATUS_SLAVE_NACK);
      	}
    
    
      	// LOAD THE REGISTER ADDRESS LSB
      	  	UCB0TXBUF = *data++;
    
    
      	   	// CHECK IF SLAVE ACK/NACK
      	  	if(UCB0IFG & UCNACKIFG)
      	  	{
      	  		// IF NACK, SET STOP BIT AND EXIT
      	  		UCB0CTL1 |= UCTXSTP;
    
      			return(USCI_I2C_STATUS_SLAVE_NACK);
      	  	}
    
    
    
      	// TURN OFF TRANSMIT (ENABLE RECEIVE)
       	UCB0CTL1 &= ~UCTR;
       	
       	// GENERATE (RE-)START BIT                  
      	UCB0CTL1 |= UCTXSTT;
      	
    
    
      	// WAIT FOR START BIT TO COMPLETE
      	while(UCB0CTL1 & UCTXSTT);
    
      	// CHECK IF SLAVE ACK/NACK
      	  	if(UCB0IFG & UCNACKIFG)
      	  	{
      	  		// IF NACK, SET STOP BIT AND EXIT
      	  		UCB0CTL1 |= UCTXSTP;
      			return(USCI_I2C_STATUS_SLAVE_NACK);
      	  	}
    
    
      	UCB0TXBUF = slave_addr+0x01;
    
      	// CHECK IF SLAVE ACK/NACK 	
      	if(UCB0IFG & UCNACKIFG)
      	{
      		// IF NACK, SET STOP BIT AND EXIT
      		UCB0CTL1 |= UCTXSTP;
    		return(USCI_I2C_STATUS_SLAVE_NACK);
      	}
      	
       	// NOW READ ONE OR MORE DATA BYTES
      	while(byteCount)
      	{
      		// IF READING 1 BYTE (OR LAST BYTE), GENERATE STOP BIT NOW TO MEET SPEC
      		if(byteCount-- == 1)
     			UCB0CTL1 |= UCTXSTP;
       			
      		 		
    	  	 // WAIT FOR NEXT RX INT
    	  	while(!(UCB0IFG & UCRXIFG));
    	  	
    	  	// READ THE BYTE
    	  	*reg = UCB0RXBUF;
    
      	}
      	//printf("data");
    	return(comres);
    }
    
    char UCB0_I2C_read_only(unsigned char slave_addr, unsigned char reg, unsigned char *data, unsigned char byteCount)
    {
    	unsigned char comres = 0;
    
    	//WAIT FOR PREVIOUS TRAFFIC TO CLEAR
    	while(UCB0STAT & UCBBUSY);
    		
    	// LOAD THE DEVICE SLAVE ADDRESS
    	UCB0I2CSA = slave_addr;
    	
       	// TURN OFF TRANSMIT (ENABLE RECEIVE)
       	UCB0CTL1 &= ~UCTR;
       	
       	// GENERATE START BIT                  
      	UCB0CTL1 |= UCTXSTT;
      	
      	// WAIT FOR START BIT TO COMPLETE
      	while(UCB0CTL1 & UCTXSTT);
      	
      	// CHECK IF SLAVE ACK/NACK 	
      	if(UCB0IFG & UCNACKIFG)
      	{
      		// IF NACK, SET STOP BIT AND EXIT
      		UCB0CTL1 |= UCTXSTP;
    		return(USCI_I2C_STATUS_SLAVE_NACK);
      	}
      	
       	// NOW READ ONE OR MORE DATA BYTES
      	while(byteCount)
      	{
      		// IF READING 1 BYTE (OR LAST BYTE), GENERATE STOP BIT NOW TO MEET SPEC
      		if(byteCount-- == 1)
     			UCB0CTL1 |= UCTXSTP;
       			
      		 		
    	  	 // WAIT FOR NEXT RX INT
    	  	while(!(UCB0IFG & UCRXIFG));
    	  	
    	  	// READ THE BYTE
    	  	*data++ = UCB0RXBUF;
      	}
      	//printf("%c",data);
    	return(comres);
    }
    

    2744.I2C.h

  • This is just an advice you don't have to care about. It's like "Smoking isn't good for your health!" and you answer "I know, but I want to do so!"

    It is just a hint that you can do it better. The ULP tells you that you could save some power if you were using a timer that runs in the background and go into a low power mode waiting for the timer to wake the MCU up again instead of wasting power doing nothing in an empty loop.

    Which infinite loop?

  • Dennis Eichmann said:
    It is just a hint that you can do it better.

    It’s more than just an advice. At least this ULP advice should be taken seriously. The empty delay loop might (will) be optimized away by the compiler when using higher optimization levels (like in release configuration) while it is there during debug. So while the code seems to work in debug mode, it will break when compiling release mode. Use __delay_cycles() for a ‘busy-waiting’ delay, if you don’t want to use timers. This might still trigger an ULP warning (as it is still energy-wasting busy-waiting) but at least it will behave consistently for different optimization levels.

**Attention** This is a public forum