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.

MSP430g253 launchpad I2C Example

Other Parts Discussed in Thread: MSP430FG4618, MSP430G2553

Welp, I have reached that point again where I am confounded.  I would think that if I ran the example code msp430g2xx3_uscib0_i2c_03 that if I connected an oscilloscope on either P1.6 (SCL) or P1.7 (SDA), that I would see at least the slave address being pulsed out.  I have pulled these two lines up with 10k resistors to Vcc.  I would expect them to go low as the 430 as Master sends out the slave address.  But I don't seem to be able to see any activity on either line when I start msp430g2xx3_uscib0_i2c_03 or let it free run.

Granted, I have no DAC connected to the launchpad, but shouldn't the slave address get pushed out anyway?

Happy Thanksgiving,

Braden Fessler

  • You need a Storage Scoop or a time-out procedure to re-send, while the address will be transmitted only once and waits for an ACK.

  • Yes thanks.  But with no slave connected, I should at least see the slave address bits sent once, ie enough toggles to trigger the scope set for single sweep to capture it.  This single sweep capture works well on the uart TX line, to see physical activity.  I'll double check my P1.6 and P1.7 ports and try again.  I suppose I should just break down and get a real DAC to hook to my lanchpad.  So we think the example should toggle SDA and SCL once even though there is no slave connected?

  • Hello,

    I've got two opinion :

    1. The pull up resistor value is too large. This happens to me once when making my own G2553 board. I use 10K as the RESET pull up. The device cannot be programmed since the 10K won't let the RESET pin pulled down. I change it to 4K7 and the problem is solved. Maybe the same problem occurs on your I2C pins.

    2. The program stops when this line is called :

    UCB0CTL0 |= UCTR + UCTXSTT;

    This should cause START condition to be transmitted. But referring to the datasheet, The USCI will check if the bus is available or not before sending the START condition. Probably, because no I2C device is attached, the USCI acts as if no bus is available, thus no START condition or Slave Address whatsoever is sent.
    Other thoughts is that the TXBuffer could never be emptied since there is no device to receive it, thus no I2C command is sent.

    If you are using LaunchPad, you should try to Debug the program. Check wether the program is able to enter the TX ISR or not.

  • It should transmit the address at least once, even without slave and also it should toggles the SCL & SDA.

    But: I tried it on a MSP430G2 LaunchPad rev 1.4 with G2553, it doesn’t work. The module is frozen. It seems he is waiting for a bus-ready, but bus=ready (1K pull-up, 3.3V). UCTXSTT = high, UCBBUSY = low (should go high), UCSCLLOW = low (should alter).

    Maybe some experts could have a look.

    This is the (little bit modified) code;

    #include <msp430.h>
    
    const unsigned char Sine_Tab[] =            // 16 Point 16-bit Sine Table
    {
      0xFF,                                     // MSB Word 0
      0xFF,                                     // LSB
      0xF6,                                     // MSB Word 1
      0x40,                                     // LSB
      0xDA,                                     // MSB Word 2
      0x81,                                     // LSB
      0xB0,                                     // MSB Word 3
      0xFA,                                     // LSB
      0x7F,                                     // MSB Word 4
      0xFF,                                     // LSB
      0x4F,                                     // MSB Word 5
      0x03,                                     // LSB
      0x25,                                     // MSB Word 6
      0x7C,                                     // LSB
      0x09,                                     // MSB Word 7
      0xBD,                                     // LSB
      0x00,                                     // MSB Word 8
      0x00,                                     // LSB
      0x09,                                     // MSB Word 9
      0xBD,                                     // LSB
      0x25,                                     // MSB Word 10
      0x7C,                                     // LSB
      0x4F,                                     // MSB Word 11
      0x03,                                     // LSB
      0x7F,                                     // MSB Word 12
      0xFE,                                     // LSB
      0xB0,                                     // MSB Word 13
      0xFA,                                     // LSB
      0xDA,                                     // MSB Word 14
      0x81,                                     // LSB
      0xF6,                                     // MSB Word 15
      0x40                                      // LSB
    };
    
    int main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop Watchdog Timer 
    
      P1REN |= BIT6 + BIT7;
      P1OUT = BIT6 + BIT7;
    
      P1SEL |= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
      P1SEL2|= BIT6 + BIT7;                     // 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 = 0x4c;                         // Set slave address
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      IE2 |= UCB0TXIE;                          // Enable TX ready interrupt
      UCB0CTL1 |= UCTR + UCTXSTT;               // I2C TX, start condition
      UCB0TXBUF = 0x010;                        // Write DAC control byte
    
      __bis_SR_register(GIE);
    
      for (;;)
      {
    	if ((UCB0STAT & UCNACKIFG) != 0)
    	{
    		  UCB0CTL1 |= UCTR + UCTXSTT;               // I2C TX, start condition
    		  UCB0TXBUF = 0x010;                        // Write DAC control byte
    		  UCB0STAT = 0;
    	}
    
    	if ((UCB0STAT & UCSCLLOW) != 0)
    	{
    		__no_operation();
    	}
    
    	if ((UCB0STAT & UCBBUSY) != 0)
    	{
    		__no_operation();
    	}
    
      }
    
    //  __bis_SR_register(CPUOFF + GIE);          // Enter LPM0 w/ interrupts
    }
    
    // USCI_B0 Data ISR
    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
      static unsigned char ByteCtr;
    
      UCB0TXBUF = Sine_Tab[ByteCtr++];          // Transmit data byte
      ByteCtr &= 0x1f;                          // Do not exceed table
    }
    

  • Leo Bosch said:
    if ((UCB0STAT & UCNACKIFG) != 0) {
    UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
    UCB0TXBUF = 0x010; // Write DAC control byte

    Since GIE is set, the TX ISR is called immediately after setting UCTXSTT. Your write to TXBUF is then carried out, overwriting the unsent content of TXBUF. Well, it won't make much of a difference in this specific case, but the first table entry (or whatever would have been the current one) is skipped.

    Leo Bosch said:
    P1REN |= BIT6 + BIT7;

    The internal pull-ups aren't sufficient for I2C operation. On many MSPs, they are disabled anyway when the USCI sets the port pins to output direction. You should use external resistors.
    Leo Bosch said:
    P1OUT = BIT6 + BIT7;
    Controlled by the USCI anyway.

    What about the TEST pin? You won't get any I/O signal on P1.4 to P1.7 if TEST is high. The pins are in JTAG mode then.

  • Jens-Michael Gross said:

    if ((UCB0STAT & UCNACKIFG) != 0) {
    UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
    UCB0TXBUF = 0x010; // Write DAC control byte

    Since GIE is set, the TX ISR is called immediately after setting UCTXSTT. Your write to TXBUF is then carried out, overwriting the unsent content of TXBUF.

    [/quote]

    I add these Lines only for test to put a break point. To let the program running and to be sure the debugger is not halting the USCI clock. But it never reaches one of them as well as the ISR.

    Jens-Michael Gross said:
    P1REN |= BIT6 + BIT7;

    The internal pull-ups aren't sufficient for I2C operation. On many MSPs, they are disabled anyway when the USCI sets the port pins to output direction. You should use external resistors.[/quote]

    They are sufficient and working, there is no load. Whiteout this statement the bus-lines are low, with they are high. Anyhow a also add 1K (as I wrote earlier), no result.

    Jens-Michael Gross said:
    .
    P1OUT = BIT6 + BIT7;

    Controlled by the USCI anyway.[/quote]

    This is necessary to make the resistor pull-up, otherwise they would pull-down the bus. As digital output your right.

    Jens-Michael Gross said:
    What about the TEST pin? You won't get any I/O signal on P1.4 to P1.7 if TEST is high. The pins are in JTAG mode then.

    That’s a good point, I didn’t check this before. With the bare demo software, no resistor enabling, in emulation mode (the debugger pulses the test-pin low, probably to give it a change) it works (address byte only, but that’s expected). As soon I add REN, even with external resistors, no SDA or SCL, I can’t see why.

    And for Braden; 10K pull-up works O.k.

  • Hi Leo. In case you already haven't, can you try your I2C code without the jumper connecting P1.6 to LED2? When the clock pin P1.6 goes high, the LED tries to draw current (if jumper is present) resulting in pulling down the line because the pin is not able to source this current. I faced a similar issue in the past. Hope this helps. Regards, Shashank
  • Ah, forgot that one.

    The same issue with LEDs also occurred to me when configuring USCI as SPI interface.

  • No that was the first I see looking to the oscilloscope, but was already aware for such, using more EVM’s with LED’s on it.

    But finally it works, only I don’t understand why it’s not working when I enable the internal resistors.

    I’m using this many times (for laziness) as a quick test with other MSP’s without any problem, I know JMG doesn’t like it, on a final PCB release I always put external resistors, no doubt. The MSP430FG4618/F2013 Experimenter’s Board don’t have pull-up’s on board and it works great, and I did the same test now with a FR5969, only internal pull-up, and works great. So this problem looks only for G2553 (if it is a problem).

  • And to complete Braden’s question;

    Remove jumper J5-2 and don’t use internal resistors (REN), external pull-up of 10K is O.K.

    I alter the software a little, so it will continuously transmit the address in case there is no slave. Also I add a Positive oscilloscope trigger pulse so you can see the whole picture, available at J5-1 (green LED).

    int main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop Watchdog Timer 
    
      // P1.0 LED & Positive oscilloscope trigger pulse
      P1DIR = BIT0;
      P1OUT = 0;
    
      P1SEL |= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
      P1SEL2|= BIT6 + BIT7;                     // 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 = 0x4c;                         // Set slave address
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      IFG2 &= ~UCB0TXIFG;
      IE2 |= UCB0TXIE;                          // Enable TX ready interrupt
      UCB0I2CIE = UCNACKIE;
      P1OUT |= BIT0;
      UCB0CTL1 |= UCTR + UCTXSTT;	// I2C TX, start condition
      UCB0TXBUF = 0x010;	// Write DAC control byte
      P1OUT &= ~BIT0;
    
      __bis_SR_register(CPUOFF + GIE);          // Enter LPM0 w/ interrupts
    }
    
    #pragma vector = USCIAB0RX_VECTOR
    __interrupt void USCIAB0RX_ISR(void)
    {
    	if ((UCB0STAT & UCNACKIFG) != 0)
    	{
    	    __delay_cycles(50);
    		P1OUT |= BIT0;
    		UCB0CTL1 |= UCTXSTP + UCTXSTT;	// I2C stop & start condition
    		UCB0TXBUF = 0x010;	// Write DAC control byte
    		P1OUT &= ~BIT0;
    	}
    
    	UCB0STAT = 0;
    }
    
    // USCI_B0 Data ISR
    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
    	static unsigned char ByteCtr;
    
        __delay_cycles(50);
    	P1OUT |= BIT0;
    	UCB0TXBUF = Sine_Tab[ByteCtr++];          // Transmit data byte
    	ByteCtr &= 0x1f;                          // Do not exceed table
    	P1OUT &= ~BIT0;
    }
    

  • Leo Bosch said:
    I know JMG doesn’t like it,

    For a reason: not only are the internal pull-ups too weak, but on most MSPs, pull-ups are disabled when the pin goes into output direction. So when I2C 'outputs' a high, the pull-ups are deactivated when they are needed most.
    Check the port pin schematics!
    (btw, it was one of the first things I noticed when evaluating the 5438 four years ago, that I cannot use the internal pull-ups on I2C for these two reasons)

  • Jens-Michael Gross said:
    For a reason: not only are the internal pull-ups too weak

    Depends on bus-capacitance, less then ~5p no problem.

    Jens-Michael Gross said:
    So when I2C 'outputs' a high, the pull-ups are deactivated when they are needed most.

    They are not going into high-output mode but to float, and the resistors are not always disabled, it’s also possible when resistors are enabled output mode is disabled.

    Jens-Michael Gross said:
    Check the port pin schematics!

    Allways correct.

    Jens-Michael Gross said:
    (btw, it was one of the first things I noticed when evaluating the 5438 four years ago, that I cannot use the internal pull-ups on I2C for these two reasons)

    Experience with one device doesn’t mean that this applies to all other devices. TI is evaluation the schematics a lot and they can be between devices totally different. Must keep alert.

    But in this case with the G2553, looking to the schematic, I don’t see any reason that it’s not working with resistors enabled.

  • Leo Bosch said:
    Depends on bus-capacitance, less then ~5p no problem.

    And bus speed. What works for 10kHz won't for 400kHz. And people tend to always use the maximum by default. If you search the forum, you'll see many examples.
    It's like they are starting to learn how to play piano with the "Flight of the Bumblebee" at full speed.

    Note that the pin capacitance alone is 2pF. And a typical scope probe will typically have way more than 5pF :)

    Leo Bosch said:
    Experience with one device doesn’t mean that this applies to all other devices. TI is evaluation the schematics a lot and they can be between devices totally different. Must keep alert.

    Right. And each time I checked it in a different 5x family device, as well as with some 2x devices, I found that the direction signal is disabling the resistors when output direction is active. And except for the case of OC driving in I2C mode, this makes a lot of sense. If a pin is an output pin, a pull-up resistor is superfluous at best, and, if in opposite direction, it will just waste power.

    Leo Bosch said:
    But in this case with the G2553, looking to the schematic, I don’t see any reason that it’s not working with resistors enabled.

    With the 5438, I tested it (and yes, no pull-up effect when the USCI is sending I2C data to floating lines)
    But yes, the schematics show that it should work. Now I never made the test with a G2553, so I cannot say for sure.

    Leo Bosch said:
    Check the port pin schematics!

    Allways correct.[/quote]Always a good idea, but unfortunately not always correct :)
    The G2 schematics have proven very incomplete or wrong in the past. While most of the obvious bugs have been fixed now (like shortcuts or false/missing logic inversions), others may still exist and can only be found by experiments.

    Leo Bosch said:
    They are not going into high-output mode but to float,

    But also not to input direction. According to the documentation, the high-drive part of the output driver is disabled.
    In my I2C code, I was indeed switching between low-output an input (toggling the direction register rather than the output register bit). Here the pull-ups would work even on a 5x device. Besides being too weak for most real-world situations.

  • Jens-Michael Gross said:
    And bus speed.

    The pull-up resistor is defined by the rise-time only. But different bus-speed modes has different rise-time definitions. For the standard 100kbits/s this is 1uS which gives great flexibility up to 100p load, but for the 400/1,000kbits/s this is (just) 300/120nS people hoes wants to plays this piano should consider this limits, here a 10K resistor wouldn’t work, limits here are 4K for 400kbits/s and 2K for 1,000kbits/s with a load up to 100p.

    Jens-Michael Gross said:
    But also not to input direction.

    Input direction is always enabled, otherwise it could not read the bus state and not for example perform an arbitrage lost detection.

    I2C is the most simple bus but with complex possibilities which leads to a lot of long discussions.

  • Wow!!  Mr. Bosch and Mr. Gross, I really appreciate that dialog.  I was away for a couple days, and you guys really beat the bushes.  

    But weirdness persists, in a good way I guess.  I am not sure what did it, but I am now getting nice waveforms on both SCL and SDA on P1.6 and P1.7.  It is weird because I reseated all connections a couple times, I re-checked my scope by seeing the UART traffic on P1.1 and P1.2 while running a session on Putty and using my USB-Serial cable.

    In the  process of reviewing all this discussion, I did run a program through this same MSP430G2553 launchpad that had that statement 'REN' that Mr. Bosch mentioned.  Possibly it toggled some hidden flash config bit?

    I would like to post the picture of the scope trace, but can't figure out how to paste it in here.  Now in the capture, I can see the capacitance effects, the clock line safely makes it high in time for a SDA to change states, but it is still in a steep climb, only at about 80% of VCC.  The clock looks like a sawtooth.  Fun!

    So I apologize for causing such a ruckus, when I see that it could have been my own setup that was at fault.

     Anyway, thank you very much.

    Braden Fessler

    Anyone 

  • Save the picture as jpg and use the ‘Insert image’ button.

    Maybe for you JMG’s remark about probe capacitance applies, add a 1Meg series resistor to your probe.

    And; No need to apologize!

  • Yes well it turns out it iwas the LED on P1.6.  That is what it was.

    I went through it again and found it out.

    With Jumper J5-2 connected to LED2, the voltage at P1.6 goes to about 1.82v and stays there.  

    My bad.  

    With the jumper removed, I see the nice signature of the slave address on SDA, plus the [apparent] sawtooth clock on SCL.  [sawtooth possibly due to high capacitive probe on this scope I have, which is kind of nice, it plugs into my other USB port and displays a couple traces with maybe 10 MHz resolution.  Cheap probes came with it though.  

    Again, thank you for the discussion, it was very enlightening.

    Braden

    Thanks again.

  • Glad it worked out for you Braden. This had harassed me as well for days together till doing this simple thing solved my problem. Hence shared the same :)

    Regards,

    Shashank

  • Leo Bosch said:
    Input direction is always enabled,

    Sure, the input buffer is always working (not for all port pins under all circumstances, see ADC channel select signal on pins with analog input), but I was talking about the direction signal (that controls the output river - and the pull-up switch on many MSPs).

    Leo Bosch said:
    I2C is the most simple bus but with complex possibilities which leads to a lot of long discussions.

    I guess, SPI beats it in being the most simple bus - and yet there's often need for help for this one too.

    Also, USCI logic adds to complexity of I2C, due to the double-buffering etc. Good for maximum throughput, but bad for ease of use.

    Braden Fessler said:
    I would like to post the picture of the scope trace, but can't figure out how to paste it in here.

    There's an 'insert image' button on the editor toolbar. It accepts JPG image, but might require some adjustment of the max height and may width parameter - and has a total file size limit.

    Braden Fessler said:
    So I apologize for causing such a ruckus, when I see that it could have been my own setup that was at fault.

    You're not alone. Usually (except for few cases) all problems in this forum are 'own fault' this or that way. :)
    That's why the forum exists: to share expertise, figure out how to fix the own faults or profit from others who have did the same in the past. No need to apologize.

  • Thanks to Shashank and all.  Now that I can see the i2c transmissions on my scope, I debugged my little program for testing the physical SCL and SDA functionality.

    When I run the program, I see the slave address code output on the blue trace (SDA), but I am still  puzzled why the SCL line (in red below) is held  low  up to the point of the transmission.  Maybe this is normal.

    void i2cgo()                                                                              //test routine for i2c
    {
    P1OUT ^= 0x01;                                                                      // Toggle P1.0 using exclusive-OR
    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 = 0x90;                                       // slave address=9x,ADDR0=gnd:x=0
    UCB0CTL1 &= ~UCSWRST;                        // Clear SW reset, resume operation
    // IE2 |= UCB0TXIE;                                        // Enable TX ready interrupt
    UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
    UCB0TXBUF = 0x00;                                    // Write DAC control byte
    // while (!(UCB0TXIFG));                               //wait for buffer to empty
    // UCB0TXBUF = 0x80;                                 // Write DAC data MSB mid-scale for 6578
    // while (!(UCB0TXIFG));                               //wait for buffer to empty
    // UCB0TXBUF = 0x00;                                 // Write DAC data LSB
    }


    I am trying to figure out why my SCL line (red below) stays low.


  • It’s waiting for an ACK. If you add an interrupt on NACK and here send a STOP, CLK will go high and the USCI is ready for a new transfer. See my previous example how to do.

  • Braden Fessler said:
    I am trying to figure out why my SCL line (red below) stays low.

    You got a NACK (SDA high when SCL was going up for the 9th time). Now the USCI is waiting for your decision to either send a stop condition or a repeated start.

    BTW, the pull-up on SCL is way too weak, hence the slow rising time.  SCL doesn't even reach full height during a clock cycle. Maybe you get a NACK because the SCL signal is simply too distorted to be read properly by the slave.

**Attention** This is a public forum