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.

MSP430F5529: I2C Stop flag timing issue

Part Number: MSP430F5529

I am trying to read data from a temperature sensor over I2C. I have managed to get comms up and running however I have found some strange behavior. 

I am unable to time the stop flag correctly and the result is that I read to much data. 

My question is this, how do I assert the Stop flag on the second frame without the delay that I am experiencing resulting on the stop being asserted on the fourth frame?

The image above demonstrates the stop flag timing issue. NOTE the DIO2 Signal is when the STP flag is asserted. I then set the DIO2 signal to zero upon the beginnings of a new I2C transaction. 

to be clear I want I2C structure as follows:

| S | Address | R | A | Data | A | Data | NAK | P |

What i am getting:

| S | Address | R | A | Data | A | Data | A | Undesired Data | A | Undesired Data |NAK | P |

CODE: 

#include <msp430.h>
#include <stdint.h>

unsigned char RXData;
unsigned char TXData;
uint8_t RXByteCtr = 0;
uint8_t TXByteCtr = 0;

void I2CInit(void)
{
P3REN |= 0x03;
P3OUT |= 0x03;
P3SEL |= 0x03; // 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 = 10; // fSCL = SMCLK/10 = 100kHz
UCB0BR1 = 0;
UCB0I2CSA = 0x48; // Slave Address is 048h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
}

void I2CWriteInit(void)
{
UCB0CTL1 |= UCTR;
UCB0IFG &=~ UCTXIFG;
UCB0IE &=~ UCRXIE;
UCB0IE |= UCTXIE;
}

void I2CReadInit(void)
{
UCB0CTL1 &=~ UCTR;
UCB0IFG &=~ UCRXIFG;
UCB0IE &=~ UCTXIE;
UCB0IE |= UCRXIE;
}

void ReadTemp(void)
{
while (UCB0STAT & UCBBUSY);
P1OUT &= ~BIT6;
RXByteCtr = 2;
I2CReadInit();
UCB0CTL1 |= UCTXSTT;
}

void SetRegPtr(void)
{
while (UCB0STAT & UCBBUSY);
TXByteCtr = 1;
TXData = 0x00;
I2CWriteInit(); 
UCB0CTL1 |= UCTXSTT; 

}

int main(void)
{
WDTCTL = WDTPW + WDTHOLD;

I2CInit();

P1DIR |= BIT6;
P1OUT &= ~BIT6;


__enable_interrupt();

SetRegPtr();

while(1)
{
ReadTemp();
}
}

#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
switch(__even_in_range(UCB0IV,12))
{
case 10:
if (RXByteCtr--) 
{
RXData = UCB0RXBUF; 
}
else 
{
UCB0CTL1 |= UCTXSTP; 
P1OUT |= BIT6;
}
break; 
case 12: 
if (TXByteCtr) 
{
UCB0TXBUF = TXData; 
TXByteCtr--; 
}
else 
{
UCB0CTL1 |= UCTXSTP; 
UCB0IFG &= ~UCTXIFG;
}
break;
default: break;
}
}

  • You have a couple of problems. The first is the use of the post decrement mode on RXByteCtr. The if() will not select your TXSTP code till the third interrupt.

    The second is that reading RXBUF frees the hardware to continue which results in that fourth byte read.

    So use predecrement and set TXSTP before reading the last byte of data from RXBUF.

  • Right on the money David, Thanks for the help.

    Code correction made to the interrupt:

    case 10:
    if (--RXByteCtr)
    {
    UCB0CTL1 |= UCTXSTP; //<- this
    P1OUT |= BIT6;
    }
    P1OUT |= BIT5;
    RXData = UCB0RXBUF; //<- before that on final frame
    break;

    The proof:

    What i missed rom the user guide (p1007):

    "Setting the UCTXSTP bit generates a STOP condition. After setting UCTXSTP, a NACK followed by a STOP condition is generated after reception of the data from the slave, or immediately if the USCI module is currently waiting for UCBxRXBUF to be read."

**Attention** This is a public forum