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.

MSP430FR5969: how to enter interupt service routine, stuck in __bis_SR_register(LPM3_bits + GIE);

Part Number: MSP430FR5969
Other Parts Discussed in Thread: MSP-EXP430FR5969

Hello!

I am new to msp430 technology and microcontroler programming. currently I am working on i2c but I am stuck with this problem. Please don't be harsh and correct me if i'm wrong but shoudn't __bis_SR_register(LPM3_bits + GIE); make the programm go into ISR? And what is the difference between LPM0 and LPM1(2,3,4)?

I added output commands so i could see in console where is my code getting stuck and it always stucks at shoudn't __bis_SR_register(LPM3_bits + GIE);

/*
 * main.c
 */

#include <msp430.h>
#include <stdio.h>

unsigned char SlaveAddress = 0x76;
unsigned char TXByteCtr;
unsigned char RXByteCtr;
unsigned char *PTxData;
unsigned char *PRxData;

unsigned char RXData[6];
unsigned char TXDataArr[3];

void initI2C(void);
void RXdata(unsigned char reg_addr, unsigned char RX_byte);
void TXdata(unsigned char TX_byte);
void iic_TX(void);
void iic_RX(void);
void start_TX(void);
void start_RX(void);
void init_slave();
void read_slave();

int main(void)
{
  WDTCTL = WDTPW | WDTHOLD;

  //// I/O INIT
  // Disable the GPIO power-on default high-impedance mode to activate
  // previously configured port settings
  PM5CTL0 &= ~LOCKLPM5;
  P1SEL1 |= BIT6 | BIT7;                    // I2C pins
  ////

  initI2C();

  __bis_SR_register(GIE);

  init_slave(); 

  read_slave();

  while(1)
  {
      //read_slave();
  }
}

/////////////////// I2C B0///////////////////
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
#else
#error Compiler not supported!
#endif
{
    puts("interupt service routine entered\n");
    switch(__even_in_range(UCB0IV,0x1E)) {
    case 0x00: break; // Vector 0: No interrupts break;
    case 0x02: break;

    case 0x04:
        UCB0CTLW0 |= UCTXSTT; //resend start if NACK
    break; // Vector 4: NACKIFG break;

    case 0x06: break; // Vector 6: STTIFG break;
    case 0x08: break; // Vector 8: STPIFG break;
    case 0x0a: break; // Vector 10: RXIFG3 break;
    case 0x0c: break; // Vector 14: TXIFG3 break;
    case 0x0e: break; // Vector 16: RXIFG2 break;
    case 0x10: break; // Vector 18: TXIFG2 break;
    case 0x12: break; // Vector 20: RXIFG1 break;
    case 0x14: break; // Vector 22: TXIFG1 break;

    case 0x16: // Vector 24: RXIFG0 break;
        *PRxData++ = UCB0RXBUF; // Get RX data
        RXByteCtr --;
        if (RXByteCtr == 0) {
            __delay_cycles(30);
            UCB0CTLW1 |= UCSWACK;
            UCB0CTLW0 |= UCTXACK;
            UCB0CTLW0 |= UCTXSTP;
        }
        else {
            UCB0IFG &= ~UCRXIFG0;
            __bic_SR_register_on_exit(LPM3_bits);
        }
    break;

    case 0x18:
        if (TXByteCtr){ // Check TX byte counter
            UCB0TXBUF = *PTxData++; // Load TX buffer
            TXByteCtr--;
        }
        else {
            UCB0CTLW0 |= UCTXSTP; // I2C stop condition
            UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag
            __bic_SR_register_on_exit(LPM3_bits);// Exit LPM0
        }
    break; // Vector 26: TXIFG0 break;

    case 0x1A:
        UCB0IFG &= ~UCBCNTIFG;
    break; // Vector 28: BCNTIFG break;

    case 0x1c: break; // Vector 30: clock low timeout break;
    case 0x1e: break; // Vector 32: 9th bit break;
    default: break;
    }
}

