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.

CCS/MSP430FR2311: Timer B0.1 not going into interrupt

Part Number: MSP430FR2311


Tool/software: Code Composer Studio

I have this code that reads form a water flow sensor. It works perfectly when I use TB1.2 on pin 2.1, but if I try to use TB0.1 on pin 1.6, it won't go into the interrupt. Here is my code:

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

//initialize variables
volatile unsigned int counter=0;
volatile unsigned int prev_counter=0;
unsigned int difference=0;
int flow_rate=0;

__attribute__((ramfunc))
int main(void)
{
    WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer

    // Disable the GPIO power-on default high-impedance mode to activate
    // previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;
  
    //P1.6/TB0.1
    P1DIR &= ~BIT6;

    P1SEL1 &= ~BIT1;  //0
    P1SEL0 |= BIT1;   //1



    // TB0CCR1: capture mode + on rising edge + enable interrupt request of corresponding CCIFG flag + synchronize capture source + Capture input select CCI1A
    TB0CCTL1 = CAP + CM_1 + CCIE + SCS + CCIS_0;

    //Use the SMCLK + Divide clk by 8 (125kHz)+Continuous mode: Timer counts up to the value set by CNTL + TimerB clear + Interrupt enable
    TB0CTL |= TBSSEL_2 + ID_3 + MC_2 + TBCLR + TBIE;

    while(1) {
        //enter low power mode0 with interrupt enable
        __bis_SR_register(LPM0_bits + GIE);
        __no_operation();

        difference = counter - prev_counter;        //amount of rising pulse edges

        //flow rate in L/min. 125000 SMCLKs divided by rising pulse edges detected gives frequency.
        //The conversion constant for frequency to L/min is 4.8 or 19/4 so instead of dividing by 4.8, mult by reciprocal of 19/4.
        //Whatever the integer result, move decimal one place to the left for true reading.
        flow_rate = (40*(125000UL/difference))/19;
             }
}

//Timer_B0 TBCCR1 Interrupt Vector Handler Routine
__attribute__((ramfunc));
#pragma vector = TIMER0_B1_VECTOR
__interrupt void TIMER0_B1_ISR (void)
{
  switch(__even_in_range(TB0IV,TB0IV_TBIFG))
  {
      case TBIV__NONE: break;       //Vector 0: No interrupt
      case TBIV__TBCCR1:            //Vector 2: TBCCR1 CCIFG. Interrupt source:capture/compare R1. Interrupt Flag: TBxCCR1 CCIFG.
         prev_counter = counter;
         counter = TB0CCR1;        // 'Counter' value is copied to TB0CCR1 register
         __bic_SR_register_on_exit(LPM0_bits + GIE); //exit LPM0
         break;
      case TBIV__TBCCR2: break;          //Vector 4: TBCCR2 CCIFG
      case TBIV__TBCCR3: break;
      case TBIV__TBCCR4: break;
      case TBIV__TBCCR5: break;
      case TBIV__TBCCR6: break;
      case TBIV__TBIFG: break;      //Vector 6: TBIFG
      default: break;
  }
}

When I run the program and make water flow through the sensor, it does not give any values for 'counter' or 'prev_counter'. I've been debugging for a while and I'm not sure what the problem is. Any suggestions or help would be greatly appreciated.

