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.

Enabling interrupt pins alongside I2C

Hi, I'm trying to work with interrupts and having some difficulty. I made a simple program (not shown) that declares pin 1.7 as an interrupt pin and then makes a pulse counter. When I tap that pin with a 3V supply, the program performs the ISR and then returns to the pulse counter, as it should. However, when I use that same interrupt pin initialization in a program that also uses I2C (below), a very strange thing happens- the program never gets to the while(1) loop and instead seems to get to the line __bis_SR_register(GIE) and then goes back to the beginning of the program and creates this sort of pseudo while loop. Removing the GIE line allows the program to run as normal, but of course interrupts are not enabled. Any suggestions are appreciated. Thanks

#include <msp430x26x.h>
#include <stdlib.h>        //Processor specific definitions
#include <stdio.h>
#include "hardware.h"

unsigned char SADDR, RADDR, TXData, TXData2 = 0x00, temp = 0x00, DRDY;
int j=0, averages[3][3], Sensor_Data[3][3], telemetry = 0x00, Sorted_Data[3][10];
unsigned char RXData[3][6][10];

void I2C_Setup_B1()
{
  UCB1CTL1 |= UCSWRST;                    // Enable SoftWare reset
  UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC;   // Mode: Master, I2C, synchronous
  UCB1CTL1 = UCSSEL_2 + UCSWRST;          // Use SMCLK, keep SW reset
  UCB1BR0 = 2;                            // fSCL = SMCLK/2 = ~200kHz
  UCB1BR1 = 0;
  UCB1CTL1 &= ~UCSWRST;                   // Clear SW reset, resume operation
  UC1IE |= UCB1TXIE;                      // Enable TX interrupt
  UC1IE |= UCB1RXIE;                      // Enable RX interrupt
}

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;               // Stop WDT
 
  P1IE |= 0x80;                           // P1.7 Enable Interrupt
  P1IES &= ~0x80;                         // P1.7 Lo to Hi edge
  P1IFG &= ~0x80;                         // P1.7 IFG cleared

  P3SEL |= 0x06;                          // Assign I2C pins to USCI_B0
  P5SEL |= 0x06;                          // Assign I2C pins to USCI_B0
  P5DIR &= ~0x20;                         // P5.5 is input: DRDY1
 
  P3DIR |= 0x01;                          // P3.0 is an output test pin
  P3OUT &= ~0x01;                         // Set it low
  P3DIR |= 0x08;                          // P3.3 is an output test pin
  P3OUT &= ~0x08;                         // Set it low
 
  I2C_Setup_B1();
 
  SADDR = 0x00F;
  initialize1(SADDR);                     // Initialize sensor 1
 
  force1(SADDR);                          // Force Mode for sensor 1
 
  __bis_SR_register(GIE);                 // General Interrupt Enabled
 
  while (1)
  {
    SADDR = 0x00F;
    RADDR = 0x10;                         // DataX register address
    DRDY = 0x20;
    P3OUT |= 0x08;
    read1_6(SADDR, RADDR, DRDY, j);       // Read sensor 1, put X,Y,Z data in jth col of RXData[0]
    P3OUT &= ~0x08;

    force1(SADDR);                        // Force Mode for sensor 1
  }
}

    //////////////////////////////Functions/////////////////////////////////

#pragma vector = PORT1_VECTOR
__interrupt void Port_1(void)
{
  P3OUT |= 0x01;
  P3OUT &= ~0x01;
  P3OUT |= 0x01;
  P3OUT &= ~0x01;
  telemetry = 0x01;
  P1IFG &= ~0x80;                           // P1.7 IFG cleared
//  __bic_SR_register_on_exit(GIE);
}

void initialize1(unsigned char SADDR)
{
  UCB1I2CSA = SADDR;                      // Slave Address is 00Fh
 
  RADDR = 0x1D;                           // Sensor's CNTL3 register address
  TXData = 0x80;                          // Soft Reset command
  transmit1_1(RADDR, TXData);

  RADDR = 0x1B;                           // Change to CNTL1 register address
  TXData = 0x82;                          // Set Active Mode
  transmit1_1(RADDR, TXData);
 
  RADDR = 0x1C;                           // Change to CNTL2 register address
  TXData = 0x0C;                          // Enable Ready signal
  transmit1_1(RADDR, TXData);
 
  RADDR = 0x5C;                           // Change to CNTL4 register address
  TXData = 0xA0;                          // High-speed measurement mode
  TXData2 = 0x7E;
  transmit1_2(RADDR, TXData, TXData2);
}

