• Resolved

Problem with I2C communication between MSP430F5529 and AD5933

Part Number: MSP430F5529

#define SLAVE_ADDRESS 0x0D /**< Address to AD5933. */
#define BAUD_RATE 12 /**< Baud Rate value. */
#define SDA_PIN 0x00                                    // msp430F5529 UCB0SDA pin
#define SCL_PIN 0x01                                    // msp430F5529 UCB0SCL pin

P1DIR |= BIT1;
P1OUT |= BIT1;
P1OUT ^= (BIT1);   //turn on LED (is turned off when all data for initialization was send)

P3REN |= SDA_PIN + SCL_PIN;
P3OUT |= SDA_PIN + SCL_PIN;
P3SEL |= SDA_PIN + SCL_PIN;                 // 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 = BAUD_RATE;                        // set prescaler
UCB0BR1 = 0;
UCB0I2CSA = SLAVE_ADDRESS;                  // Set slave address
UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
//UCB0IE = UCNACKIE;	//tried with and without this line, there isn't a difference
UCB0IE |= UCTXIE;                           // Enable TX ready interrupt

P1OUT ^= (BIT1);   //turn off LED

while (UCB0STAT & UCBBUSY)
    ;

That is my code. I know that my board works because the LED blinks fine, but I always get stuck in that last while loop.

This code is adapted from MSP430G2553 communication with AD5933 as well, where it worked fine. I did all the necessary ports and pins changes according to the datasheet.

One other difference between this and the other system is that now I am using a MSP-FET Flash Emulation Tool plus a micro UBS to power,  instead of the mini USB port. But I don't know how this may or may not affect my code.

It seems that the STAT of the MSP never changes and the communication isn't established. Can someone help me with it? I don't know what is wrong with my initialization. Maybe the problem is with the interrupts? What should I do?

