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.

USCI Interrupt Enables being non-user-code reset?

I'm working with an MSP430F2619-HT and have a problem with the USCI modules in I2C Master mode.  Having used code snippets from code examples "MSP430x261x_uscib0_i2c_08.c" and "MSP430x261x_uscib0_i2c_09.c" individually and experiencing success, I've attempted to splice the two together to get both TX and RX functionality.  The MSP is communicating with a Cypress PSoC chip, and I've currently gotten the TX segment functioning properly, albeit only without my I2C timeout function.  

My main problem is that the UCB0TXIE and UCB0RXIE bits in the IE2 SFR are being reset to "0" values about 3 bytes into my 32 byte payload, stopping the rest of the communication.  I've tried isolating the location where this happens, but when stepping through it line by line, the phenomenon never occurs.  Still having only worked in the embedded world for about 2 years now, I'm not entirely sure what that means.  The IE2 SFR is only written to in my initialization routine to set those two interrupt enable bits.  Is there any kind of hardware reset or event that could affect the IE2 register?

Below is the relevant code, including my main I2C routine, the TX/RX I2C ISR(not to be confused with the State ISR), and my timeout function.  On a somewhat related note, the TX portion of the exchange only successfully sets up the stop condition when I remove the i2c_timeout function call, and I have yet to determine why.

bool read_I2C( void )
{
		i2c_frame.read_write = true;

		// Fill TX buffer
		uint8_t TxData[2];
		TxData[0] = 0x00;	// I2C slave data address beginning at Status
		TxData[1] = (uint8_t)( 0x000F & Status );

		i2c_frame.PTxData = (unsigned char *)TxData;
		i2c_frame.TXByteCtr = sizeof TxData;

		while(UCB0CTL1 & UCTXSTP);		// Ensure stop condition has been sent
		UCB0CTL1 |= UCTR + UCTXSTT;		// TX start condition

		__delay_cycles(10000);
/*
		if( i2c_timeout( &i2c_frame.TXByteCtr ) )
		{
			i2c_frame.num_failures++;
			return 0;
		}
*/

	i2c_frame.read_write = false;	// READ
	i2c_frame.PRxData 	= (unsigned char *)i2c_frame.PRxData;	// RX array start address
	i2c_frame.RXByteCtr = 32;       							// Load TX byte counter
	while (UCB0CTL1 & UCTXSTP);            						// Ensure stop condition got sent
	UCB0CTL1 &= ~UCTR;
	UCB0CTL1 |= UCTXSTT;             							// I2C RX, start condition

	__delay_cycles(5000);

	i2c_start_xchange = false;
}

bool i2c_timeout( volatile uint8_t *ByteCtr )
{
	uint32_t i2c_timeout = 0;

	while( *ByteCtr > 0 )
	{
		__delay_cycles(16); // 1us w/ 16MHz clock
		i2c_timeout++;
		if( i2c_timeout >= 10000) // 10ms
			return 1;	// timeout
	}
	return 0;	// no timeout
}

#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
	if( i2c_frame.read_write )	// I2C TX/write
	{
		if (i2c_frame.TXByteCtr)                // Check TX byte counter
		{
			UCB0TXBUF = *i2c_frame.PTxData++;   // Load TX buffer
			i2c_frame.TXByteCtr--;              // Decrement TX byte counter
		}
		else
		{
			UCB0CTL1 |= UCTXSTP;                // I2C stop condition
			IFG2 &= ~UCB0TXIFG;                 // Clear USCI_B0 TX int flag
		}
	}
	else	// I2C RX
	{
		i2c_rx++;

		i2c_frame.RXByteCtr--;                  // Decrement RX byte counter
		if (i2c_frame.RXByteCtr)
		{
			*i2c_frame.PRxData++ = UCB0RXBUF;   // Move RX data to address PRxData
			if (i2c_frame.RXByteCtr == 1)       // Only one byte left?
			{
				UCB0CTL1 |= UCTXSTP;            // Generate I2C stop condition
			}
		}
		else
		{
			*i2c_frame.PRxData = UCB0RXBUF;     // Move final RX data to PRxData
		}
	}
}

Any help is much appreciated, and I will gladly provide further information.  Thanks beforehand!

  • Can you put a write breakpoint on the address for the SFR and catch the culprit that way? Are you sure you aren't de-referencing bad pointers and that causes the register to be inadvertently cleared?
  • Wow, I didn't realize you could do that with CCS. Yes, the write is occurring during reception of the third byte on line 74 of the code I've pasted, inside the ISR. I'm guessing that the address of IE2 is 0x0C or 0x0E. *PRxData's value starts as 0x0C, then immediately before the write to IE2 is "incremented" to 0x0E.
  • I spoke too soon, I found in the F2619 data sheet that IE2's memory address is 0x01. I'll continue to look into it, I'm sure this is the correct path to fixing it. Thanks for leading me in the right direction, I'll be back once I either hit another wall or figure the problem out
  • Another thing that I notice that is wrong is how you are setting the buffer pointers in the i2c_frame struct.

    For instance, you declare TxData[] in i2c_Read function, and then assign the address of that to the i2c_frame.PTxData

    The problem is that TxData will be allocated from i2c_Read's stack frame, and once that function exits, the pointer is no longer valid and if you use it to write to the buffer you will be trashing the stack somewhere else (possibly even in the function that is currently executing).

    You need to declare your buffers either globally or statically at the file module level. This makes sure they are in their own dedicated spot in RAM so that your pointer is always valid.

  • I didn't quite boil down the exact way this was messing up, but I set up proper TX and RX buffers for those pointers, and the miswrites to IE2 are no more. I'm getting complete frames, thanks!

**Attention** This is a public forum