Thank you!

  • On TB0.1 output through pin 1.6, please refer to FR2311 code example "msp430fr231x_tb0_16.C" and "msp430fr231x_tb0_16.C". the code example can be downloaded in www.ti.com/.../getliterature.tsp
  • Are you using the Launchpad? If so, did you remove the RXD jumper from J101?
    -------
    Also:
    > P1SEL1 &= ~BIT1; //0
    > P1SEL0 |= BIT1; //1
    I'm pretty sure these are backwards -- you want P1SEL1.1=1 and P1SEL0.1=0. (I don't much care for the notation in SLASE58C Table 6-43, but I checked it against one of the examples.)
  • My apologies. Since P1.6 will be used for another purpose, I can no longer use it. I can only use P1.0 or P1.1. In this case, I have been trying to work with P1.0.

    #include <msp430.h>
    #include <math.h>
    #include <stdio.h>
    
    //initialize variables
    volatile unsigned int counter=0;
    volatile unsigned int prev_counter=0;
    unsigned int difference=0;
    int flow_rate=0;
    
    __attribute__((ramfunc))
    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer
    
        // Disable the GPIO power-on default high-impedance mode to activate
        // previously configured port settings
        PM5CTL0 &= ~LOCKLPM5;
    
        //P1.0 as input
        P1DIR &= ~BIT0;   //0
    
        P1SEL1 |= BIT1;    //1
        P1SEL0 &= ~BIT1;   //0
    
        // Timer1_B3 setup
        //TBCCR2: capture mode + on rising edge + enable interrupt + synchronize capture source + Capture input select CCI2A
        TB1CCTL2 = CAP + CM_1 + CCIE + SCS + CCIS_0;
    
        // SMCLK=1MHz, continuous mode, TimerB clear, interrupt enable
        TB1CTL |= TBSSEL_2 + MC_2 + TBCLR + TBIE;
    
        while(1) {
            //enter low power mode0 with interrupt enable
            __bis_SR_register(LPM0_bits + GIE);
            __no_operation();
    
            difference = counter - prev_counter;        //amount of rising pulse edges
    
            //flow rate in L/min. 125000 SMCLKs divided by rising pulse edges detected gives frequency.
            //The conversion constant for frequency to L/min is 4.8 or 19/4 so instead of dividing by 4.8, mult by reciprocal of 19/4.
            //Whatever the integer result, move decimal one place to the left for true reading.
            flow_rate = (40*(125000UL/difference))/19;
                 }
    }
    
    //Timer_B1 TBCCR2 Interrupt Vector Handler Routine
    __attribute__((ramfunc));
    #pragma vector = TIMER1_B1_VECTOR
    __interrupt void TIMER1_B1_ISR (void)
    {
      switch(__even_in_range(TB1IV,TB1IV_TBIFG))
      {
          case TBIV__NONE: break;       //Vector 0: No interrupt
          case TBIV__TBCCR1: break;     //Vector 2: TBCCR1 CCIFG. Interrupt source:capture/compare R1. Interrupt Flag: TBxCCR1 CCIFG.
          case TBIV__TBCCR2:            //Vector 4: TBCCR2 CCIFG
              prev_counter = counter;
              counter = TB1CCR2;        // 'Counter' value is copied to TB1CCR2 register
              __bic_SR_register_on_exit(LPM0_bits + GIE); //exit LPM0
              break;
          case TBIV__TBCCR3: break;
          case TBIV__TBCCR4: break;
          case TBIV__TBCCR5: break;
          case TBIV__TBCCR6: break;
          case TBIV__TBIFG: break;      //Vector 6: TBIFG
          default: break;
      }
    }

    The code will not go into the interrupt. When I run the code and make water flow through my sensor, the values for 'difference' and 'flow_rate' stay at 0. I have tried two different module functions of P1SEL1 and P1SEL0, which are general purpose I/O (00), and SMCLK/VSS (10) according to SLASE58C Table 6-43. I'm thinking the way my interrupt is setup might be completely wrong since the msp430fr231x_tb1_05.c example uses TB1CCR0 with a different ISR setup. In all the examples I've looked at with P1.0, it has only been used as an output. So maybe this pin won't work when setting it as input?

    Thank you for your help so far,

    Regards

  • In SLASE58C Tables 6-43/44, you're looking for a "Function" of the form "CCIxy".

    There are no functions of that form available on P1.0/P1.1. (P1.6/7 have TB0.1/2, but they conflict with UCA0, which I suppose is why you can't use them.)

    TB1.2 is on P2.1 [Table 6-44]. There's also TB1.1 on P2.0. They (just to keep things lively) require P2SEL=0b01, i.e. P2SEL1=0, P2SEL0=1.

    If you run out of (timer) pins, it's always possible to mimic capture using a pin interrupt to capture TBR. There's some latency/jitter, so it's not as good as true Timer Capture, but it can be done.

    [Edit: fixed typo]

  • I have setup an input capture for P1.0

    #include <msp430.h>
    #include <math.h>
    #include <stdio.h>
    
    //initialize variables
    volatile unsigned int counter=0;
    volatile unsigned int prev_counter=0;
    unsigned int difference=0;
    int flow_rate=0;
    
    __attribute__((ramfunc))
    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer
        P1DIR = 0xFF;
        P1REN = 0xFF;
        P1OUT = 0x00;
    
        //P1.0 as input
        P1DIR &= ~BIT0;   //0
    
        P1OUT &= ~BIT0; // Configure P1.0 as pulled-down
        P1REN |= BIT0;  // P1.0 pull-down register enable
        P1IES &= ~BIT0; // P1.0 lo/Hi edge select
        P1IE |= BIT0;   // P1.0 interrupt enabled
    
        // Disable the GPIO power-on default high-impedance mode to activate
        // previously configured port settings
        PM5CTL0 &= ~LOCKLPM5;
    
        P1IFG &= ~BIT0; // P1.0 IFG cleared
    
        while(1) {
    
            //enter low power mode2 with interrupt enable
            __bis_SR_register(LPM3_bits + GIE);
            __no_operation();
    
            difference = counter - prev_counter;        //amount of rising pulse edges
    
            flow_rate = (40*(125000UL/difference))/19;
                 }
    }
    
    
    // Port 1 interrupt service routine
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=PORT1_VECTOR
    __interrupt void Port_1(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(PORT1_VECTOR))) Port_1 (void)
    #else
    #error Compiler not supported!
    #endif
    {
        P1IFG &= ~BIT0; // P1.0 IFG cleared
        prev_counter = counter;
        counter = TBR;
        __bic_SR_register_on_exit(LPM3_bits + GIE); //exit LPM2
    }
    

    This program does not go into the interrupt. I have tried using LPM 0, 2, and 3, setting P1OUT as pulled-up or pulled-down. I am not sure if this code is taking the pulses coming from the hall effect sensor in the water flow sensor when water flows through it. I am connecting it to the 5V pin on the launchpad which should be fine since the min working voltage of the sensor is 4.5V.

    It does go into the interrupt in a much simpler implementation of the code shown here:

    #include <msp430.h>
    #include <stdio.h>
    
    
    void Init_GPIO(void);
    void Init_GPIO(void){
    
            WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer
            P1DIR = 0xFF; P2DIR = 0xFF;
            P1REN = 0xFF; P2REN = 0xFF;
            P1OUT = 0x00; P2OUT = 0x00;
    
            // Interrupt Pin 1.0 CTS Pin from the XBee
            P1OUT &= ~BIT0;                         // Configure P1.0 as pulled-down
            P1REN |= BIT0;                          // P1.0 pull-down register enable
            P1IES &= ~BIT0;                          // P1.0 Low/High edge
            P1IE |= BIT0;                           // P1.0 interrupt enabled
    
    
            PM5CTL0 &= ~LOCKLPM5; // Disable the GPIO power-on default high-impedance mode
               // to activate previously configured port settings
    
    }
    
    
    int flag =0;
    
    int main()
    {
        Init_GPIO();
    
        P1IFG &= ~BIT0;         // P1.0 IFG cleared
        while (1){
            __bis_SR_register(LPM2_bits + GIE);          // Global interrupts Enable
            __no_operation();                           // debug
            while (flag==1){                            // when CTS (p1.0) is high go into low power mode
            }
    
            }
        }
    
    
    // Port 1 interrupt service routine
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=PORT1_VECTOR
    __interrupt void Port_1(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(PORT1_VECTOR))) Port_1 (void)
    #else
    #error Compiler not supported!
    #endif
    {
        P1IFG &= ~BIT0;                         // Clear P1.0 IFG
        flag =1;
        __bic_SR_register_on_exit(LPM2_bits + GIE);   // Exit LPM3
    
    }
    

    With this program I hit Debug then 'Resume'. Then I connect a jumper cable from the 3.3V pin to P1.0. When I pause the program, it stops on the 'while(flag==1)' line and not in the 'bis_SR' line. I hover over 'flag' in main and in the interrupt, and its value is 1. I think this means that it is going into the interrupt when I do it this way.

    I am not sure why it won't work with the first code and my flow sensor. Any tips are greatly appreciated.

  • Did you remove the jumper from J10 (LED1)? I'm not sure what effect the LED might have in all this.

    > __attribute__((ramfunc))
    Maybe this works fine, but I don't think it's needed, and it does muddy the experiment. I suggest you remove it, at least temporarily.

    In the second example, P1.0 is an output (driving low), and in the first it's an input pulled low (which is what you want). I don't have a causal chain to propose for the difference, but it is a difference.

    For the first example, how are you deducing that the ISR isn't called?

    Unsolicited:
    > __bic_SR_register_on_exit(LPM3_bits + GIE); //exit LPM2
    This actually disables interrupts in main(). It probably isn't causing trouble now, but it will eventually. I suggest:
    > __bic_SR_register_on_exit(LPM3_bits); //exit LPM2
  • I did remove the jumper from J10. For the first example, I put a breakpoint in the 'P1IFG &= ~BIT0' line in the interrupt. When I give P1.0  5V with a jumper cable, the program stops at the 'P1IFG &= ~BIT0' line in the interrupt when I pause the program. When I use the flow sensor and make water flow through it, the program does not go to the breakpoint that I set in the interrupt, it stays in the 'bis_SR' line. Here's the updated code.

    #include <msp430.h>
    #include <math.h>
    #include <stdio.h>
    
    //initialize variables
    volatile unsigned int counter=0;
    volatile unsigned int prev_counter=0;
    unsigned int difference=0;
    int flow_rate=0;
    int flag=0;
    
    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer
    
        //P1.0 as input
        P1DIR &=~ BIT0;   //0
    
        P1OUT &= ~BIT0; // Configure P1.0 as pulled-down
        P1REN |= BIT0;  // P1.0 pull-down register enable
        P1IES &= ~BIT0; // P1.0 lo/Hi edge select
        P1IE |= BIT0;   // P1.0 interrupt enabled
    
        // Disable the GPIO power-on default high-impedance mode to activate
        // previously configured port settings
        PM5CTL0 &= ~LOCKLPM5;
    
        P1IFG &= ~BIT0; // P1.0 IFG cleared
        while(1) {
    
            //enter low power mode3 with interrupt enable
            __bis_SR_register(LPM3_bits + GIE);
            __no_operation();
    
            difference = counter - prev_counter;        //amount of rising pulse edges
    
    
            flow_rate = (40*(125000UL/difference))/19;
     
                 }
    }
    
    // Port 1 interrupt service routine
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=PORT1_VECTOR
    __interrupt void Port_1(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(PORT1_VECTOR))) Port_1 (void)
    #else
    #error Compiler not supported!
    #endif
    {
        P1IFG &= ~BIT0; // P1.2 IFG cleared
        prev_counter = counter;
        counter = TBR;
        __bic_SR_register_on_exit(LPM3_bits); //exit LPM3
    }

    Also, using a multimeter, I see that my flow sensor outputs 2.5V when water flows through it. So I'm not sure if the voltage is the reason the code does not enter the interrupt.

  • Is 2.5V the "high" output, or an average while it's running?

    If the former, then that probably isn't enough. SLASE58C Table 5-10 says Vit+ can be as much as 2.25V at 3V; I think the Launchpads usually run at 3.6V, so the first guess would be (3.6/3.0)*2.25=2.7V. At best, 2.5V is borderline.

    Your meter's data sheet should tell you what the digital levels should be at the voltage you're supplying (5V?).

    Also, I recommend you don't connect 5V to any of the MSP430 pins -- Section 5.1 says no more than (3.6+0.3)=3.9V.
  • Hi Sparrow
    Any update on this problem? may I confirm the voltage on P10 of your system?
  • Hi, I apologize for not getting back to yall sooner. I made it work the way I wanted to by using P1.1 on the launchpad. I never really figured out why it didn't work with P1.0. Thank you for your help!!!

**Attention** This is a public forum