void force1(unsigned char SADDR)
{
  UCB1I2CSA = SADDR;                      // Slave Address is 00Fh
    
  RADDR = 0x1D;                           // Change to CNTL3 register address
  TXData = 0x40;                          // Force = 1
  transmit1_1(RADDR, TXData);
}

void transmit1_1(unsigned char RADDR, unsigned char TXData)
{
  UCB1CTL1 |= UCTR;                       // Transmitter Mode
  UCB1CTL1 |= UCTXSTT;                    // I2C start sequence
 
  while (temp == 0x00)
    temp = (UC1IFG & UCB1TXIFG);
  UCB1TXBUF = RADDR;                      // Load TX buffer w/Register ADDR
  temp = 0x00;
 
  while (temp == 0x00)
    temp = (UC1IFG & UCB1TXIFG);
  UCB1TXBUF = TXData;                     // Load TX buffer w/Reset commmand
  temp = 0x00;

  while (temp == 0x00)
    temp = (UC1IFG & UCB1TXIFG);
  UCB1CTL1 |= UCTXSTP;                    // I2C stop condition
  temp = 0x00;
}

void transmit1_2(unsigned char RADDR, unsigned char TXData, unsigned char TXData2)
{
  UCB1CTL1 |= UCTR;                       // Transmitter Mode
  UCB1CTL1 |= UCTXSTT;                    // I2C start sequence
 
  while (temp == 0x00)
    temp = (UC1IFG & UCB1TXIFG);
  UCB1TXBUF = RADDR;                      // Load TX buffer w/Register ADDR
  temp = 0x00;

  while (temp == 0x00)
    temp = (UC1IFG & UCB1TXIFG);
  UCB1TXBUF = TXData;                     // Load TX buffer w/Reset commmand
  temp = 0x00;

  while (temp == 0x00)
    temp = (UC1IFG & UCB1TXIFG);
  UCB1TXBUF = TXData2;                     // Load TX buffer w/Reset commmand
  temp = 0x00;
    
  while (temp == 0x00)
    temp = (UC1IFG & UCB1TXIFG);
  UCB1CTL1 |= UCTXSTP;                    // I2C stop condition
  temp = 0x00;
}

