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.

CCS/MSP430F5529: Problems with I2C Master

Part Number: MSP430F5529

Tool/software: Code Composer Studio

Hi everyone

I have a board which communicates with a Sensor but I want to use the MSP430F5529 instead of the board. I am communicating via I2C between the MSP430 (Master) and the Sensor (Slave). I have written the code for the Master, which does not work fully.

This is how it should work with delays between the transactions. The first delay is about 15us and the second one about 60us. SMCLK is 200kHz.

The Master first sends a Start condition, then the Register Adress(0). After this, he makes a Restart and the Slave transmits the Data(15).

This is how it is at the moment. The problem is that there are no delays between the transactions so the slave can't transmitt the Data. The Master always receives a '0' instead of '15'.   

Here is my Code:

int main(void)

{

WDTCTL = WDTPW + WDTHOLD; // Stop WDT

P3SEL |= 0x03; // Assign I2C pins to USCI_B0

P8DIR |= BIT1; // Set P8.1 to output direction

P8OUT |= BIT1;

for(x=100;x>0;x--);

UCB0CTL1 |= UCSWRST; // Enable SW reset

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

UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK

UCB0BR0 = 6; // fSCL = SMCLK/6 = ~200kHz

UCB0BR1 = 0;

UCB0I2CSA = 0x55; // Slave Address is 055h

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

UCB0IE |= UCRXIE; // Enable RX interrupt

 

UCB0CTL1 |= UCTR+UCTXSTT; // I2C start condition, write

while (!(UCB0CTL1 & UCTXSTT)); // Ensure start condition got sent

while (!(UCB0IFG & UCTXIFG)); // wait until data can be written

UCB0IFG &= ~UCTXIFG; // reset Tx interrupt flag

UCB0TXBUF = 0x00; // transmit data

while (!(UCB0IFG & UCTXIFG)); // wait until data can be written

UCB0IFG &= ~UCTXIFG; // reset Tx interrupt flag

UCB0CTL1 &= ~UCTR; // set receiver mode

UCB0CTL1 |= UCTXSTT; // send restart

while(UCB0CTL1 & UCTXSTT); // wait until start condition reset

UCB0IFG &= ~UCRXIFG; // reset Rx interrupt flag

while(!(UCB0IFG & UCRXIFG)); // wait until Receive flag is reset

__no_operation(); // For debugger

}

// USCI_B0 Data ISR

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)

#pragma vector = USCI_B0_VECTOR

__interrupt void USCI_B0_ISR(void)

#elif defined(__GNUC__)

void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)

#else

#error Compiler not supported!

#endif

{

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: // Vector 10: RXIFG

RXData = UCB0RXBUF; // Get RX data

break;

case 12: break; // Vector 12: TXIFG

default: break;

}

}

Does anybody know what I am doing wrong or how I can fix this?

 

Thanks for Help