void initI2C(void){
    puts("initialising i2c");
    UCB0CTLW0 |= UCSWRST; // put eUSCI_B in reset state
    UCB0CTLW0 |= UCMODE_3 | UCMST | UCSSEL_2 | UCSYNC;// I2C mode, master mode, SMCLk /// + UCSSEL_2 | UCSYNC
    UCB0CTLW1 |= UCASTP_2; //automatic stop generated
    //after UCB0TBCNT is reached
    UCB0BRW = 0x20; // 12
    UCB0CTLW0 &=~ UCSWRST; //clear reset register
    UCB0IE |= UCNACKIE | UCBCNTIE;
    puts("initialising i2c successful");
}

void TXdata(unsigned char TX_byte) {
    puts("calling iic_TX");
    iic_TX();
    puts("returned from iic_TX");
    PTxData = (unsigned char *)&TXDataArr; // TX array start address
    printf("PTxData = %d", TXDataArr[0]);
    TXByteCtr = TX_byte; // Load TX byte counter
    printf("TXByteCtr = %d\n",TX_byte);
    puts("calling start_TX");
    start_TX();
}
void iic_TX(void) {
    puts("entered iic_TX \n");
    printf("slave address = %d \n", SlaveAddress);
    UCB0I2CSA = SlaveAddress;
    puts("enabling tx interupt");
    UCB0IE |= UCTXIE0; // Enable TX interrupt
    puts("TX interupt enabled \n");
    puts("exiting iic_TX\n");
}

void start_TX(void) {
    puts("entered start_TX \n");
    while (UCB0CTLW0 & UCTXSTP); // Ensure stop condition got sent
    puts("stop condition sent \n");
    puts("starting i2c TX\n");
    UCB0CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition
    puts("start condition met\n");
    puts("entering interupt service routine\n");
    __bis_SR_register(LPM3_bits + GIE); // Enter LPM0 w/ interrupts
    puts("exiting start_TX\n");
}

void init_slave(){
    puts("initialising sensor");
    TXDataArr[0] = 0xF4;
    TXDataArr[1] = BIT5 + BIT2 + BIT1;
    TXdata(2);
    puts("initialising sensor successful");
}

