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.

Question about I2C

Other Parts Discussed in Thread: MSP430G2553, TLC59116

Hello, I'm having a similar problem here. But the solution does not reside on the address (unfortunately).
I'm trying to interface a TLC59116 with a MSP430G2553.
Here's my code:

//******************************************************************************
//  Program Name - Short Description
//
//  Description:
//
//                                /|\  /|\
//                  TLC59116      10k  10k     MSP430G2xx3
//                   slave         |    |        master
//             -----------------   |    |  -----------------
//            |          P27/SDA|<-|----+->|P1.7/UCB0SDA  XIN|-
//            |                 |  |       |                 |
//            |                 |  |       |             XOUT|-
//            |          P26/SCL|<-+------>|P1.6/UCB0SCL     |
//            |                 |          |                 |
//
//  xxxx
//  xxxx
//  June 2013
//  Built with CCS Version 5.3.0
//******************************************************************************
#include <msp430.h>
#include <stdint.h>
#define TLC59116_ADR 0xD0 // this is the allcall address
#define MODE1 0x00
#define MODE2 0x01
#define PWM0 0x02
#define PWM1 0x03
#define PWM2 0x04
#define PWM3 0x05
#define PWM4 0x06
#define PWM5 0x07
#define PWM6 0x08
#define PWM7 0x09
#define PWM8 0x0A
#define PWM9 0x0B
#define PWM10 0x0C
#define PWM11 0x0D
#define PWM12 0x0E
#define PWM13 0x0F
#define PWM14 0x10
#define PWM15 0x11
#define GRPPWM 0x12
#define GRPFREQ 0x13
#define LEDOUT0 0x14
#define LEDOUT1 0x15
#define LEDOUT2 0x16
#define LEDOUT3 0x17
#define SUBADR1 0x18
#define SUBADR2 0x19
#define SUBADR3 0x1A
#define ALLCALLADR 0x1B
#define IREF 0x1C
#define EFLAG1 0x1D
#define EFLAG2 0x1E
unsigned char *PTxData;                     // Pointer to TX data
unsigned char TXByteCtr;
unsigned char TxDataBuff[] = {0x00, 0x00, 0x00, 0x00};
void init_I2C(void);
void init_TCL59116(void);
void i2c_write(unsigned char reg, unsigned char val);
int 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
init_I2C();
init_TCL59116();
i2c_write(LEDOUT0,0x02);
__bis_SR_register(LPM0 + GIE); // LPM0 with interrupts enabled
}
void i2c_stop(void)
{
while (UCB0CTL1 & UCTXSTP);
}
void i2c_start(void)
{
UCB0CTL1 |= UCTR + UCTXSTT;
}
void i2c_write(unsigned char reg, unsigned char val)
{
    i2c_stop();
TxDataBuff[0] = reg;
TxDataBuff[1] = val;
PTxData = TxDataBuff;
TXByteCtr = 2;
i2c_start();
__bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
}
void init_TCL59116(void)
{
i2c_write(MODE1,0x01);
i2c_write(MODE2,0x01);
i2c_write(PWM0,0xFF);
i2c_write(IREF,0x00);
i2c_write(MODE1,0x01);
i2c_write(MODE1,0x01);
i2c_write(MODE1,0x01);
}
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 = 120;                             // fSCL = SMCLK/120 = ~ very slow :)
  UCB0BR1 = 0;
  UCB0I2CSA = TLC59116_ADR;                // Slave Address
  UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
  IE2 |= UCB0TXIE;                          // Enable TX interrupt
}
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
  if (TXByteCtr)                            // Check TX byte counter
  {
    UCB0TXBUF = *PTxData++;                 // Load TX 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
  }
}


It gets stuck after the first i2c_start() call. 
This is what I see when the I2C cable is connected to the TLC59116 board.

