Reading MPU-6050 with MSP430g2553 using I2C

I´ve been searching for libraries or documentations for helping me reading from and writing to the acell + gyro breakout MPU-6050 from InvenSense. I managed to read it with the arduino's libraries made by Jeff Rowberg (Link), but now I want to use the TI MSP430g2553 (with the CCS or IAR). I intend to make a good library and some examples in order to share it, since I cant find it as easily as I found for Arduino and PIC.

The code I have so far seems to work, but I cant be certain. The most basic test is to read the WHO_AM_I register, which returns the slave address (0x68). The code I used is based on this topic, which is based on a TI documentation.

My code is very simple:

Includes:

#include <msp430g2553.h>
#include "MPU6050.h"


Prototypes:

void init_I2C(void);
void Transmit(char, char);


Main:

int main(void) {

volatile char who_am_i;
char test;

WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1Mhz
DCOCTL = CALDCO_1MHZ;
P1SEL |= BIT6 + BIT7;       // Assign I2C pins to USCI_B0
P1SEL2 |= BIT6 + BIT7;       // Assign I2C pins to USCI_B0

init_I2C();    // initialize i2c
__delay_cycles(10000);

while ( i2c_notready() );       // wait for bus to be free
__delay_cycles(10000);

while(1) {}
}


Functions:

void init_I2C(void) {
UCB0CTL1 |= UCSWRST;                      // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
UCB0BR0 = 10;                             // fSCL = 1Mhz/10 = ~100kHz
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
IE2 |= UCB0RXIE + UCB0TXIE;    // Enable RX and TX interrupt
}

if(UCB0STAT & UCBBUSY) return 1;
else return 0;
}

while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT;             // I2C start condition with UCTR flag for transmit
while((IFG2 & UCB0TXIFG) == 0);     //UCB0TXIFG is set immidiately
while((IFG2 & UCB0TXIFG) == 0);     // wait until TX buffer is empty and transmitted
UCB0CTL1 &= ~UCTR ;                // Clear I2C TX flag for receive
UCB0CTL1 |= UCTXSTT + UCTXNACK;    // I2C start condition with NACK for single byte reading
while (UCB0CTL1 & UCTXSTT);             // Start condition sent? RXBuffer full?
UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
}

while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT;             // I2C start condition with UCTR flag for transmit
while((IFG2 & UCB0TXIFG) == 0);         //UCB0TXIFG is set immidiately
while((IFG2 & UCB0TXIFG) == 0);         // wait until TX buffer is empty and transmitted
UCB0TXBUF = data;                       //Write data in register
while((IFG2 & UCB0TXIFG) == 0);         // wait until TX buffer is empty and transmitted
UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
IFG2 &= ~UCB0TXIFG;                     // Clear TX interrupt flag
}


The problem is: I can only get the data if I try to read twice. That is, I can only get the register value if I write the line

         who_am_i = Receive(MPU6050_RA_WHO_AM_I);


twice. (And I do get the expected value).

It may be silly, but I think this is happening becouse I misunderstood something that could lead to total misfunction of the complete code. Therefore I would like to solve or understand this problem before geting any further on my Code. Thank you very much.

• What do you actually receive? Could you paste your actual results? How many bytes is the data you're trying to read? – scld Mar 19 '15 at 1:14
• Why are you enabling the interrupts? Any why the NACK? – CL. Mar 19 '15 at 9:12
• I´m trying to read a single byte data and I receive 0x00 when the error occurs and 0x68 (which is the expected value) when it was successful. The Answer from @SomeHardwareGuy solved the problem. – Nilo nilold Mar 24 '15 at 16:15
• @CL, the NACK is sent to inform the slave device that the master doesn´t want further bytes, as described at the end of the 10th page of this document. I´m pretty sure I will have to suppress it when I´m reading the accel and gyro datas, as theyre composed of 2 bytes. The interrupt is not necessary, indeed. – Nilo nilold Mar 24 '15 at 16:19

You might not be waiting properly for the rx buffer to fill. In your Receive function, after your line:

while (UCB0CTL1 & UCTXSTT);             // Start condition sent? RXBuffer full?


while(UCB0RXIFG != (IFG2 & UCB0RXIFG)); //keep checking for recv ready flag


Or some variation of that, and see if it helps.

Another addition. Even if you apply the fix suggested by @SomeHardwareGuy, you will read the previous buffer value if you read continuously. The buffer should be read after stop condition is applied. The correct sequence is as follows:

    uint8_t Receive(uint8_t registerAddr){
while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT;             // I2C start condition with UCTR flag for transmit
while((IFG2 & UCB0TXIFG) == 0);     //UCB0TXIFG is set immidiately