Thank you all in advance for trying to help me.

  • In reply to Clemens Ladisch:

    I checked the bus with an oscilloscope with the same I used with G2553, menu options for the channels.
    Unfurtunately, no changes happened. The SDA always low and SCL always high.
    What do you suggest I do now?
    This can't be more frustrating!
  • In reply to Clemens Ladisch:

    That makes a lot of sense, thank you.
    Although, I tried commenting the "UCB0IE |= UCRXIE;" line, and then also "UCB0IE = UCNACKIE;", and the result is the same.
  • In reply to Gabriela Costa:

    The difference is that, immediately after initialization, there is no received data, and no NACK happened, so the interrupt does not get called for those reasons.
  • In reply to Clemens Ladisch:

    Where should I put the "UCB0IE |= UCTXIE;" line? Please check my code bellow.

    Note that if I comment the first "while (UCB0STAT & UCBBUSY)" it stops on the other one.

    #include <msp430.h> 
    
    /*
     * main.c
     */
    
    #define SLAVE_ADDRESS 0x0D /**< Address to AD5933. */
    #define BAUD_RATE 0x12 /**< Baud Rate value. */
    #define SDA_PIN BIT0                                    // msp430F5529 UCB0SDA pin
    #define SCL_PIN BIT1                                    // msp430F5529 UCB0SCL pin
    
    signed char byteCtr;
    unsigned char *TI_transmit_field;
    unsigned char *TI_receive_field;
    
    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;	                // Stop watchdog timer
    
        //LED configurations
        P1DIR |= BIT1;
        P1OUT |= BIT1;
        P1OUT ^= (BIT1);   //turn on LED
    
        //MSP configurations to transmit
        P3SEL |= SDA_PIN + SCL_PIN;                 // 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 = BAUD_RATE;                         // set prescaler
        UCB0BR1 = 0;
        UCB0I2CSA = SLAVE_ADDRESS;                  // Set slave address
        UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
        UCB0IE = UCNACKIE;
        UCB0IE |= UCTXIE;                           // Enable interrupts
    
        P1OUT ^= (BIT1);                            //turn off LED
        while (UCB0STAT & UCBBUSY)                  //wait for previous traffic to clear
        ;
    
        //Starting the configuration of the slave registers
        unsigned char field[2] = { 0x80, 0xB1 };
        TI_transmit_field = field;
        byteCtr = 2;
        UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
        while (UCB0STAT & UCBBUSY)
            ;
    
        while (1)
            ;
    }
    
    //INTERRUPTS
    #pragma vector = USCI_B0_VECTOR
    __interrupt void USCI_B0_ISR(void)
    {
        switch (__even_in_range(UCB0IV, 12))
        {
        case 0:
            break;                           // Vector  0: No interrupts
        case 2:
            break;                           // Vector  2: ALIFG
        case 4:
            if (UCB0IFG & UCNACKIFG)         // send STOP if slave sends NACK
            {
                UCB0CTL1 |= UCTXSTP;
                UCB0IFG &= ~UCNACKIFG;
            }
            break;                           // Vector  4: NACKIFG
        case 6:
            break;                           // Vector  6: STTIFG
        case 8:
            break;                           // Vector  8: STPIFG
        case 10:                                  // Vector 10: RXIFG -- I am not using it yet (but I'll need it)
            if (byteCtr == 0)
            {
                UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
                *TI_receive_field = UCB0RXBUF;
                TI_receive_field++;
            }
            else
            {
                *TI_receive_field = UCB0RXBUF;
                TI_receive_field++;
                byteCtr--;
            }
            break;
        case 12:                                     // Vector 12: TXIFG
            if (byteCtr == 0)
            {
                UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
                UCB0IFG &= ~UCTXIFG;                 // Clear USCI TX int flag
            }
            else
            {
                UCB0TXBUF = *TI_transmit_field;
                TI_transmit_field++;
                byteCtr--;
            }
            break;
        default:
            break;
    
        }
    }
    
    
    

  • In reply to Gabriela Costa:

    You should REMOVE it.

    Put it where you want the first TX interrupt to happen, i.e., directly after setting TXSTT.
  • In reply to Clemens Ladisch:

    As you can see bellow (and in the complete code above) I have that same line right after the STT, however, even when I comment the first while (the one I should remove, I understood) it gets stuck in that one, right after STT.

    Please, check the code above again and ignore that first highlighted while.

        UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
        while (UCB0STAT & UCBBUSY)
            ;

  • In reply to Gabriela Costa:

    I am talking about the line that sets TXIE.
  • In reply to Clemens Ladisch:

    Oh I see. I tried it too, the same happened, stoped in the loop.

        WDTCTL = WDTPW | WDTHOLD;	                // Stop watchdog timer
    
        //LED configurations
        P1DIR |= BIT1;
        P1OUT |= BIT1;
        P1OUT ^= (BIT1);   //turn on LED
    
        //MSP configurations to transmit
        P3SEL |= SDA_PIN + SCL_PIN;                 // 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 = BAUD_RATE;                         // set prescaler
        UCB0BR1 = 0;
        UCB0I2CSA = SLAVE_ADDRESS;                  // Set slave address
        UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
        UCB0IE = UCNACKIE;
        //UCB0IE |= UCTXIE;                           // Enable interrupts
    
        P1OUT ^= (BIT1);                            //turn off LED
        //while (UCB0STAT & UCBBUSY)                  //wait for previous traffic to clear
        //;
    
        //Starting the configuration of the slave registers
        unsigned char field[2] = { 0x80, 0xB1 };
        TI_transmit_field = field;
        byteCtr = 2;
        UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
        UCB0IE |= UCTXIE;
        while (UCB0STAT & UCBBUSY)
            ;
    
        while (1)
            ;

  • The solution was enabling the global interrupts in the initialization.

    I used that line:

    __enable_interrupt();

    Thank you all who tried so hard to help me.

    The best regards,

    Gabriela