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.

Intermittant I2C hang issue

I have a script which bangs on one of the I2C buses which we are using to communicate with a smart battery. Usually our driver works perfectly, however once every several thousand transcations, our driver hangs reading from the battery while waiting for the START bit to clear in UCB1CTL1. Here is the main code for our I2C0_TransmitReceive2() function:

if((countTX > 0) && (countRX > 0)){

      UCB1CTL1 |= UCSWRST;                              // hold in reset
      UCB1I2CSA = address;                              // Set slave address

      gI2CState[1].pBufferTX = gI2C0TXBuffer2;
      gI2CState[1].countTX = countTX;
      gI2CState[1].pBufferRX = pbufferRX;
      gI2CState[1].countRX = countRX;
      gI2CState[1].pCallBack = pCallBack;

      UCB1CTL1 &= ~UCSWRST;                             // Clear SW reset to enable port
      UCB1IE = UCNACKIE + UCSTPIE + UCTXIE + UCRXIE;    // Enable NAK, STOP, TX and RX interrupts
      UCB1CTL1 |= UCTR + UCTXSTT;                       // set to transmit and start bit
      result = true;
  }

And heres the ISR code:

#pragma vector = USCI_B1_VECTOR
__interrupt void I2C1_ISR(void)
{

  uint32 value = 0;
  switch(__even_in_range(UCB1IV,12))
  {
    case  0:                                      // No interrupts
      break;
    case  USCI_I2C_UCALIFG:                       // Arbitration Lost, not used
      break;
    case  USCI_I2C_UCNACKIFG:                     // Not acknowledged
      UCB1CTL1 |= UCTXSTP;                        // send stop condition
      UCB1IFG &= ~UCNACKIFG;
      //!todo  MARK may need to SWI here as well to release resources
      break;
    case  USCI_I2C_UCSTTIFG:                      // START Condition
      break;
    case  USCI_I2C_UCSTPIFG:                      // STOP Condition
      break;
    case USCI_I2C_UCRXIFG:                        // complete character recieved
      gI2CState[1].countRX--;                     // Decrement RX byte counter
      if (gI2CState[1].countRX) {
        value = UCB1RXBUF;
        *gI2CState[1].pBufferRX++ = value;
        if (gI2CState[1].countRX == 1) {          // send stop on before last receive
          UCB1CTL1 |= UCTXSTP;
        }
      }
      else {
         value = UCB1RXBUF;
        *gI2CState[1].pBufferRX = value;
         I2C0_SWI();
      }
      break;
    case USCI_I2C_UCTXIFG:                        // transmit
      if (gI2CState[1].countTX) {                 // Check TX byte counter
          gI2CState[1].countTX--;                 // Decrement TX byte counter
          UCB1TXBUF = *gI2CState[1].pBufferTX++;  // Load TX buffer
      }
      else {                                      // terminate when all bytes sent, do not Break before restart sent
          if(gI2CState[1].countRX) {
              UCB1CTL1 &= ~UCTR;                  // change to receive

              SetConditionalFlag(kErrI2CTimeout);
              while(UCB1CTL1 & UCTXSTP);
              ResetConditionalFlag(kErrI2CTimeout);

              UCB1CTL1 |= UCTXSTT;                // I2C re-start condition
              //single bytes need to be polled to ensure proper stop
              if ( gI2CState[1].countRX == 1 ) {
                  SetConditionalFlag(kErrI2CTimeout);
                  while (UCB1CTL1 & UCTXSTT);     // poll for start clear
                  ResetConditionalFlag(kErrI2CTimeout);

                  UCB1CTL1 |= UCTXSTP;            // I2C stop condition
              }
          } else {
              UCB1CTL1 |= UCTXSTP;                // send stop condition
              UCB1IFG &= ~UCTXIFG;                // Clear USCI_B0 TX int flag
              I2C0_SWI();
          }
      }
      break;
    default:
      break;
    }
}

When the bus hangs, it hangs in the "while (UCB1CTL1 & UCTXSTT); " line in the "USCI_I2C_UCTXIFG" case. When this happens the bus indicates the NACK flag and SCL low flags are set. I have setup a spare GPIO to go high before the loop and go low after the loop and setup my scope to trigger if the pulse width is too wide. What I'm seeing is that it looks like that when everything works, the bus changes to RX mode while the last data byte is being TX but when it hangs, the last data byte gets retransmitted before thew bus switches to RX mode. I'm guessing another higher priority interrupt is firing. I have attached captures of when everything works and when it hangs below. I would appreciate if anyone would have some insight as to what I can do to prevent this from happening. TIA.

1106.tek00003.tif

1376.tek00004.tif

**Attention** This is a public forum