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.

Using UCNACKIE in I2C comms



I've noticed that in most of the I2C example code I've looked at (see below) that the function TI_USCI_I2C_notready() is called to wait before either transmitting or receiving on the i2c bus.  Every time its called within a while loop, like this: 
while ( TI_USCI_I2C_notready() );         // wait for bus to be free

So, this means that if the UCBBUSY bit ever gets stuck high, the code will be forever stuck in this while loop.  I figured it would be good code practice to provide an out.  
My question is, is that why the UCNACKIE interrupt is enabled each time before a TX or RX?  If so, how is that interrupt handled?  None of the example code shows any reference to an ISR for this particular case.

Any info would be great,
Thanks! 

http://www.ti.com/mcu/docs/litabsmultiplefilelist.tsp?sectionId=96&tabId=1502&literatureNumber=slaa382&docCategoryId=1&familyId=342

  • Hello,

    I do not know if this is answering your question you would like to, but as i am also using this code I will post some of my experience.

    I did use the UCBBUSY while-loop as well, and I got stuck a lot of times in it, i cannot exactly tell you why, for me it seems to be related with my DCO-settings, but this might only be in my specific code.

    Now I did some work around, I have yet to evaluate the whole thing, but right now it seems to be working properly :)

    The family user guide posts, that the UCBBUSY bit is only set inbetween a START-condition and a STOP-condition. So i did introduce a help_variable which asks if a STOP-condition is sent or not, after the STOP the I2C did finish anyway so my code is something like:

        TI_USCI_I2C_transmit(2,&MBSpeicher[0]);       // start transmitting
        while ( I2C_BUSY );

    and in the interrupt, I did highlight the crucial parts:

    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
      if (IFG2 & UCB0RXIFG){
        if ( byteCtr == 0 ){
          UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
          *TI_receive_field = UCB0RXBUF;
          TI_receive_field++;
          I2C_BUSY = 0;
        }
        else {
          *TI_receive_field = UCB0RXBUF;
          TI_receive_field++;
          byteCtr--;
        }
      }
      else {
        if (byteCtr == 0){
          UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
          I2C_BUSY = 0;
          IFG2 &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
        }
        else {
          UCB0TXBUF = *TI_transmit_field;
          TI_transmit_field++;
          byteCtr--;
        }
      }
    }

    Of course then the code gets stuck untill the whole data was sent or received, which has to be noticed if working with time crucial code.

    Perhaps this might help you too.

    Greetings.

  • Hi,

    That seems like a possible work around, however, it assumes that you only check to see if the bus is busy after you've called your transmit or receive function.  It seems more prudent to check if the bus is busy before you initiate a TX or RX. The example code we are both looking at calls the wait-for-bus-to-be-free loop before each time a TX or RX function is called (as seen below).  

    Is this just a bad or incomplete example or am I missing something?

    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT

    BCSCTL1 = CALBC1_8MHZ;
    DCOCTL = CALDCO_8MHZ;

    _EINT();

    TI_USCI_I2C_transmitinit(0x50,0x12); // init transmitting with USCI
    while ( TI_USCI_I2C_notready() ); // wait for bus to be free
    if ( TI_USCI_I2C_slave_present(0x50) ) // slave address may differ from
    { // initialization
    TI_USCI_I2C_receiveinit(0x50,0x12); // init receiving with USCI
    while ( TI_USCI_I2C_notready() ); // wait for bus to be free
    TI_USCI_I2C_receive(4,store);
    while ( TI_USCI_I2C_notready() ); // wait for bus to be free

    TI_USCI_I2C_transmitinit(0x50,0x12); // init transmitting with
    while ( TI_USCI_I2C_notready() ); // wait for bus to be free
    TI_USCI_I2C_transmit(4,array); // start transmitting
    }

    LPM3;

    }
  • If you're the one and only master on teh I2C bus (whcih the software cannot know, btu the coder should know), then you can assume that the busy bit is always clear if you're not currently in a transfer. Or, if it isn't, that you coded something wrong. But then, the solution is simple: send a stop.

    If someone holds the clock or data line low externally, There' s nothing you can do anyway: the bus is unusable then.

    It's a good idea to have some panic strategy then. e.g. the following:

    timeout = 100;
    while ( timeout && TI_USCI_I2C_NOTREADY() ) timeout--;
    if (!timeout) panic!

**Attention** This is a public forum