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.

MSP430G2553 MCU I2C enabling problem

Other Parts Discussed in Thread: MSP430G2553

Hi All,

Can any one help me , i am new for MSP430 micro controller  presently i am working MSP430G2553 controller

my problem is  I2C  communication is not enabling, i saw the o/p in Pico Scope SCL and SDA pins are always low, i am attaching the my code, please help me  thanks advance.

#include "msp430g2553.h"

unsigned char TXData=0x55;
unsigned char TXByteCtr;

void I2c_init();
void I2c_trans();

void main(void)
{
     WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
      P1SEL |= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
      P1SEL2|= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
      UCB0CTL1 |= UCSWRST;                       // Enable SW reset
    I2c_init();
    while(1)
    {
    I2c_trans();
    }
}



void I2c_init()
{
  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 = 0x48;                         // Slave Address is 048h
  UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
  IE2 |= UCB0TXIE;                          // Enable TX interrupt

}                           // Holds TX data

void I2c_trans()
  {
    TXByteCtr = 1;                          // Load TX byte counter
    while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
    UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
    __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
                                            // Remain in LPM0 until all data
                                            // is TX'd
    }

//------------------------------------------------------------------------------
// The USCIAB0TX_ISR is structured such that it can be used to transmit any
// number of bytes by pre-loading TXByteCtr with the byte count.
//------------------------------------------------------------------------------
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
  if (TXByteCtr)                            // Check TX byte counter
  {
    UCB0TXBUF = TXData;                     // Load the 0x55 value in the buffer
    TXByteCtr--;                            // Decrement TX byte counter
  }
  else
  {
    UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
    IFG2 &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
    __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
  }
}

  • I2C ports are open collector ports. They can only pull the lines low or leave them alone. They canto pull them high. So you need external pullup resistors on SDA and SCL. 10k or even 4.7k are normally used (depending on line length and number of Slaves).

    Don't forget the common GND connection.

  • In many cases it’s already satisfying to just enable the internal Pull-Up, try it;

    P1REN |= BIT6 + BIT7;

    P1OUT |= BIT6 + BIT7;

  • Leo Bosch said:
    In many cases it’s already satisfying to just enable the internal Pull-Up, try it;

    On most MSPs, the internal pullups are disabled when the port is in output direction (to avoid cross-currents, as ports in output direction are usually push/pull).

    However, the internal pullups are too weak anyway for reliable I2C operation, especially for higher bus speeds above the 10kHz minimum.

  • Hi Jens-Michal,

    thanks for your replay,

    I put the pull up Resisters(10k), i will give the fixed 3.5V(DC) to pull up and also i  give the variable voltage (2v to 3.5v) to the pull up resisters SCL and SDA lines are always high only.

      MY controller  Board is EMULATION MSP-EXP430G2

  • Hi Leo Bosh,

    thanks for your replay,

    i change my code

    WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
         P1OUT |= BIT6 + BIT7;
          P1SEL |= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
          P1SEL2|= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
         P1REN |= BIT6 + BIT7;
          UCB0CTL1 |= UCSWRST;                       // Enable SW reset

    but it always SCL and SDA lines are  high only.  and  i put the pull up resisters (10k) and  i give the fixed 3.5V  DC voltage  and also i give the variable(2 to 3.5v) DC voltage ,i put the  pull up resister(4.5k)also.

  • What do you mean by "i give the fixed 3.5V  DC voltage  and also i give the variable(2 to 3.5v) DC voltage" ?

    mahdhu kommu1 said:
      UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
      UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset


    You should flip these two lines (first set UCSWRST before reconfiguring the mode),. But since it is set by power-on default anyway, it shouldn't make a difference here (only if you switch mode after already using the USCI). Or move the line in main that sets UCSWRST into the init function. Maybe even the port config.

    Another thing: when combining bits, please use the binary OR operator and not the arithmetic + operator. While the compiler accepts both, the outcome will be different when you have duplicate bits in your formula by accident (the '+' will give a completely undesired result and is difficult to track down)

    The flow of events in your code doesn't take care for the possibility that the slave doesn't answer (will stall then), but at least it should start with sending the start byte.
    Also, after the first run, GIE remains set. So when you set UCTXSTT next time, the ISR will be immediately called, before you actually enter LPM.

    I don't know why you see any activity on the pins. Is (for some reason) your TEST pin high? If so, P1.4 to P1.7 are in JTAG mode, which overrides all your software settings for these pins.

  • Hi Jens-Michael,


    Before going to set communication between two MCUs, I am trying to see I2C ( clock & data ) to make sure I2C pins are functioning properly, But i am not able to see. [i am using Single MCU]

    1.) fixed 3.5V  DC voltage
              Put  the connection  MCU VCC to  pullup resisters

    2.) the variable(2 to 3.5v) DC voltage"
     
              Put  the connection MCU VCC to POT(variable resister ) and POT O/P to pullup resisters.

    3.)  i was checked The TEST pin is High.
    Changes the code  with OR- operations, and put in main function but there is no changes in O/P.

          WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
         P1OUT |= BIT6 + BIT7;
          P1SEL |= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
          P1SEL2|= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
          P1REN |= BIT6 + BIT7;
          UCB0CTL1 |= UCSWRST;                       // Enable SW reset
          UCB0CTL0 |= UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
          UCB0CTL1 |= UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset



     4.)Debugging the code step by step data is storing in the Transmitting buffer(UCB0TXBUF), the Program was halting after executing the interrupt subroutine. at the statement of  TXByteCtr++;
     


    #include "msp430g2553.h"

    unsigned char TXData=0xA0;
    unsigned char TXByteCtr;

    void I2c_init();
    void I2c_trans();

    void main(void)

    {
         WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
         P1OUT |= BIT6 + BIT7;
          P1SEL |= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
          P1SEL2|= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
          P1REN |= BIT6 + BIT7;

          UCB0CTL1 |= UCSWRST;                       // Enable SW reset
          UCB0CTL0 |= UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
            UCB0CTL1 |= UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
        I2c_init();
        while(1)
        {
        I2c_trans();
        }
    }



    void I2c_init()
    {

      UCB0BR0 = 12;                             // fSCL = SMCLK/12 = ~100kHz
      UCB0BR1 = 0;
      UCB0I2CSA = 0xFE;                         // Slave Address is 048h
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      IE2 |= UCB0TXIE;                          // Enable TX interrupt

    }                           // Holds TX data

    void I2c_trans()
      {
        TXByteCtr = 1;                          // Load TX byte counter
        while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
        UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
        __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
                                                // Remain in LPM0 until all data
                                                // is TX'd
        TXByteCtr++;
        }

    //------------------------------------------------------------------------------
    // The USCIAB0TX_ISR is structured such that it can be used to transmit any
    // number of bytes by pre-loading TXByteCtr with the byte count.
    //------------------------------------------------------------------------------
    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
      if (TXByteCtr)                            // Check TX byte counter
      {
        UCB0TXBUF = TXData;                     // Load the 0x55 value in the buffer
        TXByteCtr--;                            // Decrement TX byte counter
      }
      else
      {
        UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
        IFG2 &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
        __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
      }
    }



  • I2C address range is 0x00-0x7F (7-bit), 0xFE is also illegal. The USCI will strip the MSB off and this gives 0x7E which is an reserved address. I’m not sure what the USCI will do with this, but better use a valid address.

    mahdhu kommu1 said:
    void I2c_trans()
      {
        TXByteCtr = 1;                          // Load TX byte counter
        while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
        UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
        __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
                                                // Remain in LPM0 until all data
                                                // is TX'd
        TXByteCtr++;
        }

    TXByteCtr++; is useless and confusing.

  • Leo Bosch said:
    I2C address range is 0x00-0x7F (7-bit), 0xFE is also illegal. The USCI will strip the MSB off and this gives 0x7E which is an reserved address.

    I wonder where this 0xfe comes from. even if you shift it right by one (the cure for the usual mistake of taking the start byte as slave address), the result would be 0x7f, within I2C address range but still reserved and no valid slave address.

  • From here:

    mahdhu kommu1 said:
    void I2c_init()
    {

      UCB0BR0 = 12;                             // fSCL = SMCLK/12 = ~100kHz
      UCB0BR1 = 0;
      UCB0I2CSA = 0xFE;                         // Slave Address is 048h
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      IE2 |= UCB0TXIE;                          // Enable TX interrupt

    }                           // Holds TX data

    And nobody is shifting the address. The USCI is ignoring bit-7, which gives 0x7E and not 0x7F!

  • Leo Bosch said:
    From here:

    You got me wrong. I meant where was the idea coming from that 0xfe should be used in this code. Datasheet or appnote or demo code or what else.

    Leo Bosch said:
    And nobody is shifting the address.

    I meant, even if assuming the usual mistake of writing a start byte and not the slave address into UCB0I2CSA, and manually shifting it right, it still wouldn't give a valid slave address. So this value doesn't make even the faintest sense.

  • Sorry for late reply, i am in leave

      thanks for your replying Leo , and finding the my mistake i change the Slave address

    UCB0I2CSA=0x52;

    But there is no change in output it  always showing (SCL & SDA Lines) high only.

  • mahdhu kommu1 said:
    But there is no change in output it  always showing (SCL & SDA Lines) high only.

    I don't see any further mistake in the code (doesn't mean there is none).
    So one thing that comes in mind is the TEST pin. If it is latched high for some reason, P1.6/7 are switched into JTAG mode, overriding your software settings.

  • mahdhu kommu1 said:
    But there is no change in output it  always showing (SCL & SDA Lines) high only

    I don’t know how you check the state of the SDA & SCL lines, but if you look in the debugger you will not see much.

    Use an oscilloscope or wire the two lines to another Port input (edge detect High->Low) and check the state of the Interrupt flags.

  • After weeks of frustrating lab work, I found that using msp430G2553 in I2C mode, you MUST NOT use/assign/enable the internal pullup resistors; doing so will somehow interfere with I2C mechanism; SCL & SDA lines remain HIGH.

    I have found NO documentation anywhere as to why, but I have tried three different chips from different date codes and production batches, and they all MIS-behave in the same way. Use EXTERNAL pull-ups only. IF anyone finds documentation about this, please reply & post

    I wrote a big COMMENT in my code so I will never forget about this again. VERY VERY painful.

    NOW - very cool I2C communications to Sensirion Temp / Humidity chip (SHT21) & to RTC clock calendar chip.

    Kind regards,

    Ray

  • On most MSPs, the pull-up resistor is automatically disabled when the port pin is set to output direction.
    On G2 family, it isn’t. However, the resistor values are much too high to be of any use for I2C operation, so it makes no sense enabling them, even though they are active when the pin is in output direction.

    There is indeed no hint that indicates any influence of the enabled resistor to the I2C operation (other than adding an additional load). Especially, the >30k pull-up cannot pull the pin high when the I2C output driver actively pulls the pin low with several mA driving capacity. But it will of course have a small influence on the signal shape, as it is an additional 100µA load.
    The only thing that would interfere with I2C operation (by disabling the output driver) would be using the comparator or ADC on this pin.

    So maybe you found a new silicon bug. Katie!

**Attention** This is a public forum