Part Number:MSP430F5249
Hi,
I've got a really strange problem when trying to read over I2C. The first write and read work fine. However, the second write fails.
I am writing the two byte register address one byte at a time, then changing to read mode to do the reading. My code is shown below.
static void StoreRegisterAddress(const I2CAddressSize register_size, const uint16_t register_address)
{
uint8_t index = 0;
regAddressSize = register_size;
// MSB of register address first
switch (register_size)
{
case I2CAddressSizeTwoBytes:
regAddress[index++] = MSB16(register_address);
// no break - intentional
case I2CAddressSizeOneByte:
regAddress[index++] = LSB16(register_address);
break;
default:
// Nothing is written
break;
}
}
void WriteToI2CSlave(const uint8_t slave_address, const I2CAddressSize register_size, const uint16_t register_address, const uint8_t *data, const uint8_t size)
{
txMasterSize = (size <= MaxI2cBufferLength) ? size : MaxI2cBufferLength;
txMasterCount = 0;
memcpy(txMasterData, data, txMasterSize);
UCB0I2CSA = slave_address; // Set slave address
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
StoreRegisterAddress(register_size, register_address);
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
__no_operation();
}
void ReadFromI2CSlave(const uint8_t slave_address, const I2CAddressSize register_size, const uint16_t register_address, const uint8_t size)
{
rxMasterSize = (size <= MaxI2cBufferLength) ? size : MaxI2cBufferLength;
rxMasterCount = rxMasterSize;
pRxMasterData = rxMasterData;
UCB0I2CSA = slave_address; // Set slave address
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
StoreRegisterAddress(register_size, register_address);
UCB0CTL1 |= UCTR + UCTXSTT; // Enter writing mode and send start
__no_operation();
}
// USCI_B0 Data ISR - this is the interrupt service routine for PMU <--> slave devices
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(UCB0IV,12))
{
case 0: break; // Vector 0: No interrupts
case 2: break; // Vector 2: ALIFG
case 4: // Vector 4: NACKIFG
{
UCB0CTL1 |= UCTXSTP; // When an acknowledge is missing the slave gets a stop condition
UCB0IFG &= ~UCTXIFG;
break;
}
case 6: break; // Vector 6: STTIFG
case 8: break; // Vector 8: STPIFG
case 10: // Vector 10: RXIFG
{
if (rxMasterSize == 1)
{
if (rxMasterCount > 0)
{
UCB0CTL1 |= UCTXSTP; // Generate I2C stop condition
*pRxMasterData = UCB0RXBUF; // Move final RX data to rxMasterData
--rxMasterCount;
}
else
{
UCB0IFG &= ~UCRXIFG; // Clear USCI_B0 RX int flag
readMasterData = TRUE;
__bic_SR_register_on_exit(LPM0_bits + GIE); // Exit low power mode
}
}
else
{
--rxMasterCount;
if (rxMasterCount)
{
*pRxMasterData++ = UCB0RXBUF; // Move RX data to address rxMasterData
if (rxMasterCount == 1) // Only one byte left?
{
UCB0CTL1 |= UCTXSTP; // Generate I2C stop condition
}
}
else
{
*pRxMasterData = UCB0RXBUF; // Move final RX data to PRxData
UCB0IFG &= ~UCRXIFG; // Clear USCI_B0 RX int flag
readMasterData = TRUE;
__bic_SR_register_on_exit(LPM0_bits + GIE); // Exit low power mode
}
}
break;
}
case 12: // Vector 12: TXIFG
{
if (regAddressSize > 0)
{
// Send register address
UCB0TXBUF = regAddress[I2cMaxRegisterSize - regAddressSize];
--regAddressSize;
}
else
{
if (rxMasterCount > 0)
{
UCB0IFG &= ~UCTXIFG;
UCB0CTL1 &= ~UCTR; // Enter reading mode
UCB0CTL1 |= UCTXSTT; // I2C start condition
}
else
{
if (txMasterCount < txMasterSize) // Check TX byte counter
{
UCB0TXBUF = txMasterData[txMasterCount++]; // Load TX buffer and increment TX byte counter
}
else
{
UCB0CTL1 |= UCTXSTP; // I2C stop condition
UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag
sentMasterData = TRUE;
__bic_SR_register_on_exit(LPM0_bits + GIE); // Exit low power mode
}
}
}
break;
}
default: break;
}
}
The program always seems to fail after the following lines in the TXIFG case block:
if (rxMasterCount > 0)
{
UCB0IFG &= ~UCTXIFG;
UCB0CTL1 &= ~UCTR; // Enter reading mode
UCB0CTL1 |= UCTXSTT; // I2C start condition
...I don't understand how this could first time but not the second!
Can anyone tell me what is wrong?