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: I2C program for DS2482

Part Number: MSP430F5529

Tool/software: Code Composer Studio

Hi, 

I try writing a program for DS2482-100 (specifically for reading DS18B20 through DS2482-100). I'm using MSP430F5529. According to Maxims "How to use the DS2482", there need to be:

I tried following code but it doesn't work, it hangs on reading operation (I marked the place in the code). Can you please look if I'm not missing anything?

unsigned char *PTxData; // Pointer to TX data
unsigned char TXByteCtr;
unsigned char RXData;

void initI2C()
{
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    P4SEL |= 0x06; // Assign I2C pins to USCI_B1
    UCB1CTL1 |= UCSWRST; // Enable SW reset
    UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
    UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
    UCB1BR0 = 2; // fSCL = SMCLK/12 = ~100kHz
    UCB1BR1 = 0;

    UCB1I2CSA = 0x18; // shifted 0x30

    UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
    UCB1IE |= UCTXIE; // Enable TX interrupt
}

void restart(int type)
{
    UCB1CTL1 &= ~UCTR;              // set receiver mode
    UCB1CTL1 |= UCTXSTT;        // send restart
    while (UCB1CTL1 & UCTXSTT)
        ;     // wait for start condition done
    UCB1CTL1 |= UCTXSTP;            // send STOP
}
void stopCommand()
{
    UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
}
unsigned char receiveData() //wywaliłam pętle, bo i tak odbieramy tylko 1 bajt
{
    while (UCB1CTL1 & UCTXSTP)
        ;             // Ensure stop condition got sent
    UCB1CTL1 |= UCTXSTT;                    // I2C start condition
    while (UCB1CTL1 & UCTXSTT)
        ;              // Start condition sent?
    UCB1CTL1 |= UCTXSTP;                    // I2C stop condition

    __bis_SR_register(LPM0_bits + GIE);     // Enter LPM0, enable interrupts
    __no_operation();                       // For debugger

    return RXData;                  // Increment correct RX value
}

