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.

MSP430G2553 - I²C problem - Master receiver does not work - RX interrupt function is not called - TX instead

Other Parts Discussed in Thread: MSP430G2553

Hi @ all!

I really got a big problem with my MSP430G2553 device. I'm using the I²C to communicate to either an DAC and an ADC. I have written a code that communicates to each device in "ping pong mode" - therefore i built up a state-machine for each device which are sequently called by the main. Once they are called, the communication runs interrupt driven. Sending data to the DAC and to the ADC (config-data) works without problems, but receiving data from the ADC aborts every time.

The following data is transfered until it stops:

START -> ADDRESS with Write-Bit -> ACK -> 1st read data byte -> ACK -> 7 bits of the 2nd data byte........then SCL and SDA both go low and stay there.

If I step through the debugger I can see, that the ISR for the RX interrupt is never called. Instead the TX-ISR comes up and the controller never leaves this ISR so that the program stops here.

The funny thing about it: UCB0TXIE is NOT set. After sending the start both, RXIFG and TXIFG are set - is that normal? Anyway the TX-ISR should not be called!! What's wrong? I read the device errata and topic USCI30 could be my problem...maybe. The workaround says, that the received byte should be fetched by a ISR and that is exactly what I do. My receive-buffer for the data is not filled, too, because this would be done in the ISR. But it is very strange, that the state-machine of the USCI requests further bytes without the RX-buffer read.

Is there someone having the same problem? I'm working on that problem for about 2 days now and I'll get crazy!

Here is some code:

case ADC_STATE__SEND_START:
    {
      UCB0CTL1 |= UCSWRST;
      UCB0I2CSA = ( (MCP3425_DEVICE_CODE | MCP3425_DEVICE_ADDRESS) >> 1 );
      UCB0CTL1 &= ~UCSWRST;

      adc_control.bytecounter = 0;

      adc_control.bytecount = 3;
      IFG2 &= ~UCB0RXIFG;
      IE2 |= UCB0RXIE;
      adc_control.state = ADC_STATE__RECEIVING_DATA;
      UCB0CTL1 &= ~UCTR;
      UCB0CTL1 |= UCTXSTT;

      break;
    }

and the RX-ISR:

// USCI_A/B0 receive interrupt service routine
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR( void )
{
  if( IFG2 & UCB0RXIFG )
  {
    if( i2c_sm_control_flags == ADC_SM_ACTIVE )
    {
      switch( adc_control.state )
      {
        case ADC_STATE__RECEIVING_DATA:
        {
          if( adc_control.bytecounter < adc_control.bytecount )
          {
            adc_control.adc_data[adc_control.bytecounter++] = UCB0RXBUF;
          }
          else
          {
            IFG2 &= ~UCB0RXIFG;
            IE2 &= ~UCB0RXIE;
            adc_set_flag( ADC_FLAG__DATA_TO_PROCESS );
            adc_change_state( ADC_STATE__WAIT_FOR_STOP_COMPLETE );
            UCB0CTL1 |= UCTXSTP;
          }

          break;
        }

        default: break;
      }
    }
  }
}

But as I said, only the TX-ISR is entered without TXIE enabled :-(

  • OK, another strange thing...

    now I added some code that waits for a key-press before the main program starts. The controller runs to this point every time I press the button which means that the controller restarts after the aborted transmission. I checked the transmission again and it is still after the 7th bit of the second data byte that comes from the adc. I marked out the TX-ISR which shouldnt be a problem because normally the TX-ISR should not be called. There is no TXIE enabled.

    Why? Seems as if the controller runs to an address that is not valid or something. Any ideas?

  • I had a look at the code axamples for that device and I don't understand why they are using the TX-ISR after enabling the RXIE. And I can't find anything on that in the documentation, too.

    Is there a hidden note you have to know to get the thing running. Here is my opinion of how it should work:

    1) I set the address for the device, clear the transmit-bit in UCB0CTL1. Before sending the start-condition I clear the UCB0IFG (just to be sure) and enable UCB0RXIE.

    2) Then I send the start condition and the controller transmits the address and waits for the ACK by the slave.

    3) After the ACK, the device automatically requests the first data-byte and acknoledges it. The received byte causes the RX-ISR to pop up and I can store the received byte.

    4) The controller continues requesting further bytes until I send the stop-condition.

    5) I disable the RXIE and thats it.

    Is anything wrong in there?

  • Hi @ all!

    Everything works fine now. Using TX-ISR instead of RX-ISR even for receiving solved the problem. If anyone knows why TX is used for receiving bytes and why RXIFG calls the TX-ISR...let me know.

  • Dennis E. said:
    If anyone knows why TX is used for receiving bytes and why RXIFG calls the TX-ISR...let me know.

    In opposition to SPi and UART mdoe, I2C has more than jsu tRX and TX interrupts. So someone decided it would be smart to put RX and TX into one ISR, and the status change interrupts into the other one.

    Thsi makes some sense since I2C has unidirectional transactions, so during one transaction, you only get either TX or RX interrupts, but never both.

    This is documented in the users guide, but easy to miss.

**Attention** This is a public forum