And this is what I see when the cable is UNPLUGGED (different address though)
Why is SCL line forced low? Is this normal? It's not the slave that is forcing it Low because when the I2C wire is unplugged it is also being forced low. Oh, btw, I'm using two 10k pullup resistors.
Can you help me with this?
Thank you in advance
  • Well, if it's not the slave, then it's the master. And without getting into your code, the oscillograms doesn't look right. I2C data transfer have to start with a start bit (Data line pulled low while clock line remains high) and ends with a stop bit. So it seems that your code isn't working properly.

  • Yes, well. I kindda have the feeling the problem is in my code. But i just copied one of the code examples so It should work wright?

    I will draw the same oscilograms with one of the launchpad code examples with the I2C wire unplugged (but with the 10k pull-ups) and see what happens.

  • Oh, my bad, start bit looks OK, but I don't know why the master would pull the clock line low at the end.

  • Hello,

    I have tested this with one of the Grace Examples for the MSP430: USCI I2C Master TX. The same thing happens. It gets stuck in LPM. Why is the clock being pulled down in the end of the transmission if there is no slave connected to the i2C wire?

    This is my setup for this test:

    //******************************************************************************
    //  MSP430G2xx3 Demo - USCI_B0 I2C Master TX single bytes to MSP430 Slave
    //
    //  Description: This demo connects two MSP430's via the I2C bus. The master
    //  transmits to the slave. This is the master code. It continuously
    //  transmits 00h, 01h, ..., 0ffh and demonstrates how to implement an I2C
    //  master transmitter sending a single byte using the USCI_B0 TX interrupt.
    //  ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = ~1.2MHz
    //
    //                                /|\  /|\
    //               MSP430G2xx3      10k  10k     MSP430G2xx3
    //                   slave         |    |        master
    //             -----------------   |    |  -----------------
    //           -|XIN  P1.7/UCB0SDA|<-|---+->|P1.7/UCB0SDA  XIN|-
    //            |                 |  |      |                 |
    //           -|XOUT             |  |      |             XOUT|-
    //            |     P1.6/UCB0SCL|<-+----->|P1.6/UCB0SCL     |
    //            |                 |         |                 |
    //******************************************************************************
    /*
     * ======== Standard MSP430 includes ========
     */
    #include <msp430.h>
    
    /*
     * ======== Grace related declaration ========
     */
    extern void CSL_init(void);
    
    unsigned char TXData;
    unsigned char TXByteCtr;
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        CSL_init();
    
        TXData = 0x00;                            // Holds TX data
    
        while (1)
        {
          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
          TXData++;                               // Increment data byte
        }
    }
    
    //------------------------------------------------------------------------------
    // 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.
    //------------------------------------------------------------------------------
    unsigned short USCIAB0TX_ISR(void)
    {
        if (TXByteCtr)                            // Check TX byte counter
        {
          UCB0TXBUF = TXData;                     // Load TX buffer
          TXByteCtr--;                            // Decrement TX byte counter
          return 0;
        }
        else
        {
          UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
          IFG2 &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
          return CPUOFF;                          // Exit LPM0
        }
    }
    

  • Without getting into or testing your code, just a guess, but maybe you should add PORT1 setup, like set clock pin to output (or input - high impedance), select it's functionality (P1SEL) etc. You should take the Familys User Guide and read the description of USCI I2C mode. I actually haven't used so without looking into user guide I can't tell you anything for sure. But take a look and if you still can't get it to work, it will try the code my self (but only in evening CET).

  • Hi! Thank you, once again for taking interest in my post.

    I checked the guide and I think I have an explanation for this.
    I think the configurations needed are correct in my code. The problem I see here, is that on the 9th clock cycle, the master expects an ACK from the slave. The ACK will trigger the interrupt and the stop condition is sent.

    As we can see in the oscilograms, the ACK is not there (the SDA line should go low in the 9th clock cycle). If the ACK doesn't come, then it is a NACK. In my code I'm not testing the flags for NACKs, causing the micro to stuck in LPM.

    I'm not sure about this, but if what I said is true, the conclusion is that the slave is, simply, dead or not there. This is very bad for me because I printed a PCB board for the TLC ship and this means I have some kind of problem in the hardware.

    What do you think?

    Cheers

     

     

  • Hmm, OK. But you just said that the slave isn't connected, so it's only a software problem, isn't it? If the master doesn't receive ack, it should simply start from the beginning.

  • Hi again,

    I solved the problem!
    I think what I sad before is true, but the problem was the 7Bit address. I was writing the 7bit address + the r/w bit as the address. Arrgh. Sorry about this waste of time. 

     

  • Pedro Serra said:
    But the solution does not reside on the address (unfortunately).

    No, but the address is still wrong. OS you apparently have two bugs.

    Pedro Serra said:
    #define TLC59116_ADR 0xD0 // this is the allcall address
    UCB0I2CSA = TLC59116_ADR;                // Slave Address

    0xD0 is not a valid slave address. Slave address is a 7 bit value and 0xd0 is obviously 8 bit, so it can't be right.
    Apparently, 0xD0 is a start byte, consisting of 7 bit slave address and 1 bit R/W.

    So the slave address is apparently 0x68 (right-justified 7 bit) which needs to be written to UCB0I2CSA. The USCI will padd it then with a R/W bit based on UCTR bit wehn sending the start byte.

**Attention** This is a public forum