void read_slave(){
    puts("reading data from sensor..");
    RXdata(0xFA, 2);
    puts("data read");

}

  • I suggest: Start with LPM0, until you get everything else working reliably.

    At LPM0, only the CPU is switched off. Successively higher LPMs (LPM1/2/3/4) turn off more MCU functions (mostly clocks) to the point where at LPM4 almost nothing is running. I forget which things don't run at LPM3 on the FR5xx series, though you should be able to extract it from the User Manual. In the meantime, just avoid the question by using LPM0.
  • Hello Krisjanis,

    Alongside what Bruce has already said, your eUSCI peripheral is supplied by SMCLK which is turned off in LPM3. It is possible that the start bit and slave address have not been entirely sent before you enter LPM3 and therefore turn off the SMCLK which generates your I2C clock output. You also set GIE UCTXIE0 too early (therefore an interrupt will occur before starting the I2C sequence) and never set UCRXIE0. The puts and printf functions could also be interfering.

    Regards,
    Ryan
  • 1) Shoudn't i enable UCRXIE0 if i wan't to use master as a receiver at later point?

    2) If i wan't to just enter ISR shuld i use LPM if i don't need to save power.

    3) I can't figure out what is wrong with my code if i enable LPM i get stuck in __bis_SR_register(LPM0_bits + GIE) - this time i enabled UCTXIE0 right before I want to enter ISR. And if i don't enable LPM the ISR is skipped 

    #include <msp430.h> 
    #include <stdio.h>
    
    void initialize_master(void);
    void initialize_slave(void);
    void transmit_data(unsigned char tx_byte);
    void start_tx(void);
    
    const unsigned char SLAVE_ADDRESS = 0x76;
    
    unsigned char rx_byte_ctr = 0;
    unsigned char tx_byte_ctr = 0;
    unsigned char rx_data = 0;
    unsigned char tx_data[] = {};
    
    unsigned char tx_byte = 0;
    
    //const unsigned char TXData[] = { 0xA1, 0xB1, 0xC1, 0xD1 };
    //const unsigned char SlaveAddress[] = { 0x0A, 0x0B, 0x0C, 0x0D };
    
    int main(void)
    {
        tx_data[0] = 0xF4;
        tx_data[1] = BIT5 + BIT2 + BIT1;
    	WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
    
    	P1SEL1 |= BIT6 | BIT7; // set i2c pins
    	 // Disable the GPIO power-on default high-impedance mode to activate
    	  // previously configured port settings
    	PM5CTL0 &= ~LOCKLPM5;
    
    	initialize_master();
    
    	while (1)
    	{
    	    initialize_slave();
    
    	   // __delay_cycles(2000);
    	   // UCB0I2CSA = SLAVE_ADDRESS;
    	   // tx_byte_ctr = 1;
    
    	  //  while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
    	  //  UCB0CTLW0 |= UCTR | UCTXSTT;                    // I2C start condition
    
    
    	  //  __bis_SR_register(GIE);     // Enter LPM0 w/ interrupt
        }
    
    //return 0;
    }
    
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = USCI_B0_VECTOR
    __interrupt void USCI_B0_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
      switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
      {
        case USCI_NONE:          break;         // Vector 0: No interrupts
        case USCI_I2C_UCALIFG:   break;         // Vector 2: ALIFG
        case USCI_I2C_UCNACKIFG:                // Vector 4: NACKIFG
          UCB0CTL1 |= UCTXSTT;                  // I2C start condition
          break;
        case USCI_I2C_UCSTTIFG:  break;         // Vector 6: STTIFG
        case USCI_I2C_UCSTPIFG:  break;         // Vector 8: STPIFG
        case USCI_I2C_UCRXIFG3:  break;         // Vector 10: RXIFG3
        case USCI_I2C_UCTXIFG3:  break;         // Vector 12: TXIFG3
        case USCI_I2C_UCRXIFG2:  break;         // Vector 14: RXIFG2
        case USCI_I2C_UCTXIFG2:  break;         // Vector 16: TXIFG2
        case USCI_I2C_UCRXIFG1:  break;         // Vector 18: RXIFG1
        case USCI_I2C_UCTXIFG1:  break;         // Vector 20: TXIFG1
        case USCI_I2C_UCRXIFG0:                 // Vector 22: RXIFG0
            rx_data = UCB0RXBUF;                   // Get RX data
          __bic_SR_register_on_exit(LPM0_bits | GIE); // Exit LPM0
          break;
        case USCI_I2C_UCTXIFG0:                  // Vector 24: TXIFG0
            if (tx_byte_ctr)                        // Check TX byte counter
            {
                int i = 0;
              UCB0TXBUF = &tx_data;      // Load TX buffer
              tx_byte_ctr--;                        // Decrement TX byte counter
              i++;
            }
            else
            {
              UCB0CTLW0 |= UCTXSTP;               // I2C stop condition
              UCB0IFG &= ~UCTXIFG;                // Clear USCI_B0 TX int flag
              __bic_SR_register_on_exit(LPM0_bits | GIE); // Exit LPM0
            }
            break;
        case USCI_I2C_UCBCNTIFG:                // Vector 26: BCNTIFG
          P1OUT ^= BIT0;                        // Toggle LED on P1.0
          break;
        case USCI_I2C_UCCLTOIFG: break;         // Vector 28: clock low timeout
        case USCI_I2C_UCBIT9IFG: break;         // Vector 30: 9th bit
        default: break;
      }
    }
    
    
    void initialize_master(void){
        UCB0CTLW0 |= UCSWRST; // put eUSCI_B in reset state
        UCB0CTLW0 |= UCMODE_3 | UCMST | UCSSEL_2 | UCSYNC;// I2C mode, master mode, SMCLk /// + UCSSEL_2 | UCSYNC
        UCB0CTLW1 |= UCASTP_2; //automatic stop generated
        //after UCB0TBCNT is reached
        UCB0BRW = 0x20; // 12
        UCB0CTLW0 &=~ UCSWRST; //clear reset register
        UCB0IE |= UCNACKIE | UCBCNTIE;
    }
    
    void initialize_slave(void){
        tx_data[0] = 0xF4;
        tx_data[1] = BIT5 + BIT2 + BIT1;
        transmit_data(2);
    }
    
    void transmit_data(unsigned char tx_byte) {
        UCB0I2CSA = SLAVE_ADDRESS;
        tx_byte_ctr = tx_byte; // Load TX byte counter
        start_tx();
    }
    
    void start_tx(void) {
    //    while (UCB0CTLW0 & UCTXSTP); // Ensure stop condition got sent
        UCB0CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition
        UCB0IE |= UCTXIE0; // Enable TX interrupt
        __delay_cycles(2000);
        __bis_SR_register(LPM0_bits | GIE);
        __delay_cycles(2000);
        //__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
    }

    4) Does it matter how much delay I set?

    I ask these questions because i look at the TI examples and don't get why the LPMs 

    5) Could there be something wrong with my project setup or hardware itself?

  • 1. I assume you expect to receive something since you have code inside the RXIFG0 case, therefore RXIE0 would need to be set at some point.
    2/3. You aren't stuck in __bis_SR_register(LPM0_bits + GIE), rather the PC is asleep and the ISR is never entered, therefore no code is executed. Enable TXIE0 before UCTXSTT.
    4. No, this is for debugging purposes.
    5. There could be something wrong with the hardware if you do not see any communication with a TI-provided example, are you using the proper pull-up resistances (10 kOhm) on the I2C lines? Can you view them on an oscilloscope or logic analyzer?

    Regards,
    Ryan
  • //*
    #include <msp430.h>
    //#include <stdio.h>
    
    void initialize_master(void);
    void initialize_slave(void);
    void transmit_data(unsigned char tx_byte);
    void start_tx(void);
    
    const unsigned char SLAVE_ADDRESS = 0x76;//works w/ 0x46
    
    unsigned char rx_byte_ctr = 0;
    unsigned char tx_byte_ctr = 0;
    unsigned char rx_data = 0;
    unsigned char tx_data[] = {};
    
    unsigned char tx_byte = 0;
    
    //const unsigned char TXData[] = { 0xA1, 0xB1, 0xC1, 0xD1 };
    //const unsigned char SlaveAddress[] = { 0x0A, 0x0B, 0x0C, 0x0D };
    
    int main(void)
    {
        tx_data[0] = 0xF4;
        tx_data[1] = BIT5 + BIT2 + BIT1;
    	WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
    
    
    	P1SEL1 |= BIT6 | BIT7; // set i2c pins
    	P1REN |= BIT6 | BIT7; //pull ups
    	 // Disable the GPIO power-on default high-impedance mode to activate
    	  // previously configured port settings
    	PM5CTL0 &= ~LOCKLPM5;
    
    	
    
    
    	while (1)
    	{
    	    initialize_master();
    	    initialize_slave();
    
    //return 0;
    }
    
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = USCI_B0_VECTOR
    __interrupt void USCI_B0_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
    
      switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
      {
        case USCI_NONE:          break;         // Vector 0: No interrupts
        case USCI_I2C_UCALIFG:   break;         // Vector 2: ALIFG
        case USCI_I2C_UCNACKIFG:                // Vector 4: NACKIFG
            UCB0CTL1 |= UCTXSTT; //resend start if NACK
          break;
        case USCI_I2C_UCSTTIFG:  break;         // Vector 6: STTIFG
        case USCI_I2C_UCSTPIFG:  break;         // Vector 8: STPIFG
        case USCI_I2C_UCRXIFG3:  break;         // Vector 10: RXIFG3
        case USCI_I2C_UCTXIFG3:  break;         // Vector 12: TXIFG3
        case USCI_I2C_UCRXIFG2:  break;         // Vector 14: RXIFG2
        case USCI_I2C_UCTXIFG2:  break;         // Vector 16: TXIFG2
        case USCI_I2C_UCRXIFG1:  break;         // Vector 18: RXIFG1
        case USCI_I2C_UCTXIFG1:  break;         // Vector 20: TXIFG1
        case USCI_I2C_UCRXIFG0:                 // Vector 22: RXIFG0
            rx_data = UCB0RXBUF;                   // Get RX data
          __bic_SR_register_on_exit(LPM0_bits | GIE); // Exit LPM0
          break;
        case USCI_I2C_UCTXIFG0:                  // Vector 24: TXIFG0
            if (tx_byte_ctr)                        // Check TX byte counter
            {
                int i = 0;
              UCB0TXBUF = tx_data[i];      // Load TX buffer
              tx_byte_ctr--;                        // Decrement TX byte counter
              i++;
            }
            else
            {
              UCB0CTLW0 |= UCTXSTP;               // I2C stop condition
              UCB0IFG &= ~UCTXIFG;                // Clear USCI_B0 TX int flag
              __bic_SR_register_on_exit(LPM0_bits | GIE); // Exit LPM0
            }
            break;
        case USCI_I2C_UCBCNTIFG:                // Vector 26: BCNTIFG
          P1OUT ^= BIT0;                        // Toggle LED on P1.0
          break;
        case USCI_I2C_UCCLTOIFG: break;         // Vector 28: clock low timeout
        case USCI_I2C_UCBIT9IFG: break;         // Vector 30: 9th bit
        default: break;
      }
    }
    
    
    void initialize_master(void){
        //printf("initialising i2c\n");
        UCB0CTLW0 |= UCSWRST; // put eUSCI_B in reset state
        UCB0CTLW0 |= UCMODE_3 | UCMST | UCSSEL_2 | UCSYNC;// I2C mode, master mode, SMCLk /// + UCSSEL_2 | UCSYNC
        UCB0CTLW1 |= UCASTP_2; //automatic stop generated
        //after UCB0TBCNT is reached
        UCB0BRW = 0x20; // 12
        UCB0CTLW0 &=~ UCSWRST; //clear reset register
        UCB0IE |= UCNACKIE | UCBCNTIE;
        //printf("initialising i2c successful\n");
    }
    
    void initialize_slave(void){
        UCB0I2CSA = SLAVE_ADDRESS;
        tx_data[0] = 0xF4;
        tx_data[1] = BIT5 + BIT2 + BIT1;
        transmit_data(2);
    }
    
    void transmit_data(unsigned char tx_byte) {
        tx_byte_ctr = tx_byte;
        start_tx();
    }
    
    void start_tx(void) {
        while (UCB0CTLW0 & UCTXSTP); // Ensure stop condition got sent
        UCB0IE |= UCTXIE0; // Enable TX interrupt
        UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
        __delay_cycles(2000);
         __bis_SR_register(LPM0_bits | GIE);
    }
    
    
    

    I put TXIE0 before UCTXSTT like you suggested

    I also enabled pull ups (i don't know if i did it correctly) P1REN |= BIT6 | BIT7; //pull ups

    And I looked at osciloscope and i can see that slave is not acknowledged.  by the way. i use msp-exp430fr5969 launchpad with sensor booster pack and my launchpad has asd and slc as P3.5 and P3.6 although the readings are from P1.6 and P1.7. 

  • You need external pull-ups as compared to internal. You aren't going to get slave acknowledgement with nothing connected to your I2C pins.

    Regards,
    Ryan

**Attention** This is a public forum