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 plaguing me on MSP430

Other Parts Discussed in Thread: MSP430G2553, MSP430G2955

 I'm trying to get my MSP430g2553 to talk to a sensor via I2C. If anyone can spot-check the hardware in the picture below and see if there's a problem there, I'd be grateful. The resistors are connected to the red rail. Right now they're 2.2k, but I've also tried 8k and 10k.

Picture:  http://imgur.com/OTwArXa

The slave device is a PMU-6050 if you're interested.

Code is included.

#include <msp430g2553.h>
//#include "MPU6050.h"
#define MPU6050_RA_WHO_AM_I         0x75
#define MPU6050_DEFAULT_ADDRESS     0xD0

void init_I2C(void);
int i2c_notready(void);
char Receive(char);
void Transmit(char, char);


  // Pin 1.6 is SCL
  // Pin 1.7 is SDA
  // Slave address for MPU6050 is 0x68

int main(void)

{

         volatile char who_am_i;
         char gotit=0;

         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);
         if (who_am_i != 0x00)
           gotit=who_am_i;

         
   while(1){       }
}

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 = 12;                             // fSCL = 1Mhz/12 = ~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 (UCTXSTP auto clears after STOP is sent)
        UCB0CTL1 |= UCTR + UCTXSTT;             // I2C start condition with UCTR flag for transmit
        while((IFG2 & UCB0TXIFG) == 0);     //UCB0TXIFG is set immidiately (UCB0TXIFG is set to indicate TXBUF is ready for more data) 
        UCB0TXBUF = registerAddr;           //write registerAddr in TX buffer
        __delay_cycles(1000);
        
/***********************       
        if (UCB0STAT & UCNACKIFG)
        {
          UCB0CTL1 |= UCTR + UCTXSTT;             // I2C start condition with UCTR flag for transmit
          while((IFG2 & UCB0TXIFG) == 0);
          UCB0TXBUF = registerAddr;           //write registerAddr in TX buffer
          __delay_cycles(1000);
        }
************/
        
        
        while((IFG2 & UCB0TXIFG) == 0);     // STUCK HERE 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
}

