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: I2C ISRs not running. GIE bit is set, TXIE is set, TXIFG is set

Part Number: MSP430G2553
Other Parts Discussed in Thread: TMP100, MSP430WARE

In my code I have enabled ALL of the USCI_B module's interrupts, set the GIE bit and have an ISR with the correct interrupt vector. (used the vector and ISR name from TI's example code) Currently I use polling to implement I2C. However I'd like to do it the proper way using interrupts to save power since this will a battery operated device.

Using polling, I've verified that the corresponding TX flag is being set and with a logic analyzer I verified that the slave acknowledges each byte. I can't understand why the ISR won't run. Relevant code blocks below:

USCI_B initialization block:

// Initialize USCI_B0 to standard speed I2C master mode. Pins are already assigned to SCL and SDA.
UCB0CTL0 = UCMST | UCMODE_3 | UCSYNC;                    // 7-bit addressing, single master
UCB0CTL1 |= UCSSEL_2 | UCTR | UCSWRST;                     // Transmitter mode, sourced from SMCLK
UCB0BR1 = 0;                                                                                // set the upper baud rate register to 0
UCB0BR0 = I2C_CLOCK_DIV;                                                   // 100KHz bus frequency, sourced from 16MHz SMCLK divided by 40
UCB0STAT = 0;                                                                               // reset state change flags
IFG2 &= ~(UCB0TXIFG | UCB0RXIFG);                                     // reset the transmit and recieve flags
UCB0I2CIE = UCNACKIE | UCSTPIE | UCSTTIE | UCALIE; // Enable interrupts for all bus state changes
IE2 |= UCB0RXIE | UCB0TXIE;                                                   // Enable interrupts for I2C receive and transmit (transmit enabled on default)
UCB0I2CSA = 0;                                                                            // Initialize slave address to 0
UCB0CTL1 &= ~UCSWRST;                                                       // Reset UCSWRST, starting I2C communication
__bis_SR_register(GIE); // enable global interrupts

I2C Bus Initialization loop:

while (~status & MCP23018_INIT) {                                                // while the MCP23018 is NOT initialized
      if (IFG2 & UCB0TXIFG || interrupt_test > 0) {                           // if it is time to load the TXBUFFER
        if (~status & MCP23018_INIT) {                                               // if the MCP23018 is NOT initialized:
          if (i2c_i > OLATB+1) {                                                               // if this is the bit after the last register:
            i2c_i = 0;                                                                                   // reset i2c iterator
            UCB0CTL1 |= UCTXSTP;                                                     // transmit STOP signal
            status |= MCP23018_INIT;
          }
          UCB0TXBUF = MCP23018_INIT_DATA[i2c_i];                  // put the corresponding byte from init data array into the tx buffer
          i2c_i++;                                                                                      // increment the i2c iterator
          }
      } else if (UCB0I2CSA == 0) {                                                     // otherwise: if the slave address is 0
        UCB0I2CSA = MCP23018_OPCODE;                                 // load slave address+0 for write mode
        UCB0CTL1 |= UCTXSTT;                                                        // send I2C start condition
      } else if (UCB0STAT & UCNACKIFG) {                                   // if NACK was recieved
        UCB0STAT &= ~UCNACKIFG;                                              // clear the flag
        i2c_i = 0;                                                                                    // reset address iterator to 0
        UCB0CTL1 |= UCTXSTT;                            // set a start condition
        IFG2 |= UCB0TXIFG;                              // set the TX flag
      }
//__bis_SR_register(LPM0_bits + GIE);                 // turn off the CPU to save power, global interrupt enabled } P1OUT |= BIT0; // light up LED1 when initialized

I2C Data ISR:

#pragma vector=USCIAB0TX_VECTOR                       // since the USCI_B is in I2C mode, this is the I2C data ISR
__interrupt void USCIAB0TX_ISR(void) {                  // when the USCI_B TX register is empty or RX register is full
    __bic_SR_register_on_exit(LPM0_bits);               // clear the bits to wake up the CPU
}                                                       // return to the main loop

I2C State ISR:

#pragma vector=USCIAB0RX_VECTOR                       // since the USCI_B is in I2C mode, this is the I2C state ISR
__interrupt void USCIAB0RX_ISR(void) {                  // when the I2C state changes
    __bic_SR_register_on_exit(LPM0_bits);               // clear the bits to wake up the CPU
}                                                       // return to the main loop

  • My first recommendation is that you review the I2C examples provided by TI and sourced through the online community, the code excerpts shown vary greatly from the typical interrupt implementation.

    Regards,
    Ryan
  • I have read the official TI I2C examples for the MSP430G2xx3 series. I've read all 13 I2C examples, the TimerA examples and the P1 examples. I have not been able to test any of the I2C examples as I don't own any other MSP430G2553s, any TMP100 sensors, PCF8574s or DAC8751s.

    My implementation IS different and more complicated, because I cannot get the ISRs to run! Therefore cannot put any useful code in the ISRs. At the moment, I simply have the I2C Data and I2C Status ISRs attempt to wake up the CPU, in an attempt to test if I can get them to run. As you might have noticed, __bis_SR_register(LPM0_bits + GIE); was commented out, because the ISRs would not wake up the CPU.

    My I2C implementation gets the job done, but inefficiently as the CPU is always polling the interrupt flags. I'm simply trying to figure out why my TimerA ISRs run, the Port 1&2 ISRs run but the I2C ISRs refuse to run.
  • Oops, I forgot to include the logic analyzer screenshot, here it is: running at 100KHz, the I2C bus works exactly as expected and the MCP23018 is initialized to the correct state, however the ISRs were no help. I had to a while loop to not only to initialize the MCP, but to send and receive data from it.

  • Please take msp430g2xx3_uscib0_i2c_06.c (or 08.c), modify it for your I2C clock frequency and slave address, and confirm that the slave responds to its address but that the UCSCIAB0TX_ISR is never entered.

    Regards,
    Ryan
  • This was the result of the code below:

    /* --COPYRIGHT--,BSD_EX
    * Copyright (c) 2012, Texas Instruments Incorporated
    * All rights reserved.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    *
    * * Redistributions of source code must retain the above copyright
    * notice, this list of conditions and the following disclaimer.
    *
    * * Redistributions in binary form must reproduce the above copyright
    * notice, this list of conditions and the following disclaimer in the
    * documentation and/or other materials provided with the distribution.
    *
    * * Neither the name of Texas Instruments Incorporated nor the names of
    * its contributors may be used to endorse or promote products derived
    * from this software without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    *******************************************************************************
    *
    * MSP430 CODE EXAMPLE DISCLAIMER
    *
    * MSP430 code examples are self-contained low-level programs that typically
    * demonstrate a single peripheral function or device feature in a highly
    * concise manner. For this the code may rely on the device's power-on default
    * register values and settings such as the clock configuration and care must
    * be taken when combining code from several examples to avoid potential side
    * effects. Also see www.ti.com/grace for a GUI- and www.ti.com/msp430ware
    * for an API functional library-approach to peripheral configuration.
    *
    * --/COPYRIGHT--*/
    //******************************************************************************
    // MSP430G2xx3 Demo - USCI_B0 I2C Master TX single bytes to MSP430 Slave
    //
    // Description: This demo connects two MSP430's via the I2C bus. The master
    // transmits to the slave. This is the master code. It continuously
    // transmits 00h, 01h, ..., 0ffh and demonstrates how to implement an I2C
    // master transmitter sending a single byte using the USCI_B0 TX interrupt.
    // ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = ~1.2MHz
    //
    // *** to be used with "msp430g2xx3_uscib0_i2c_07.c" ***
    //
    // /|\ /|\
    // MSP430G2xx3 10k 10k MSP430G2xx3
    // slave | | master
    // ----------------- | | -----------------
    // -|XIN P1.7/UCB0SDA|<-|---+->|P1.7/UCB0SDA XIN|-
    // | | | | |
    // -|XOUT | | | XOUT|-
    // | P1.6/UCB0SCL|<-+----->|P1.6/UCB0SCL |
    // | | | |
    //
    // D. Dang
    // Texas Instruments Inc.
    // February 2011
    // Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
    //******************************************************************************
    #include <msp430.h>

    unsigned char TXData;
    unsigned char TXByteCtr;

    int main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0
    P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0
    UCB0CTL1 |= UCSWRST; // Enable SW reset
    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
    UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
    UCB0BR0 = 40; // fSCL = SMCLK/12 = ~100kHz
    UCB0BR1 = 0;
    UCB0I2CSA = 32; // Slave Address is 32
    UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
    IE2 |= UCB0TXIE; // Enable TX interrupt

    TXData = 0x00; // Holds TX data

    while (1)
    {
    TXByteCtr = 1; // Load TX byte counter
    while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
    UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
    __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
    // Remain in LPM0 until all data
    // is TX'd
    TXData++; // Increment data byte
    }
    }

    //------------------------------------------------------------------------------
    // The USCIAB0TX_ISR is structured such that it can be used to transmit any
    // number of bytes by pre-loading TXByteCtr with the byte count.
    //------------------------------------------------------------------------------
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(USCIAB0TX_VECTOR))) USCIAB0TX_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
    if (TXByteCtr) // Check TX byte counter
    {
    UCB0TXBUF = TXData; // Load TX buffer
    TXByteCtr--; // Decrement TX byte counter
    }
    else
    {
    UCB0CTL1 |= UCTXSTP; // I2C stop condition
    IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag
    __bic_SR_register_on_exit(CPUOFF); // Exit LPM0
    }
    }

    From the logic analyzer it looks like the MSP took a nap and never woke up. Could this be the behavior described by USCI29 in SLAZ440H?

  • Solved my own question, when debugging I saw the PC was caught in the TRAPINT_ISR exactly like specified in the erratasheet. Work around #1 is guess what... poll the affected interrupts... Just have to live with the inefficiency then.

  • I'm glad to see that you've found the source of your issues although it is unfortunately from an errata. Thank you for providing your solution to the E2E community. Hopefully you will still be able to minimize your application's power consumption by shortening the amount of time spent communicating through I2C.

    Regards,
    Ryan
  • I'm glad too Ryan, perhaps the USCI's interrupt issue is actually a blessing in disguise. With the module active, the lowest power state the MSP430 can enter is LPM0. When in LPM0 the MSP still uses a whole order of magnitude more current than my intended state of LPM3.

    The USCI module's issue isn't so bad after all.

**Attention** This is a public forum