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.

I2C hangs on while (UCB0CTL1_bit.UCTXSTT == 1);

Other Parts Discussed in Thread: MSP430G2553

I'm trying to communicate with an external sensor with I2C interface, using the MSP430G2553 peripheral in polling mode (no interrupt).

The code hangs on the while (UCB0CTL1_bit.UCTXSTT == 1); polling line, just after the MSP sends the start command and then the slave address.

I checked the signals with an oscilloscope: the clock remains low just after the last address bit.

I know that after the UCTXSTT while loop I should also check the interrupt to verify if the slave has the acknowledged the address, but the main problem is that program doesn't exit the while loop.

I also noticed that many MSP users have the same problem in using the I2C in a polling mode.

Shouldn't be used in this way?

Is there any solution?

Hereafter the code:

--------

UCB0CTL1_bit.UCSWRST = 1; // USCI Software Reset

UCB0CTL0_bit.UCSYNC = 1; // Syncronous Mode
UCB0CTL0_bit.UCMODE0 = 1; // I2C Mode
UCB0CTL0_bit.UCMODE1 = 1; // I2C Mode
UCB0CTL0_bit.UCMST = 1; // Master Select
UCB0CTL0_bit.UCMM = 0; // Single Master Environment
UCB0CTL0_bit.UCSLA10 = 0; // 7 bit Slave Address
UCB0CTL0_bit.UCA10 = 0; // 7 bit Own Address

UCB0CTL1_bit.UCSSEL0 = 1; // SMCLCK Select
UCB0CTL1_bit.UCSSEL1 = 1; // SMCLCK Select

UCB0BR1 = 0;
UCB0BR0 = 80;

UCB0I2COA = 0x0000 + I2C_MSP430_ADDRESS; // 7 bit own address (1Bh = 27d) + General Call Disabled

UCB0CTL1_bit.UCSWRST = 0; // USCI Software un-Reset


...


int I2C_start_and_write (unsigned char argData, unsigned char argAddress) {
// // wait for the end of any previous activity on the bus
// while (UCB0CTL1_bit.UCTXSTP == 1);

// Set the slave address
UCB0I2CSA = argAddress;

// set UCTR for transmitter mode
UCB0CTL1_bit.UCTR = 1;

// set UCTXSTT to generate a START condition
// (the slave address is automatically sent after the START condition)
UCB0CTL1_bit.UCTXSTT = 1;

// wait for the end of any previous activity on the bus
while (UCB0CTL1_bit.UCTXSTT == 1);

// Write the data on the I2C bus
UCB0TXBUF = argData;

// Return true
return (1);
}

  • Flavio Renga90296 said:
    I also noticed that many MSP users have the same problem in using the I2C in a polling mode.

    And I often answered to this:

    This is documented and intended unctionality. Look at the I2C diagram for master transmitter mode.
    After setting UCTXSTT, TXIFG gets set. And the USCI waits in the ACK cycle of teh start condition until either something is written to TXBUF (so it can continue) or UCTXSTT or UCTXSTP are set (so it will end the current transfer).

    In your code, you don't tell the USCI whether you want to continue with data sending or end the transfer, so it waits for you.

    If using interrupts, many people don't notice this as the intrrupt gets called immediately after setting UCTXSTT, stuffing something into TXBUF.

  • Thanks so much for the clarification.

    I've implemented some modification to the code according to your comments (see hereafter), but the program is still halting on the while loop:

            while (UCB0CTL1_bit.UCTXSTT == 1);

    Where am I wrong?

    Thanks again.

    Flavio

    int I2C_start_and_write (unsigned char argData, unsigned char argAddress) {
        // wait for the end of any previous activity on the bus
        while (UCB0CTL1_bit.UCTXSTP == 1);

        // Set the slave address
        UCB0I2CSA = argAddress;

        // set UCTR for transmitter mode
        UCB0CTL1_bit.UCTR = 1;

        // set UCTXSTT to generate a START condition
        // (the slave address is automatically sent after the START condition)
        UCB0CTL1_bit.UCTXSTT = 1;

        // wait until the START condition has been sent
        while (IFG2_bit.UCB0TXIFG == 0);                              // OPTIONAL?

        // immidiately write the data on the I2C bus
        UCB0TXBUF = argData;

        // wait for the end of any previous activity on the bus
        while (UCB0CTL1_bit.UCTXSTT == 1);                            // THE CODE LOOPS HERE

        // if not acknowledge
        if (UCB0STAT_bit.UCNACKIFG == 1) {
            // Generate stop condition
            UCB0CTL1_bit.UCTXSTP = 1;
            // Return false
            return (0);
        }

        // Return true
        return (1);
    }

  • Thanks again for your suggestions.

    The code I posted is now working.

    For your information, the problem was in another part of the code, in particular there was a bug in the code I wrote to  release the I2C bus sending a stop condition. This caused the I2C peripheral to enter in an unknown state. The I2C peripheral remains in this hanged state even after a new flash downloading, causing the correct portion of the code to run abnormally.

    The only approaches I can use to exit  the I2C peripheral from the hanged state are:

    1. to remove the power from the microcontroller and run again the code (the code works once until the bug in my code)
    2. to manually set the I2C port  outputs first to 1 then to 0 (the code works once until the bug in my code)

    Did you ever noticed this kind of behavior?

    Thanks again.

  • Flavio Renga90296 said:

    The only approaches I can use to exit  the I2C peripheral from the hanged state are:

    1. to remove the power from the microcontroller and run again the code (the code works once until the bug in my code)
    2. to manually set the I2C port  outputs first to 1 then to 0 (the code works once until the bug in my code)


    So it seems your bug was crashing the I2C slave, which was still 'busy' when receiving the new transmission and was holding the clock low.

    The USCIs itnernal state and behaviour is reset whenever you set the UCSWRST bit (which you should do before setting/changing the slave address, the baudrate, switching master/slave mode etc.)

  • I'm having exactly the same problem.

    The weird thing is that it worked two times already while trying to write into the FRAM I'm working with.

    What did you do to solve this problem?

    I've tried to disconnect from the JTAG and then reset the computer and ... nothing.

    It worked two days ago(the last time I tried it) and no problems. This morning while I was trying to debug it again, it keeps hanging on the same UCTXSTT loop.

    Please help me out,

    Thank you so much!

  • Joao Benevides said:
    It worked two days ago

    Code that worked once will continue working if there was no change. The only thing that might have changed is the hardware. Do you have proper pullups on the SDA and SCL lines? If not, this may slow down the I2C to a few 100Hz effective frequency (which may go through undetected as 'working' and then suddenly fail totally.

**Attention** This is a public forum