Hi,
I seem to be having a similar issue to what a.h. was seeing in this thread:
I am reading several values repeatedly from a BNO055 and occasionally the MSP430 does not send an ack, and just starts repeatedly sending clock data. I am not seeing any issues to relate this to voltage drop however.
I am reading these at 20 Hz and I see a failure every few minutes. Is there a known workaround for this bug? It was my understanding that nothing needs to be done in receive mode to trigger sending of the ack. Is this correct?
Here is the transaction that is failing:
Here it is more zoomed in on the failed byte:
Here is the same transaction when it is successful:
And zoomed in on one of the bytes:
I have attached my i2c code.
#include "i2c_driver.h" #include "Boards/hal.h" #include "driverlib.h" #ifdef I2C_USCI_INT_VECTOR volatile bool i2cTransactionInProgress = false; const uint8_t* i2cTxBuffer; uint8_t* i2cRxBuffer; volatile unsigned int writeLength; volatile unsigned int readLength; volatile bool* statusFlag; void initI2C(void) { GPIO_setAsPeripheralModuleFunctionInputPin(I2C_PORT, I2C_SCL); GPIO_setAsPeripheralModuleFunctionInputPin(I2C_PORT, I2C_SDA); USCI_B_I2C_initMasterParam i2cParams = {0}; i2cParams.dataRate = USCI_B_I2C_SET_DATA_RATE_400KBPS; i2cParams.i2cClk = UCS_getSMCLK(); i2cParams.selectClockSource = USCI_B_I2C_CLOCKSOURCE_SMCLK; USCI_B_I2C_initMaster(I2C_USCI_MODULE, &i2cParams); USCI_B_I2C_enableInterrupt(I2C_USCI_MODULE, USCI_B_I2C_NAK_INTERRUPT); } bool isI2CBusy(void) { return i2cTransactionInProgress; } int startI2CReadTransaction(uint8_t* receiveBuffer, uint8_t slaveAddress, uint8_t regAddress, unsigned int length, volatile bool* completedFlag) { if (isI2CBusy()) { return -1; } i2cTransactionInProgress = true; statusFlag = completedFlag; *statusFlag = false; readLength = length; i2cRxBuffer = receiveBuffer; USCI_B_I2C_setSlaveAddress(I2C_USCI_MODULE, slaveAddress); USCI_B_I2C_setMode(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_MODE); USCI_B_I2C_enable(I2C_USCI_MODULE); USCI_B_I2C_disableInterrupt(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_INTERRUPT); USCI_B_I2C_clearInterrupt(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_INTERRUPT); USCI_B_I2C_masterSendMultiByteStart(I2C_USCI_MODULE, regAddress); // Wait for transmit flag to be set while (!USCI_B_I2C_getInterruptStatus(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_INTERRUPT)) { } USCI_B_I2C_masterReceiveMultiByteStart(I2C_USCI_MODULE); USCI_B_I2C_enableInterrupt(I2C_USCI_MODULE, USCI_B_I2C_RECEIVE_INTERRUPT); return 0; } int startI2CWriteTransaction(const uint8_t* transmitBuffer, uint8_t slaveAddress, uint8_t regAddress, unsigned int length) { if (isI2CBusy()) { return -1; } i2cTransactionInProgress = true; i2cTxBuffer = transmitBuffer; writeLength = length; USCI_B_I2C_setSlaveAddress(I2C_USCI_MODULE, slaveAddress); USCI_B_I2C_setMode(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_MODE); USCI_B_I2C_enable(I2C_USCI_MODULE); // Enable interrupts here and handle the rest of the transaction using them // to free up the processor for other tasks USCI_B_I2C_clearInterrupt(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_INTERRUPT); USCI_B_I2C_enableInterrupt(I2C_USCI_MODULE, USCI_B_I2C_TRANSMIT_INTERRUPT); // This function sends a start command, polls the TX IFG, and then writes // the byte to the TX register USCI_B_I2C_masterSendMultiByteStart(I2C_USCI_MODULE, regAddress); return 0; } int I2CBlockingWriteTransaction(const uint8_t* transmitBuffer, uint8_t slaveAddress, uint8_t regAddress, unsigned int length) { int rv; rv = startI2CWriteTransaction(transmitBuffer, slaveAddress, regAddress, length); while (isI2CBusy()) { } return rv; } bool i2cISR(uint16_t usciModule, int ucbIv) { switch (ucbIv) { case 0x02: // Arbitration Lost break; case 0x04: // Nack // A NAK was received from a slave device // TODO: We probably should handle NAKs somehow, KJL USCI_B_I2C_masterSendMultiByteStop(usciModule); i2cTransactionInProgress = false; break; case 0x06: // Start // Should not get here since the START interrupt is disabled and // for slaves only break; case 0x08: // Stop // Should not get here since the STOP interrupt is disabled and // for slaves only break; case 0x0A: // Data Received // Received data is ready to be read from UCBxRXBUF into the recieve // buffer // Send a stop command if the last byte is in the RX buffer if (readLength == 1) { USCI_B_I2C_masterReceiveMultiByteStop(usciModule); } *i2cRxBuffer = USCI_B_I2C_masterReceiveMultiByteNext(usciModule); i2cRxBuffer++; readLength--; if (readLength == 0) { i2cTransactionInProgress = false; *statusFlag = true; return true; } break; case 0x0C: // TX Buffer Empty // The I2C bus is ready to transmit data written into the UCBxTXBUF if (writeLength == 0) // There is no data left to be written { USCI_B_I2C_masterSendMultiByteStop(usciModule); i2cTransactionInProgress = false; return true; } else { USCI_B_I2C_masterSendMultiByteNext(usciModule, *i2cTxBuffer); writeLength--; i2cTxBuffer++; } break; } return false; // stay in LPM } #endif
#include "Boards/hal.h" #include "SerialCommunications/spi.h" #include "driverlib.h" #include "i2c_driver.h" #ifndef VS_CODE #pragma vector = USCI_B1_VECTOR __interrupt void USCI_B1_ISR(void) #else void USCI_B1_ISR(void) #endif { #ifdef I2C_USCI_INT_VECTOR if (UCB1CTL0 & UCMODE_3 == UCMODE_3) { // USCI module is in I2C Mode if (i2cISR(USCI_B1_BASE, UCB1IV)) { __bic_SR_register_on_exit(LPM0_bits); } } else { // USCI module is in SPI mode if (spiISR(USCI_B1_BASE, UCB1IV)) { __bic_SR_register_on_exit(LPM0_bits); } } #else if (spiISR(USCI_B1_BASE, UCB1IV)) { __bic_SR_register_on_exit(LPM0_bits); } #endif } #ifndef VS_CODE #pragma vector = USCI_A1_VECTOR __interrupt void USCI_A1_ISR(void) #else void USCI_A1_ISR(void) #endif { // USCI module is in SPI mode if (spiISR(USCI_A1_BASE, UCA1IV)) { __bic_SR_register_on_exit(LPM0_bits); } } #ifdef MPU #ifndef VS_CODE #pragma vector = USCI_B0_VECTOR __interrupt void USCI_B0_ISR(void) #else void USCI_B0_ISR(void) #endif { #ifdef I2C_USCI_INT_VECTOR if (UCB1CTL0 & UCMODE_3 == UCMODE_3) { // USCI module is in I2C Mode if (i2cISR(USCI_B0_BASE, UCB0IV)) { __bic_SR_register_on_exit(LPM0_bits); } } else { // USCI module is in SPI mode if (spiISR(USCI_B0_BASE, UCB0IV)) { __bic_SR_register_on_exit(LPM0_bits); } } #else if (spiISR(USCI_B0_BASE, UCB0IV)) { __bic_SR_register_on_exit(LPM0_bits); } #endif } #ifndef VS_CODE #pragma vector = USCI_A0_VECTOR __interrupt void USCI_A0_ISR(void) #else void USCI_A0_ISR(void) #endif { // USCI module is in SPI mode if (spiISR(USCI_A0_BASE, UCA0IV)) { __bic_SR_register_on_exit(LPM0_bits); } } #endif