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.

My msp430f5529 i2c do not work

Other Parts Discussed in Thread: MSP430F5529

  Hey,I am going to use msp430f5529 to calculate quaternion form mpu6050.

  I write some codes to read some data form mpu6050.But it do not work, I write the codes after  reading  the examples form TI.I am sure there are some error in my  project,but i can find it. I am crazy now.

  Here is my code.

#include <msp430.h>
#include "msp430_i2c.h"
#include "mpu6050.h"
uchar I2CSendBuffer[2],I2CRecvBuffer;
int I2CSendPtr=0;
void I2C_Init(uchar SlaveAddress)
{
	  P3SEL |= 0x03;                            // Assign I2C pins to USCI_B0
	  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 = SMCLK/12 = ~100kHz
	  UCB0BR1 = 0;
	  UCB0I2CSA = SlaveAddr;                         // Slave Address 
	  UCB0CTL1 &= ~UCSWRST;
}
void I2CWriteInit()
{
    UCB0IE |= UCTXIE;                // enable Transmit ready interrupt
}
void I2CReadInit()
{
    UCB0IE |= UCRXIE;               // enable Receive ready interrupt
}

void I2C_Write(uchar address,uchar data)
{
	I2CSendPtr = 1;
	I2CSendBuffer[1] = address;
	I2CSendBuffer[0] = data;
	I2CWriteInit();
	while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
	UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
	__bis_SR_register(LPM0_bits + GIE);     // Enter LPM0 w/ interrupts

}

uchar I2C_Read(uchar address)
{

	 I2CSendBuffer[0] = address;
	 I2CSendPtr = 0;
	 I2CWriteInit();
	 while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
	 UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
	 __bis_SR_register(LPM0_bits + GIE);     // Enter LPM0 w/ interrupts
	 I2CReadInit();
	 UCB0CTL1 |= UCTXSTT;
	 while (UCB0CTL1 & UCTXSTT);
	 __bis_SR_register(LPM0_bits + GIE);     // Enter LPM0 w/ interrupts
	  while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
    return I2CRecvBuffer;
}
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
  switch(__even_in_range(UCB0IV,12))
  {
  case  0: break;                           // Vector  0: No interrupts
  case  2: break;                           // Vector  2: ALIFG
  case  4: break;                           // Vector  4: NACKIFG
  case  6: break;                           // Vector  6: STTIFG
  case  8: break;                           // Vector  8: STPIFG
  case 10: I2CRecvBuffer = UCB0RXBUF;                     // Get RX data
  __bic_SR_register_on_exit(LPM0_bits);   // Exit LPM0
  	  	   break;                          // Vector 10: RXIFG
  case 12:                                  // Vector 12: TXIFG
    if (I2CSendPtr)                          // Check TX byte counter
    {
      UCB0TXBUF = I2CSendBuffer[I2CSendPtr];                   // Load TX buffer
      I2CSendPtr--;                          // Decrement TX byte counter
    }
    else
    {
      UCB0TXBUF = I2CSendBuffer[I2CSendPtr];
      UCB0CTL1 |= UCTXSTP;                  // I2C stop condition
      UCB0IFG &= ~UCTXIFG;                  // Clear USCI_B0 TX int flag
      __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
    }
    break;
  default: break;
  }
}

  • You don’T need separate init functions for read and write. This can be done in the actual read or write function. Or, if the other code is written properly, the IE bits can be set right in the I2C_INIT function and remain on, as there are no interrupts without an active transfer.

    The RX ISR has a problem: it never sets TXSTP, so it keeps receiving data over and over again. Also, it is impossible to receive just one byte with interrupts. When the interrupt for first byte received is triggered, the second byte is already coming in. No way around it, as you need to set TXSTP before the last byte you want to receive has been fully received.

    Are you sure the SDA and SCL pins are P3.0 and P3.1?

    Do you have an external pull-up of 10k or less to VCC on both lines? Do the MSP and the sensor have a common GND connection?

    Is the slave address correct? (It is a 7-bit address, not containing the R/W bit)

    The send logic is wrong. Your code writes the last byte to TXBUF and then immediately sets TXSTP. Which will prevent the just written byte form being sent because (apart from the very first byte) the TX interrupt is called when the previous byte starts sending,. So you stop after the byte that is sending right now, not after the one you just wrote to TXBUF.
    You need to set I2CSendPtr (should be named a counter, not a pointer) to 2 (two bytes to send), and in TX ISR, after checking it for being zero, decrement it first, and then write  from buffer to TXBUF. When it is already zero at the beginning of the ISR, no data is there to send and you just set TXSTP (don’t write to TXBUF).
    Setting TXSTP, as well as writing to TXBUF, will clear TXIFG, so no need to do it manually. Actually, reading UCB0IFG has already cleared TXIFG :)

**Attention** This is a public forum