void read1_6(unsigned char SADDR, unsigned char RADDR, unsigned char DRDY, int j)
{
  UCB1I2CSA = SADDR;                      // Slave Address
 
  while ((P5IN&DRDY)==0);                 // Wait for DRDY from sensor 1
 
  UCB1CTL1 |= UCTR;                       // Transmitter Mode
  UCB1CTL1 |= UCTXSTT;                    // I2C start sequence

  while (temp == 0x00)
    temp = (UC1IFG & UCB1TXIFG);            // Wait for TX Interrupt flag
  UCB1TXBUF = RADDR;                      // Load TX buffer w/Register ADDR
  temp = 0x00;
 
  while (temp == 0x00)
    temp = (UC1IFG & UCB1TXIFG);            // Wait for TX Interrupt flag
  UCB1CTL1 |= UCTXSTP;                    // I2C stop condition
  temp = 0x00;
 
  //Receiver Mode

  UCB1CTL1 &= ~UCTR;                      // Master is a receiver
  UCB1CTL1 |= UCTXSTT;                    // Restart

  for (int i=0;i<4;i++)
    {
      while (temp == 0x00)
        temp = (UC1IFG & UCB1RXIFG);          // Wait for RX Interrupt flag
      RXData[0][i][j] = UCB1RXBUF;
      temp = 0x00;
    }
    
    while (temp == 0x00)
      temp = (UC1IFG & UCB1RXIFG);            // Wait for RX Interrupt flag
    RXData[0][4][j] = UCB1RXBUF;
    UCB1CTL1 |= UCTXSTP;                    // I2C stop condition
    temp = 0x00;
    
    while (temp == 0x00)
      temp = (UC1IFG & UCB1RXIFG);            // Wait for RX Interrupt flag
    RXData[0][5][j] = UCB1RXBUF;
    temp = 0x00;
}

  • Hi,

    My guess is that you are enabling the UCB1TXIE and UCB1RXIE in the I2C_Setup_B1 function but you don't have an ISR for these interrupts.  When you enable the GIE it is probably jumping to the interrupt vector for one of these and causing a reset.

    HTH,

    Barry

  • Fantastic, thank you, I think you might be right- I'll give that a try and then post again with the results.

  • Ok, so I realized I can't have interrupts enabled during I2C communication because if the protocol gets interrupted, the slave that I'm trying to talk to (a sensor in this case) gets confused and there is either data loss or the system simply shuts down. So instead, I decided to try to turn off the I2C TX and RX interrupts before enabling GIE. The program (below) compiles and runs, but I get a weird result, shown in the picture.

    The sequence of events in the while loop is supposed to be: Read each of the 3 sensors, Put each into Force Mode, enable GIE so I can see if interrupts occur on P1.7, delay for 1 ms while I monitor the interrupt line, and then disable GIE so I can start reading the sensors again. For some reason, the output pin 3.3 goes high some time after I enable GIE and goes low some time after I disable it. 3.3 is the output test pin that I plan to wiggle with the ISR, and when I trigger an interrupt on pin 1.7, nothing happens on pin 3.3.

    This forum is pretty good about getting back to people pretty quickly, but I'm under a big time crunch, so fast replies (even tomorrow) would be even more appreciated. Also, if you need to see the other functions mentioned in the program let me know, I didn't include them because it made the post super long. Thanks




    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;               // Stop WDT
     
      P1IE |= 0x80;                           // P1.7 Enable Interrupt
      P1IES &= ~0x80;                         // P1.7 Lo to Hi edge
      P1IFG &= ~0x80;                         // P1.7 IFG cleared

      P3SEL |= 0x06;                          // Assign I2C pins to USCI_B0
      P5SEL |= 0x06;                          // Assign I2C pins to USCI_B0
      P5DIR &= ~0x20;                         // P5.5 is input: DRDY1
      P4DIR &= ~0x80;                         // P4.7 is input: DRDY2
      P4DIR &= ~0x10;                         // P4.4 is input: DRDY3
     
      P3DIR |= 0x01;                          // P3.0 is an output test pin
      P3OUT &= ~0x01;                         // Set it low
      P3DIR |= 0x08;                          // P3.3 is an output test pin
      P3OUT &= ~0x08;                         // Set it low
     
      I2C_Setup_B0();
      I2C_Setup_B1();
     
      SADDR = 0x00F;
      initialize1(SADDR);                     // Initialize sensor 1
      initialize2(SADDR);                     // Initialize sensor 3
      SADDR = 0x00E;
      initialize1(SADDR);                     // Initialize sensor 2
     
      SADDR = 0x00F;
      force1(SADDR);                          // Force Mode for sensor 1
      force2(SADDR);                          // Force Mode for sensor 3
      SADDR = 0x00E;
      force1(SADDR);                          // Force Mode for sensor 2
     
      while (1)
      {
        SADDR = 0x00F;
        RADDR = 0x10;                         // DataX register address
        DRDY = 0x20;
        read1_6(SADDR, RADDR, DRDY, j);       // Read sensor 1, put X,Y,Z data in jth col of RXData[0]
        DRDY = 0x10;
        read2_6(SADDR, RADDR, DRDY, j);       // Read sensor 3, put X,Y,Z data in jth col of RXData[2]
        SADDR = 0x00E;
        DRDY = 0x80;
        read1_6(SADDR, RADDR, DRDY, j);       // Read sensor 2, put X,Y,Z data in jth col of RXData[1]
        
        SADDR = 0x00F;
        force1(SADDR);                        // Force Mode for sensor 1
        force2(SADDR);                        // Force Mode for sensor 3
        SADDR = 0x00E;
        force1(SADDR);                        // Force Mode for sensor 2
        
        P3OUT |= 0x08;
        IE2 &= ~UCB0TXIE;                        // Disable TX interrupt
        IE2 &= ~UCB0RXIE;                        // Disable RX interrupt
        UC1IE &= ~UCB1TXIE;                      // Disable TX interrupt
        UC1IE &= ~UCB1RXIE;                      // Disable RX interrupt
        __bis_SR_register(GIE);                  // General Interrupt Enabled
        P3OUT &= ~0x08;
        
        delay_ms(1);                                     // Monitor Interrupt pin during this delay
        
        P3OUT |= 0x08;
        __bic_SR_register(GIE);                 // General Interrupt Disabled
        IE2 |= UCB0TXIE;                        // Enable TX interrupt
        IE2 |= UCB0RXIE;                        // Enable RX interrupt
        UC1IE |= UCB1TXIE;                      // Enable TX interrupt
        UC1IE |= UCB1RXIE;                      // Enable RX interrupt
        P3OUT &= ~0x08;
      }
    }

        //////////////////////////////Functions/////////////////////////////////

    void I2C_Setup_B0()
    {
      UCB0CTL1 |= UCSWRST;                    // Enable SoftWare reset
      UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;   // Mode: Master, I2C, synchronous
      UCB0CTL1 = UCSSEL_2 + UCSWRST;          // Use SMCLK, keep SW reset
      UCB0BR0 = 2;                            // fSCL = SMCLK/2 = ~200kHz
      UCB0BR1 = 0;
      UCB0CTL1 &= ~UCSWRST;                   // Clear SW reset, resume operation
      IE2 |= UCB0TXIE;                        // Enable TX interrupt
      IE2 |= UCB0RXIE;                        // Enable RX interrupt
    }

    void I2C_Setup_B1()
    {
      UCB1CTL1 |= UCSWRST;                    // Enable SoftWare reset
      UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC;   // Mode: Master, I2C, synchronous
      UCB1CTL1 = UCSSEL_2 + UCSWRST;          // Use SMCLK, keep SW reset
      UCB1BR0 = 2;                            // fSCL = SMCLK/2 = ~200kHz
      UCB1BR1 = 0;
      UCB1CTL1 &= ~UCSWRST;                   // Clear SW reset, resume operation
      UC1IE |= UCB1TXIE;                      // Enable TX interrupt
      UC1IE |= UCB1RXIE;                      // Enable RX interrupt
    }


    #pragma vector = PORT1_VECTOR
    __interrupt void Port_1(void)
    {
      P3OUT |= 0x01;
      P3OUT &= ~0x01;
      P3OUT |= 0x01;
      P3OUT &= ~0x01;
      telemetry = 0x01;
      P1IFG &= ~0x80;                           // P1.7 IFG cleared
    }

  • uhhh. heh... sorry, please disregard the last post- I had the probe on the wrong pin... *smacks head*

  • Peter McMenamin said:

    Ok, so I realized I can't have interrupts enabled during I2C communication because if the protocol gets interrupted, the slave that I'm trying to talk to (a sensor in this case) gets confused and there is either data loss or the system simply shuts down.

    Actually that's not the case; it only "doesn't work" because you don't have specific ISRs handling the USCI interrupts from your I2C, since you enabled them here:

        IE2 |= UCB0TXIE;                        // Enable TX interrupt
        IE2 |= UCB0RXIE;                        // Enable RX interrupt
        UC1IE |= UCB1TXIE;                      // Enable TX interrupt
        UC1IE |= UCB1RXIE;                      // Enable RX interrupt

    So when an interrupt happens, i.e. when you're sending or receiving over the I2C, the MSP430 would try to fetch from the (undefined) interrupt vector, by default 0xFFFF which would cause the device to reset.

    All the TI examples for I2C uses interrupts fairly extensively, see this example from the Value Line family:

    #include "msp430g2553.h"
    
    unsigned char TXData;
    
    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
      P1DIR |= BIT0;                            // P1.0 output
      P1SEL |= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
      P1SEL2|= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
      
      UCB0CTL1 |= UCSWRST;                      // Enable SW reset
      UCB0CTL0 = UCMODE_3 + UCSYNC;             // I2C Slave, synchronous mode
      UCB0I2COA = 0x48;                         // Own Address is 048h
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      UCB0I2CIE |= UCSTTIE;                     // Enable STT interrupt
      IE2 |= UCB0TXIE;                          // Enable TX interrupt
      TXData = 0xff;                            // Used to hold TX data
    
      while (1)
      {
        __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
      }
    }
    
    // USCI_B0 Data ISR
    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
      UCB0TXBUF = TXData;                       // TX data
      __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
    }
    
    // USCI_B0 State ISR
    #pragma vector = USCIAB0RX_VECTOR
    __interrupt void USCIAB0RX_ISR(void)
    {
      UCB0STAT &= ~UCSTTIFG;                    // Clear start condition int flag
      TXData++;                                 // Increment data
    }
    


    Tony

**Attention** This is a public forum