And the code keeps getting snagged at the line indicated below. Pretty sure the slave isn't sending back an acknowledge signal:

  • You must not enable interrupts if you do not have the appropriate handler functions.

  • I commented out line 54, but that didn't change the results. Still, it's a good tip and I'll be more careful of that in the future!
  • Additionally, the GIE bit was never set to 1, so interrupts were never fully enabled.
  • The documentation on the use of UCTXNACK is a bit thin and I think it is supposed to be used only in slave mode. Setting UCTXSTP will cause a NACK to be generated before the stop but of course you have to set it before the character is received.

    So after setting waiting on the start condition flag (UCTXSTT), set UCTXSTP and then wait for the receive operation to complete before reading UCTXIFG.

    I haven't done quite what you are doing but it was close. I use a MPU-9150 with the msp430g2955 and used interrupts. As I recall, getting it to work was tricky.

  • Troubleshooting I've tried so far:

    Different MSP430's. Identical models, different units.

    With and without breadboard.

    With and without jumper cables. Currently have wires soldered into slave and inserted into female headers on Launchpad.

    Different resistor values (2k, 8k, 10k). Current slave's breakout board has built-in resistors.

    Many different sample programs. Variations include using interrupts, not using interrupts but relying on the built-in I2C functionality, and plain old bit-banging.

    Different slave devices. Here's where it gets interesting. What does work: I can make two MSP's talk over I2C. What's an MSP430 got that an accelerometer doesn't?
  • The MSP430 slave has working hardware, and the correct address. Either one might not be the case for the accelerometer.
  • Could be. I've tried two different accelerometers, and I've used a FOR loop to probe all addresses from 0x00 to 0x7F. No response from any of them.

    Both accelerometers are less than a week old. Different brands. If they're both broken, I'm probably the reason. If I were an expert I wouldn't be here begging for help, but after a couple of years of doing this I'm probably (emphasis on probably) not shorting things out. It's not a complicated circuit. I'm just thinking aloud...
  • According to the photograph, the sensor's logic I/O reference voltage is not connected and floating.
  • Hi David,

    I am trying to have the interrupt work on the MPU 9150 but the read operation within the ISR doesn't seem to send an acknowledgment to the slave. What configuration process did you use for the device?
  • The ACK is automatically generated (unless you set the bit to generate a NACK) before the interrupt.


    Which makes the interrupt driven code a little more complicated. The ISR must check to see if it is about to receive the last byte and then take steps to send a NACK if it is. If only one byte is expected for the entire read operation, this must of course be handled before the ISR gets called.

    If you never want to read more than one byte at a time, then the ISR probably isn't worth the effort.


  • void MPU9150_Handler(void) { //temporarily disable Interrupt NVIC_EN0_R &=~8; int read_imu_status=0; int acknowledge=0; //read status register read_imu_status=readData(0x3A); acknowledge=read_imu_status & 0x01; read_imu_status=readData(0x43)<<8 | readData(0x44);; //INTERRUPT CLEAR GPIO_PORTD_ICR_R |=0b01000000; flag_IMU=FLAG_IMU_Data_ready; //Re-enable Interrupt NVIC_EN0_R |= 8; } void configure_IMU(void) { //GPIO D configuration for interrupt pin SYSCTL_RCGC2_R |=0b00001000; GPIO_PORTD_DIR_R &=0b10111111; GPIO_PORTD_DEN_R |=0b01000000; GPIO_PORTD_AFSEL_R &=0b10111111; //GPIO_PORTF_DR2R_R |=0b00001000; GPIO_PORTD_IS_R &=0b10111111; GPIO_PORTD_IBE_R &=0b10111111; GPIO_PORTD_IEV_R |=0b01000000; //GPIO_PORTD_IM_R &=0b10111111; GPIO_PORTD_IM_R |=0b01000000; NVIC_EN0_R &=~8;//Temprarly disable Interrupt//will be Enabled outside of the function GPIO_PORTD_RIS_R |=0b01000000; //*********************************************Gyroscope and Accelerometer*********************************************** //Register 107 – Power Management 1//reset device write(0x6B, 0b10000000); //Register 107 – Power Management 1// turn sleep mode off write(0x6B, 0x00); //Register 25 – Sample Rate Divider//SMPLRT_DIV -- SMPLRT_DIV = 0 Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV) write(0x19, 0x00); //Register 26 – Configuration//default DLPF_CFG = 2 bandwidth is 94Hz for acc and 98HHz for gyro write(0x1A, 0x02); //Register 28 – Configure Accelerometer//(Full Scale = +/-2G) write(0x1C, 0x00<< 4); //Register 27 – Gyroscope Configuration//( FS_SEL: 0; Full Scale Range: ± 250 °/s; LSB Sensitivity: 131 LSB/°/s) write(0x1B, 0x00<< 4); //Register 35-FIFO enable //write(0x23, 0x01); //Register 55-Interrupt PIN write(0x37, 0x30); //Register 56-Interrupt Enable (select interrupt sources) write(0x38, 0x01); }


    My first function, shown above, is the ISR  and the second function is the configuration sequence I used to configure the 9150 as well as configuring the interrupt. I have also added the interrupt handler (for GPIO port D interrupt) in the startup.c file for the interrupt configuration.

    I have tested the GPIO interrupt at PORT D (positive edge triggered) using an LED and a switch and I observed the LED flashing when ever I fed a rising edge signal (positive edge), as expected. So this small experimentation probably confirms that I configured the interrupt correctly on the Tiva C but I am not sure if I configured the interrupt correctly on the slave device (mpu 9150).

    Im not really sure what is going on because the reading operation should automatically send the acknowledgment to the slave but instead the interrupt is not being acknowledged by the slave. Sometimes the I am able to enter the ISR once but I cant enter the ISR again (probably because the slave did not ack the interrupt) and other times the code gets stuck in the ISR. The device seems to hang and change its behavior like aforementioned.

    This MPU 9150/6050 is driving me crazy, especially with the vague datasheets. 

**Attention** This is a public forum