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.

MSP430F1611: I2CIE Register writing problem

Part Number: MSP430F1611
Other Parts Discussed in Thread: MSP430F148, MSP430F5335

Hello,  

I am using the MSP430F1611 in a simple application which provides i2c to RS232/485 conversion.  

I am having a problem in the i2c interrupt routine where I am writing to the I2CIE register to clear the TXRDYIE bit.  For some reason, the bit does not always clear properly.  I first clear the bit, then I added a nop just for good measure, then I am reading the bit again, and clearing it again if it was not already cleared.  For some reason, the bit is not being cleared on the first attempt sometimes.  I am using IAR EW430 7.10.3.  Here is the code:

#pragma vector = USART0TX_VECTOR                
__interrupt void slave_byte(void){               // slave i2c interface
  switch (__even_in_range(I2CIV, 0x10)) {                      // trigger on interrupt
  case I2CIV_NONE:                              // (0x0000u)    /* I2C interrupt vector: No interrupt pending */
    break;
  case I2CIV_AL:                                // (0x0002u)    /* I2C interrupt vector: Arbitration lost (ALIFG) */
    break;
  case I2CIV_NACK:                              // (0x0004u)    /* I2C interrupt vector: No acknowledge (NACKIFG) */
    break;
  case I2CIV_OA:                                // (0x0006u)    /* I2C interrupt vector: Own address (OAIFG) */
      i2cbuff_p = 0;                            // init to first char in i2c buffer
      break;
  case I2CIV_ARDY:                              // (0x0008u)    /* I2C interrupt vector: Access ready (ARDYIFG) */
      break;
  case I2CIV_RXRDY:                             // (0x000Au)    /* I2C interrupt vector: Receive ready (RXRDYIFG) */
      i2cbuff[i2cbuff_p] = I2CDRB;
      if (i2cbuff_p < MAX_I2C_BUFF_P)
        if (++i2cbuff_p == 2) {
          I2CIE = (OAIE | RXRDYIE);             // disable tx interrupt to provide clock stretching and trigger process_i2c   FIRST ATTEMPT TO CLEAR TXRDYIE BIT
          __no_operation();                               
          if ((I2CIE & TXRDYIE) != 0)            // CHECK TO SEE IF BIT ACTUALLY CLEARED
            I2CIE = (OAIE | RXRDYIE);             // disable tx interrupt to provide clock stretching and trigger process_i2c  I AM SETTING A BREAK POINT HERE AND IT

                                                                    // IS STOPPING HERE ON OCCASTION WITH THE TXRDYIE BIT STILL SET IF I INSPECT IN THE REGISTERS IN IAR.
        }
      break;
  case I2CIV_TXRDY:                             // (0x000Cu)    /* I2C interrupt vector: Transmit ready (TXRDYIFG) */
      I2CDRB = i2c_tx_char;                     // copy outgoing byte
      break;
  case I2CIV_GC:                                // (0x000Eu)    /* I2C interrupt vector: General call (GCIFG) */
      break;
  case I2CIV_STT:                               // (0x0010u)    /* I2C interrupt vector: Start condition (STTIFG) */
      break;
  } // end switch
} // end receive bit interrupt

Any suggestions would be greatly appreciated.

Thanks,