void startCommand()
{
    UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
}
void sendData(unsigned char*TxData)
{
    unsigned int i;

    for (i = 0; i < 10; i++)
        ; // Delay required between transaction
    PTxData = (unsigned char *) TxData; // TX array start address
                                        // Place breakpoint here to see each
                                        // transmit operation.
    TXByteCtr = sizeof TxData; // Load TX byte counter

  
    __bis_SR_register(LPM0_bits + GIE);
    // Enter LPM0, enable interrupts
    __no_operation(); // Remain in LPM0 until all data
                      // is TX'd
    while (UCB1CTL1 & UCTXSTP)
        ; // Ensure stop condition got sent
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCI_B1_VECTOR
__interrupt
void USCI_B1_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B1_VECTOR))) USCI_B1_ISR (void)
#else
#error Compiler not supported!
#endif
{
    switch (__even_in_range(UCB1IV, 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:
        RXData = UCB0RXBUF;                     // Get RX data
        __bic_SR_register_on_exit(LPM0_bits);   // <- HERE IT STOPS
        break; // Vector 10: RXIFG
    case 12: // Vector 12: TXIFG
        if (TXByteCtr) // Check TX byte counter
        {
            UCB1TXBUF = *PTxData++; // Load TX buffer
            TXByteCtr--; // Decrement TX byte counter
        }
        else
        {
            UCB1CTL1 |= UCTXSTP; // I2C stop condition
            UCB1IFG &= ~UCTXIFG; // Clear USCI_B1 TX int flag
            __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
        }
    default:
        break;
    }
}

  • Hi,

    Have you tried using a logic analyzer or oscilloscope to see if you are seeing the correct signals on the data and clock lines? Please take a look at the following document for help on debugging your serial communication issues: www.ti.com/.../slaa734a.pdf

    Regards,
    Nathan
  • Hello,
    I checked it with oscilloscope, SCL is being kept low right after starting of debugging, without even one signal.
    Best regards,
    toann
  • Hi,

    To clarify, you never see the SCL line go high? I'm a little confused here, because in your code you include a comment that indicates that it is getting stuck in the USCI_B ISR? Is this true? Because, if the SCL line stays low, then there shouldn't be anything to cause the device enter the ISR, so I am not sure how this would have happened.

    Regards,
    Nathan
  • > RXData = UCB0RXBUF; // Get RX data

    This won't clear the RXIFG for UCB1, so you'll keep coming back to the ISR. (You also won't get your data.) Try:

    > RXData = UCB1RXBUF; // Get RX data
  • I changed B0 to B1, nothing differs. Here's how SDA looks like:

    SCL looks the same. And here are registers:

  • Where is your program executing (stuck?) after the change? Also: In what order are you calling these functions?

    The DS2482 doesn't (can't, per data sheet p. 21) do clock-stretching, so the USCI must be doing it. Clock-stretching is consistent with not servicing RXBUF (or TXBUF as appropriate). Reading UCB1IV clears RXIFG, but the F5 User Guide (SLAU208O) section 38.3.4.2.2 talks about reading the RXBUF, not clearing the RXIFG.

    Can you post your updated ISR?
  • It still hangs at "__bic_SR_register_on_exit(LPM0_bits);", just like it was before. 

    That's how I'm calling it in main():

    while (1)
        {
            initI2C();
            startCommand();
             int i = DS2482_detect(DS2482_ADDRESS);
        }

    It's just to check whether implementation (and hardware) works at all.

    The DS2482_detect(DS2482_ADDRESS) function was given by Maxim, I just adapted the naming. 

    After reading user guide, I tried this:

     unsigned char receiveData() 
    {
        while (UCB1CTL1 & UCTXSTP)
            ;             // Ensure stop condition got sent
        UCB1CTL1 |= UCTXSTT;                    // I2C start condition
    	
        while (UCB1CTL1 & UCTXSTT)
            ;              // Start condition sent?
        UCB1CTL1 |= UCTXSTP;                    // I2C stop condition
    
        __bis_SR_register(LPM0_bits + GIE);     // Enter LPM0, enable interrupts
        __no_operation();                       // For debugger
    
        return RXData;                  // Increment correct RX value
    }
     
     
     .....
     
     case 10:
    		 do
            {
                RXData = UCB1RXBUF;
            }
            while ((!(UCB1CTL1 & UCTXSTT)) && (!(UCB1CTL1 & UCTXSTP)));
            __bic_SR_register_on_exit(LPM0_bits);                                                     //<-still hangs here
            break; // Vector 10: RXIFG

  • > while ((!(UCB1CTL1 & UCTXSTT)) && (!(UCB1CTL1 & UCTXSTP)));
    This loop is a bit disturbing. STT and STP can go from 1 to 0 on their own, but will only go from 0 to 1 based on software (main). If you get here with both =0, you'll never get out of this loop.

    More generally, I'm pretty sure a loop is unnecessary here. What did it do before you added the loop?
  • It hanged at the exact same place.
  • Actually that's a clue. It means that the RXIFG happened before main set STP.

    With BR0=2, you're running the I2C at 512kHz, which is faster than Fast Mode. More to the point, the CPU has only 2*8=16 clocks after STT goes low to set STP [Ref F5 User Guide SLAU208O Figure 38-13]. That's maybe 3 instructions, which isn't much.

    Once the first byte comes in, you won't be able to get out of the ISR before the next byte arrives (16 more clocks) so you'll never get back to main.

    Try setting BR0=10 (100kHz) and see if your program acts different.
  • It didn't act different, still stucks at the same place.
  • I think the debugger's claim that you're sitting in the RXIFG case (with RXIE=0) is just false. I'm pretty sure it's related to Erratum UCSI39 [See also F5529 Errata Sheet SLAZ314W]. The workaround is to set GIE early in the program. Add this just after the initI2C() call:
    > __enable_interrupt();

    The reason you're stalling is that you're requesting a Start (in startCommand()) before you've set up the Tx parameters, so the transmission (length 0) ends immediately and "wakes" main long before it goes to LPM0. By the time the LPM starts, there's no event left to wake it up. Move the STT setting into sendData, after you've set up PTxData and such.

    Unsolicited: sizeof(unsigned char *) is the length of the pointer, not the data. Change sendData to pass an explicit length.
  • Okay, still doesn't work but finally something happened: now it stucks there:

    unsigned char receiveData() //wywaliłam pętle, bo i tak odbieramy tylko 1 bajt
    {
        while (UCB1CTL1 & UCTXSTP)
            ;             // Ensure stop condition got sent
        UCB1CTL1 |= UCTXSTT;                    // I2C start condition
        while (UCB1CTL1 & UCTXSTT)
            ;              // Start condition sent?
        UCB1CTL1 |= UCTXSTP;                    // I2C stop condition
    
        __bis_SR_register(LPM0_bits + GIE);     //<----HERE
        __no_operation();                       // For debugger
    
        return RXData;                  // Increment correct RX value
    }

    After initI2C() registers are:

    When it stucks, registers are:

    RXBUF changes to 0x18 after: " UCB1CTL1 |= UCTXSTT;        // send restart" in restart(int type).

  • You need to enable the RXIFG that's pending, something like:
    > UCB1IE |= UCRXIE0; // Enable RXIFG
  • The first time I run it after adding "UCB1IE |= UCRXIE; // Enable RXIFG" it worked but then I restarted program and now it stops at "__bis_SR_register(LPM0_bits + GIE);" in sendData(). At the moment it stucks, only TXIFG is 1, others IFGs are 0.
  • That's odd. Did UCTXIE0 get turned off somewhere? (I don't see it in what you've posted.)
  • Not intentionally, for sure. Here's current code:

    void initI2C()
    {
        WDTCTL = WDTPW + WDTHOLD; // Stop WDT
        P4SEL |= 0x06; // Assign I2C pins to USCI_B1
        UCB1CTL1 |= UCSWRST; // Enable SW reset
        UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
        UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
        UCB1BR0 = 10; // fSCL = SMCLK/12 = ~100kHz
        UCB1BR1 = 0;
    
        UCB1I2CSA = 0x18; // shifted 0x30
    
        UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
        UCB1IE |= UCTXIE; // Enable TX interrupt
    }
    
    void restart(int type)
    {
        UCB1CTL1 &= ~UCTR;              // set receiver mode
        UCB1CTL1 |= UCTXSTT;        // send restart
        while (UCB1CTL1 & UCTXSTT)
            ;     // wait for start condition done
        UCB1CTL1 |= UCTXSTP;            // send STOP
    }
    
    void stopCommand()
    {
        UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
    }
    
    unsigned char receiveData() {
        while (UCB1CTL1 & UCTXSTP)
            ;             // Ensure stop condition got sent
        UCB1CTL1 |= UCTXSTT;                    // I2C start condition
        while (UCB1CTL1 & UCTXSTT)
            ;              // Start condition sent?
        UCB1CTL1 |= UCTXSTP;                    // I2C stop condition
        UCB1IE |= UCRXIE; // Enable RXIFG
        __bis_SR_register(LPM0_bits + GIE);     // Enter LPM0, enable interrupts
        __no_operation();                       // For debugger
    
        return RXData;                  // Increment correct RX value
    }
    
    void startCommand()
    {
        UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
    }
    
    void sendData(unsigned char*TxData, unsigned int lenght)
    {
        unsigned int i;
    
        for (i = 0; i < 10; i++)
            ; // Delay required between transaction
        PTxData = (unsigned char *) TxData; 
        TXByteCtr = lenght; // Load TX byte counter
        startCommand();
       
        __bis_SR_register(LPM0_bits + GIE);
        __no_operation(); /
        while (UCB1CTL1 & UCTXSTP)
            ; // Ensure stop condition got sent
    }
    
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = USCI_B1_VECTOR
    __interrupt
    void USCI_B1_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(USCI_B1_VECTOR))) USCI_B1_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
        switch (__even_in_range(UCB1IV, 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:
            RXData = UCB1RXBUF;
            __bic_SR_register_on_exit(LPM0_bits);   
            break; // Vector 10: RXIFG
        case 12: // Vector 12: TXIFG
            if (TXByteCtr) // Check TX byte counter
            {
                UCB1TXBUF = *PTxData++; // Load TX buffer
                TXByteCtr--; // Decrement TX byte counter
            }
            else
            {
                UCB1CTL1 |= UCTXSTP; // I2C stop condition
                UCB1IFG &= ~UCTXIFG; // Clear USCI_B1 TX int flag
                __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
            }
        default:
            break;
        }
    }
    

  • I don't see your symptom. I'm also not using your device, just a random I2C device I pulled out of a drawer.

    I did see some odd symptoms that appeared to be timing. I switched to blinking an LED and disconnected the debugger, and it appears to free-run fine.

    If it is the debugger throwing your timing off, or (somehow) your device, I'm not sure I can help much more.

    Here's the main program I'm using

    int
    main(void)
    {
        P1OUT |=  BIT0;
        P1DIR |=  BIT0;
        initI2C();
        __enable_interrupt();
         while(1)
        {
            //startCommand();
            sendData(txdata, sizeof(txdata));
            restart(0);
            receiveData();
            P1OUT ^= BIT0;
            __delay_cycles(50000UL); // 
        }
        /*NOTREACHED*/
        return(0);
    }
    
  • Okay, thank you for all your help!

**Attention** This is a public forum