Fabian

  • Hi Fabian,

    Please re-post your images as they did not attach correctly. Your code should not be manually changing the IFGs, these are addressed through manipulating the corresponding buffer registers. You also never enable global interrupts so your ISR is never accessed, you can confirm this through use of your IDE's debugger. I suggest revisiting the MSP430F55xx I2C code examples provided by TI.

    Regards,
    Ryan
  • Hi Ryan

    I don't use the interrupt function at the moment.

    Here are the images

    When I use  the demoboard with the sensor it looks like this with delays between the bytes. The first delay is about 15us and the second one about 60us. The Master first sends a Start condition with slave address, then the Register Address(0). After this, he makes a Restart with slave address and the Slave transmits the Data(15).

    This is how it looks at the moment with the MSP430. I think the problem is that there are no delays between the bytes so the slave can't transmit the Data. Is it normally that there are delays between the bytes and how can i do them? The Master always receives a '0' instead of '15'.   

    Once I set a breakpoint after the Master sent the start condition with the slave address and the Master received to correct Data('15'). That's why I think the delays are the problem.

    Here is my code:

    #include <msp430.h>
    
    unsigned char RXData;
    int x;
    
    int main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
      P3SEL |= 0x03;                                                // Assign I2C pins to USCI_B0
      P8DIR |= BIT1;                                                 // Set P8.1 to output direction
      P8OUT |= BIT1;
      for(x=100;x>0;x--);
      UCB0CTL1 |= UCSWRST;                                          // Enable SW reset
      UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
      UCB0CTL1 = UCSSEL_2 + UCSWRST;                    // Use SMCLK
      UCB0BR0 = 6;                                                             // fSCL = SMCLK/6 = ~200kHz
      UCB0BR1 = 0;
      UCB0I2CSA = 0x55;                                                   // Slave Address is 055h
    
      UCB0CTL1 &= ~UCSWRST;                                     // Clear SW reset, resume operation
      UCB0IE |= UCTXIE;                                                   // Enable TX interrupt
      UCB0IE |= UCRXIE;                                                   // Enable RX interrupt
    
    
      UCB0CTL1 |= UCTR+UCTXSTT;			             // I2C start condition, write
      while (!(UCB0CTL1 & UCTXSTT));                           // Ensure start condition got sent
    
      while (!(UCB0IFG & UCTXIFG)); 		                    // wait until data can be written
      UCB0TXBUF = 0x00;				                    // transmit data
    
      while (!(UCB0IFG & UCTXIFG)); 		                    // wait until data can be written
      UCB0CTL1 &= ~UCTR; 				           // set receiver mode
      UCB0CTL1 |= UCTXSTT; 				           // send restart
    
      while(UCB0CTL1 & UCTXSTT); 		                  // wait until start condition reset
      while(!(UCB0IFG & UCRXIFG));		                  // wait until Receive flag is reset
    
        __no_operation();                                                 // For debugger
    }
    
    // USCI_B0 Data ISR
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = USCI_B0_VECTOR
    __interrupt void USCI_B0_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
      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:  				     // Vector 10: RXIFG
    	RXData = UCB0RXBUF;     // Get RX data
        break;
      case 12: break;                           // Vector 12: TXIFG
      default: break;
      }
    }

    Thanks for your help

    Fabian

  • In theory, I²C does not need any pauses between bytes (if the slave needs more time, it can do clock stretching).

    But why are you using 200 kHz? Does the slave actually support more than 100 kHz? Try using even less.
  • Slave supports up to 400kHz, but I will try it with clock stretching
  • This is not what clock stretching means; the slave would automatically use it if it supported it.

    You could try to add __delay_cycles(...) after the wait loops in your code.

  • So I misunderstood this. Thanks for this.

    But there is an other problem. If I add a delay_cycle it appears not at the end of the Acknowledgement. It appears between the Byte and the Acknowledgement.

    So do I have to do a query if I have already received the Acknowledgement or what can I do?

  • Well, the USCI module conforms to the I²C specification. If you want to do something does goes beyond that, you'd have to write your own I²C implementation using bit banging.

    (I'm not sure if the problem actually is the delays, but that's impossible to debug without knowing anything about the slave device.)
  • Before sending the restart instruction, you can use a UCBUSY while loop to confirm that the master is done transmitting. This way the __delay_cycles function will appear at the proper time during the communication sequence.

    You should put a forever while loop at the end of your code so that it doesn't complete main, that way you are not dependent on the debugger to halt at a breakpoint.

    Regards,
    Ryan

  • The sensor is MMA8491Q from freescal
  • The MMA8491Q does not require any delays.

    This looks like a perfectly valid read transaction. Did you actually go into active mode by sending a rising edge on EN after the last measurement?
  • This is the result, when I add the UCBUSY while loop. The Master transmits the Register adress ('0') but I don't do a Stop. The UCBUSY is only cleared after a Stop.

    Here is the part of the code that I have changed:

      UCB0CTL1 |= UCTR+UCTXSTT;				// I2C start condition, write
      while (!(UCB0CTL1 & UCTXSTT));                      // Ensure start condition got sent
    
      while (!(UCB0IFG & UCTXIFG)); 			        // wait until data can be written
      UCB0TXBUF = 0x00;						// transmit data
    
      while (!(UCB0IFG & UCTXIFG)); 			        // wait until data can be written
      while (UCB0STAT & UCBBUSY);				// wait until bus isn't busy
      UCB0CTL1 &= ~UCTR; 					// set receiver mode
      UCB0CTL1 |= UCTXSTT; 					// send restart
    
    
      while(UCB0CTL1 & UCTXSTT); 				// wait until start condition reset
      while(!(UCB0IFG & UCRXIFG));				// wait until Receive flag is reset
    
        __no_operation();                                               // For debugger
        while(1);

    To Clemens Ladisch:

    There is a rising edge on EN 1ms befor the Master sends the first Start condition and the EN remains high to the end.

  • I guess "first start" means "every start, but not the re-start"?

  • No only one time.

  • My mistake Fabian, I forgot that UCBUSY mainly applies to SPI and UART as compared to I2C. Have you tried using interrupts instead of polling? There are several examples provided by TI that would be worth trying to at least see if this alters the issue's behavior.

    Regards,
    Ryan
  • I solved the problem.
    The only thing I needed was more time between the EN High an the start condition as in the picture above. But thanks for your help guys.

**Attention** This is a public forum