2

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 can`t 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);
int i2c_notready(void);
char Receive(char);
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);

         who_am_i = Receive(MPU6050_RA_WHO_AM_I);

         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;
          UCB0I2CSA = MPU6050_DEFAULT_ADDRESS;
          UCB0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
          IE2 |= UCB0RXIE + UCB0TXIE;    // Enable RX and TX interrupt
}


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


char Receive(char registerAddr){
        char receivedByte;
        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
        UCB0TXBUF = registerAddr;           //write registerAddr in TX buffer
        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?
        receivedByte = UCB0RXBUF;
        UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
        return receivedByte;
}


void Transmit(char registerAddr, char data){
    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
    UCB0TXBUF = registerAddr;               //write registerAddr in TX buffer
    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.

Nilo nilold
  • 23
  • 1
  • 3
  • 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 01:14
  • Why are you enabling the interrupts? Any why the NACK? – CL. Mar 19 '15 at 09: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](http://www.nxp.com/documents/user_manual/UM10204.pdf). I´m pretty sure I will have to suppress it when I´m reading the accel and gyro datas, as they`re composed of 2 bytes. The interrupt is not necessary, indeed. – Nilo nilold Mar 24 '15 at 16:19

2 Answers2

1

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?

try adding a:

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

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

Some Hardware Guy
  • 15,815
  • 1
  • 31
  • 44
0

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){
    int8_t receivedByte;
    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
    UCB0TXBUF = registerAddr;           //write registerAddr in TX buffer
    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(UCB0RXIFG != (IFG2 & UCB0RXIFG)); //keep checking for recv ready flag
    receivedByte = UCB0RXBUF;
    return receivedByte;

}