Greg Dunn

  • Hello Greg,

    As this might be a compiler issue have you tried using I2CIE &= ~TXRDYIE;? Does the code behave differently in CCS? Have you tried using a longer delay than one no-op? The USART peripheral is quite old and contains several errata related to the I2C block, for this reason a MSP430 with an (e)USCI is recommended. Since TXRDYIE is ignored when TXDMAEN = 1, have you considered using the DMA to transfer all of your bytes?

    Regards,
    Ryan
  • Hello Ryan,

    Thanks for your reply.  The first version of my code was simply I2CIE &= ~TXRDYIE.  This is when I first suspected the problem, as I seemed to be missing seeing the flag cleared in the main loop of my application.  

    I then updated my code to the following to try and confirm my suspicion and discovered that I was actually hitting a breakpoint inside the if statement:

    I2CIE &= ~TXRDYIE

    if ((I2CIE & TXRDYIE) != 0)

    I2CIE &= ~TXRDYIE

    My latest version of the code which I ran all last night and have not seen any errors is as follows:

              I2CIE = (OAIE | RXRDYIE);             // disable tx interrupt to provide clock stretching and trigger process_i2c
              I2CIE = (OAIE | RXRDYIE);             // disable tx interrupt to provide clock stretching and trigger process_i2c
              I2CIE = (OAIE | RXRDYIE);             // disable tx interrupt to provide clock stretching and trigger process_i2c

    I also have another piece of code in the main loop of the program which checks for TXRDYIE to be low, does some processing to determine if a value needs to be prepared for transmit during the next i2c read command, then sets the TXRDYIE flag back high to allow transmitting.  I also found that attempting to set the flag only once was not reliable either.  I also have three set commands in my latest version as follows:

          I2CIE = (OAIE | RXRDYIE | TXRDYIE);             // enable Transmit Byte Interrupt to release bus hold and continue
          I2CIE = (OAIE | RXRDYIE | TXRDYIE);             // enable Transmit Byte Interrupt to release bus hold and continue
          I2CIE = (OAIE | RXRDYIE | TXRDYIE);             // enable Transmit Byte Interrupt to release bus hold and continue

    I have not really tried using more than one no-op between statements.

    As far as I can tell so far, the three attempts seem to be working, but it still doesn't give me the confidence level I would like.

    Unfortunately, we have about 4000 of these devices already deployed to various locations in the field.  We have not seen any field issues at this point as they are all running with an older piece of hardware as the i2c master device.  We have recently released a new piece of hardware that is an upgrade for the i2c master device.  This newer master hardware is much faster and uses repeated starts on the i2c bus.  I have been working on the firmware in the i2c slave (MSP430F1611) to make it more compatible with the new master hardware when I discovered the issue.

    I have not tried in CCS as we have been using the IAR IDE for about 17 years and have several boards that use the MSP430F148, MSP430F1611 and MSP430F5335.  I will try to give CCS a shot if it doesn't take too long to install and get up and running.

    I had already reviewed the Errata for the 1611 and didn't see anything that specifically indicated a problem like I am observing.  I have considered trying DMA also, but will have to do some thinking to see if I can fit it into the i2c model that we have to support for backward compatibility.  I may give it a try.

    As I mentioned above, the code seems to be functioning properly with the three attempts.  Do you have any other information on the processor that would indicate that a problem may occur like I am seeing?  Do you have any other recommendations that you feel I should include in my current code version that may help insure reliability?

    Thanks,

    Greg

  • Hi Greg,

    Thank you for the detailed update on your issue and providing more history on this use case. Since you have stated that the master is now running much faster and using repeated starts I am wondering if there is a race condition involved where additional bytes are being received (hence raising flags and making changes to I2C registers) as you attempt to finish servicing the ISR. Would it be possible to increase your processor frequency to 8 MHz and reduce the number of instructions in your I2CIV_RXRDY case?

    Regards,
    Ryan
  • Ryan,

    We are currently running with a 3.579545 MHz. I suppose I could try increasing the crystal frequency on my development board as a test, but this would not really be an option with the 4000 units already deployed in the field. I have added debugging code to be able to observe interrupt service code states on my oscilloscope and I didn't really see anything that was an obvious problem other than when the I2CIE flags were not set properly. The latest version of the code has ran with 185000 successful (no failures) Modbus communication sequences over the i2c/RS232 port so maybe the current solution of three attempts will be ok. I will try to finish testing all of the other optional aspects of the code and make sure I don't see anything else. Thank you for your help.

    Greg

**Attention** This is a public forum