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.
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!
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.
**Attention** This is a public forum