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.

BMP180 I2C - MSP430 Not Storing Second Data Byte

Other Parts Discussed in Thread: MSP430F5529

I am using the MSP430F5529 Launchpad with the SensorHub Boosterpack. I am just trying to get the I2C working with the BMP180.

When I hook up the oscilloscope I can see that the MSP430 is properly addressing the BMP180 and receiving data. Unfortunately I am only able to store the most significant bit into my variable.  I have a second variable for storing the least significant bit but nothing gets stored into here, even though I see both bits being sent on the oscilloscope.

In my code I have a loop that waits for the RX buffer flag to be set, then I place the RXBUFF data into my variable. Then I immediately check again to see if the RX flag is set, which then stored the least significant bit into the other variable. I guess I am not 100% sure I understand how the RX flag is set. I am assuming it is set immediately after a new byte is sent.

Here is my code:

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


/***************************************************************************/
// Includes and defines
#include <msp430.h>

#define MSP430F5529_USCIB0_ADDR 0x05E0
#define BMP180_ADDR 0x77

void initI2C(void);
void Setup_TX(void);
void i2c_start(void);
void i2c_stop(void);


/***************************************************************************/
// Main
int main(void){

	int i = 0;
	int cmd = 0xAA;
	int MSB = 0;
	int LSB = 0;

    WDTCTL = WDTPW + WDTHOLD;	// Stop watchdog timer

	initI2C();

    while(1){

        Setup_TX();
        i2c_start();

        if(UCB0IFG & UCTXIFG){
            UCB0TXBUF = cmd;
        }

        for (i=0; i<1000; i++) {
        	if (UCB0IFG & UCTXIFG){
        		break;
        	}
        }
        // Data was not sent, return
        if (i == 1000) {
        	return -1;
        }

        UCB0CTL1 &= ~UCTR;	// Switch to receive mode
        i2c_start();		// Restart

    	// Wait to receive data in RX buffer
    	for (i = 0; i < 1000; i++){

    		// Get data if RXIFG is set
    		// RXIFG is set when buffer has received a byte
			if (UCB0IFG & UCRXIFG){
				MSB = UCB0RXBUF;		// Get byte from RX buffer
				UCB0IFG &= ~UCRXIFG;	// Set RXIFG to 0
				break;
			}
			if (UCB0IFG & UCRXIFG){
				LSB = UCB0RXBUF;		// Get byte from RX buffer
				UCB0IFG &= ~UCRXIFG;	// Set RXIFG to 0
				break;
			}
    	}

        i2c_stop();

        // Clear USCI_B0 TX int flag
        UCB0IFG &= ~UCTXIFG;
    }
}


/***************************************************************************/
//
void initI2C(void){
	P3DIR |= BIT0 + BIT1;	// Set SDA and SCL as outputs
	P3OUT &= ~BIT0;			// Write 0 to SDA
	P3SEL |= BIT0 + BIT1;	// Assign I2C pins to USCI_B0
}


/***************************************************************************/
//
void Setup_TX(void){

    int i;

    // Ensure stop condition got sent
    for (i = 0; i < 1000; i++) {
    	if ((UCB0CTL1 & UCTXSTP) == 0)
    		break;
    }

    // Enable SW reset
    UCB0CTL1 |= UCSWRST;

    // I2C Master, synchronous mode
    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;

    // Use SMCLK, keep SW reset
    UCB0CTL1 = UCTR + UCSSEL_2 + UCSWRST;

    // fSCL = SMCLK/12 = ~100kHz
    UCB0BR0 = 12;
    UCB0BR1 = 0;

    UCB0I2COA = MSP430F5529_USCIB0_ADDR;	// MSP430 addr
    UCB0I2CSA = BMP180_ADDR;				// BMP180 addr

    // Clear SW reset, resume operation
    UCB0CTL1 &= ~UCSWRST;
}


/***************************************************************************/
//
void i2c_start(void){
    UCB0CTL1 |= UCTXSTT;
}


/***************************************************************************/
//
void i2c_stop(void){

	int i;

	// I2C stop condition
	UCB0CTL1 |= UCTXSTP;

	// Ensure stop condition got sent
    for (i=0; i<1000; i++) {
    	if ((UCB0CTL1 & UCTXSTP) == 0)
    		break;
    }

    P1OUT |= BIT0;
}

  • I apologize, I forgot to ask a question! My question is, how does the RX flag work and what in my code must I change to allow me to store the second byte.
  • The break; aborts the receiving loop after the first byte.

    Furthermore, the same flag is set for all received bytes, so you must use your own counter to determine how many bytes have been received; something like this:

    byte buffer[2];
    int received = 0;
    
    while (received < 2) {
        while (!(UCB0IFF & UCRXIFG))
            ;
        buffer[received++] = UCB0RXBUF;
    }

    You also need to check for errors like missing ACK after each byte.

  • I am still confused as to how the RX flag works. The datasheet says it is set when the RX buffer has received a "complete character". In my code I am assuming that the RX flag goes up on the first byte, I read out that first byte, set the RX flag down. Then the RX flag goes up again for the second byte, and I need to read that second byte and set the flag down again.

    Is this correct behavior?
  • Your description of the RX behaviour is basically correct. However, see section 36.3.7.2 of the User's Guide:

    UCRXIFG is automatically reset when UCxRXBUF is read.

    The problem was only wrong logic in the code.

    Check out the F5529 example code, or the driverlib source.

  • The USCI works byte-oriented. A 'complete character' is 8 data bits (or maybe 7 in UART mode) and (again in UART mode) start and stop and maybe parity bits. RXIFG is set when a new byte has arrived, and is cleared when you read RXBUF, reset the USCI or manually clear it.
    Whether a received byte is part of a 16 bit value or a 32 bit value or a text string or whatever, is up to you to interpret.

    Hint:
    for (i=0; i<1000; i++) {
    if (UCB0IFG & UCTXIFG){
    break;
    }
    }
    can be better written as
    for(i=0; (i<1000) && !(UCB0IFG&UCTXIFG); i++);

**Attention** This is a public forum