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, second transfer fails

Other Parts Discussed in Thread: MSP430G2553

I have a problem with I2C and the MSP430G2553. Here is my Code:

#include <msp430g2553.h>


const unsigned char Init[] = {0xAE,0x81,0x07,0x20,0x01,0x21,0x00,0x7F,0x22,0x00,0x07,0x40,0xA0,0xA8,0x3F,0xC0,0xD3,0x00,0x8D,0x14,0xDA,0x12,0xD5,0x80,0xD9,0x22,0xDB,0x20,0xA6,0xA4,0xAF};

const unsigned char Mod[] = {0xA5};



void printC(const unsigned char* Array, unsigned int length){
	UCB0CTL1 = UCSWRST;
	UCB0CTL0 = UCMODE_3 + UCMST + UCSYNC;			// I2C master mode
	UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
	UCB0BR0 = 0x40;                          // < 100 kHz
	UCB0I2CSA = 0x3C;                       // address
	UCB0CTL1 &= ~UCSWRST;
	IE2 |= UCB0TXIE;				// Enable TX ready interrupt
	//UCB0I2CIE = UCNACKIE;
	UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition

	unsigned int c;
	for(c = 0; c < length; c++){
		__bis_SR_register(LPM3_bits + GIE);
		UCB0TXBUF = 0x80;
		__bis_SR_register(LPM3_bits + GIE);
		UCB0TXBUF = Array[c];
		//__bis_SR_register(LPM3_bits + GIE);
	}
	__bis_SR_register(LPM3_bits + GIE);

    UCB0CTL1 |= UCTXSTP;
    IE2 &= ~UCB0TXIE;
    IFG2 &= ~UCB0TXIFG;
}

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

    DCOCTL = CALDCO_8MHZ;				//DCO setting = 8MHz
    BCSCTL1 = CALBC1_8MHZ;				//DCO setting = 8MHz

    // Configure Pins for I2C
    P1SEL |= BIT6 + BIT7;                  // Pin init
    P1SEL2 |= BIT6 + BIT7;                  // Pin init


    printC(Init,31);

    __delay_cycles(8000000);

    printC(Mod,1);

    while(1);

}


// USCI_B0 Data ISR
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void){
	__bic_SR_register_on_exit(LPM3_bits);               // Wakeup main code
	IFG2 &= ~UCB0TXIFG;
}

The first printC works fine (slave executes the commands)  but in the second (printC(Mod,1);) the processor stays in the low power mode forever after entering the for loop. Any ideas?

  • After setting UCTXSTP, you should wait for the stop to be complete, before you start a new transfer. A TX interrupt happens while the _previous_ byte has just started sending (double-buffering). So it takes some time to actually perform the stop. You can test for UCTXSTP clear at the start of your sending function, before resetting the USCI.
    However, the 8M delay should give enough time.
    The code has another problem:
    When TXSTT is set in transmit modem this will immediately set TXIFG. This calls your ISR which clears the TXIFG bit. So between setting TXSTT and entering LPM, interrupts must be disabled. Which is the case iin the first run, as interrupts are disabled at startup. But after the first transfer, you leave them enabled. With the result that on second run, TXIFG, set by setting TXSTT, is instantly cleared, and won't ever be set again while your code goes into LPM and waits for it to happen.

    The approach is wrong. Either you poll the IFG bit without interrupts in your main code where you want to check it, or you put the code to write the next data byte into the ISR too. Using the interrupt and LPM for synchronization is quite fragile and prone to errors. Especially if you can't ensure that between enablign the interrupt source and entering LPM, the source won't generate an interrupt. Some demo code implicitly does this (for timer delays or ADC conversion), but without telling you why it works and that it won't always work for other situations.

**Attention** This is a public forum