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.

Help... Input Low Frequency Counter msp430fr5739

Other Parts Discussed in Thread: MSP430WARE, MSP430FR5739, MSP430G2213

Hello,

I'm new to msp430 programming. I am attempting to make a frequency counter for a very low frequency range.
So, I have a square wave signal coming out of a schmitt trigger that has a frequency range of 0-150Hz with max 3.3V going into the msp430.

Is it possible to do this the following
Have a known faster clock signal run and count the rising edges in one period of the input signal.
Then unknown freq= known/count

Can someone point me in the right direction or show me an example code? I am trying to do this with Timer A and capture but I am not sure exactly how to.
I am currently reading http://www.ti.com/lit/ug/slau272b/slau272b.pdf

  • Quy Tran said:
    Is it possible to do this the following
    Have a known faster clock signal run and count the rising edges in one period of the input signal.
    Then unknown freq= known/count

    Yes. You can do exactly that.

    Quy Tran said:
    Can someone point me in the right direction or show me an example code? I am trying to do this with Timer A and capture but I am not sure exactly how to.

    Have you looked at the examples in MSP430Ware? I am sure there are timer examples there you can look through and learn from.

    Also, remember that the accuracy of your frequency counter will be directly related to the accuracy of the MSP430's clock. Your best accuracy will come from using an external high-frequency crystal as your clock source.

  • Brian Boorman said:

    Have you looked at the examples in MSP430Ware? I am sure there are timer examples there you can look through and learn from.

    Also, remember that the accuracy of your frequency counter will be directly related to the accuracy of the MSP430's clock. Your best accuracy will come from using an external high-frequency crystal as your clock source.

    Brian,

    Thanks for the response. Yes, I have been looking at examples in the MSP430Ware. I was thinking of using VLO as source for ACLK, but I agree with using external crystal. I read that the VLO can vary based on temp more.... In the example, there is the following that I think I will use.

    WDTCTL = WDTPW + WDTHOLD;

    PJSEL0 |= BIT4 + BIT5; // XT1 Setup,

    CSCTL0_H = 0xA5;
    CSCTL1 |= DCOFSEL0 + DCOFSEL1;            // Set max. DCO setting
    CSCTL2 = SELA_0 + SELS_3 + SELM_3;      // set ACLK = XT1, pg 74; MCLK = DCO, pg 73
    CSCTL3 = DIVA_3 + DIVS_0 + DIVM_0;          // set all dividers to 0
    CSCTL4 |= XT1DRIVE_0;
    CSCTL4 &= ~XT1OFF;

    So, I plan to connect the input signal to P1.1 (TA1CLK corresponds to P1.1)
    I am thinking of using Timer A to count TA1CLK and use capture for the edges of ALCK.
    Does you have any suggestion on how to do this?

    Thanks

    Edit:
    Since my input frequency range is low (0-150Hz), I will be using a 32kHz microcrystal and will divide ALCK by 8.

    Edit2:
    From the user guide, I'm getting this.

    The timer clock can be sourced from ACLK, SMCLK, or externally via TAxCLK or INCLK. The clock
    source is selected with the TASSEL bits. The selected clock source may be passed directly to the timer or
    divided by 2, 4, or 8, using the ID bits. The selected clock source can be further divided by 2, 3, 4, 5, 6, 7,
    or 8 using the TAIDEX bits. The timer clock divider logic is reset when TACLR is set.


    TA1CTL = TASSEL_0 + MC_2      //Set source as TA1CKL, continuous up mode


    Then I would need to use capture compare control register for ACLK edges
    TAxCCTL0 

  • Quy Tran said:
    I am thinking of using Timer A to count TA1CLK and use capture for the edges of ALCK.
    Does you have any suggestion on how to do this?

    I'm afraid I have very little experience with the capture/compare modes of the MSP430 Timer. But I'm sure someone else will jump in with some suggestions....

  • Regarding timer capture mode - please refer to timer source code examples, there's one for period and duty cycle measurement. You can add some averaging for couple/as_many_as_needed of period measurements and you are done.

    Quy Tran said:
    Since my input frequency range is low (0-150Hz), I will be using a 32kHz microcrystal and will divide ALCK by 8.

    You don't need to decrease resolution here because 16bit timer have 2 second period at this freq.

  • Ilmars said:

    Regarding timer capture mode - please refer to timer source code examples, there's one for period and duty cycle measurement. You can add some averaging for couple/as_many_as_needed of period measurements and you are done.

    Hmm, I only saw how to generate PWM signals by defining the period and duty cycle. I guess I have to examine it more.

  • Quy Tran said:
    Hmm, I only saw how to generate PWM signals by defining the period and duty cycle. I guess I have to examine it more.

    Perhaps you need to get new version for your chip or check g2xx3 source (rev.B) I am looking at right now:

    msp430g2xx3_ta_21.c

  • Ilmars said:

    Hmm, I only saw how to generate PWM signals by defining the period and duty cycle. I guess I have to examine it more.

    Perhaps you need to get new version for your chip or check g2xx3 source (rev.B) I am looking at right now:

    msp430g2xx3_ta_21.c

    [/quote]

    Ilmars,

    Thank you for pointing out that specific file. I am now looking at a data sheet from that family and my chip family to see if I can use the code by modifying.

    I was wondering if you can clear up some things for me if possible. I apologize in advance if these seem trivial.
    From what I am understanding, that example performs the following:
    -8MHz SMCLK for Timer_A clock source (TASSEL_2)
    -Timer_A Capture/Compare control (TA0CCTL1) is set to capture at rising and falling edges for period calculations
    -Interrupt occurs when capture occurs
    -The capture input signal is synchronized with the Timer_A clock 
    -When it goes to ISR, the time stamp of a rising edge (or falling edge) is captured. The time stamp is based on Timer_A

    Question 1: 
    Why doesn't it use ALCK/LFXT1 - 32kHz - for timer? Is it because it just syncs with the SMCLK to determine the period by subtracting time stamps of rising edges; thus, it doesn't need an external oscillator to perform frequency calculations as the method that I discussed in my first post? They use a 32kHz for a PWM output signal which I guess is for output accuracy.

    Question 2:
    To define a input direction of P1.1, they have set "P1DIR &=~BIT2"
    I thought Bit=0 means input direction and Bit=1 means output direction, so the ~ makes sense but....
    Why isn't it "P1DIR &=~BIT1" for a pin P1.1?

    Question 3:
     Ok, this is the worst question. Why are cases needed?

     From my knowledge, I am guessing it's because of the flags of interrupts and handling multiple interrupts? I will probably need to read more about this.

  • Quy Tran said:
    Question 1: 
    Why doesn't it use ALCK/LFXT1 - 32kHz - for timer?

    Because measuring clock properties using same clock is no big deal.

    Q2 you shall answer yourself reading user manual of your chip (series). If you are still puzzled - come back and ask again :)

    Quy Tran said:
    Ok, this is the worst question. Why are cases needed?

    Worst question indeed ;) If this does not answer - come back and ask again :)

  • Ilmars,

    Haha... thanks for clearing some of that up. I looked more into the datasheet  (^_^)
    However, I still can't make it work. I tried to model my code after the example that you suggested and am stuck. The following is what I tried.
    MSP430FR5739: http://www.ti.com/lit/ds/symlink/msp430fr5739.pdf
    Family User Guide: http://www.ti.com/lit/ug/slau272b/slau272b.pdf


    #include <msp430.h>

    unsigned Count, First_Time;
    unsigned REdge1, REdge2, FEdge;
    unsigned Period, ON_Period;
    unsigned DutyCycle;

    int main(void)
    {

    WDTCTL = WDTPW + WDTHOLD;

    PJSEL0 |= BIT4 + BIT5;                                 // XT1 Setup,
     
      CSCTL0_H = 0xA5;
      CSCTL1 |= DCOFSEL0 + DCOFSEL1;           // Set max. DCO setting
      CSCTL2 = SELA_0 + SELS_3 + SELM_3;     // set ACLK = XT1, pg 74; MCLK = DCO, pg 73
      CSCTL3 = DIVA_0 + DIVS_0 + DIVM_0;         // set all dividers to 0
      CSCTL4 |= XT1DRIVE_0;
      CSCTL4 &= ~XT1OFF;

     // Configure Port Pins
    P1DIR &= ~BIT1;                             //P1.1/TA0.2 Input Capture, pg 295, Bit=0 for input direction
    P1SEL0 |= BIT1;                             //TA0.2 option select

    // Configure the TA0CCR1 to do input capture
    TA0CCTL2 = CAP + CM_3 + CCIE + SCS + CCIS_0; // CAP, TA0CCR1 Capture mode; CCIS, capture input select CCI1A; Both
                                                                                                  // CM_3, Rising and Falling Edge; CCIE, interrupt enable, pg 352
    TA0CTL = TASSEL_1 + MC_2 + TACLR;                      //Set source as ACLK, continuous up mode, start timer

    // Variable Initialization
    Count = 0x0;
    First_Time = 0x01;

     while(1)
      {
          __bis_SR_register(LPM0_bits + GIE);   // Enter LPM0
          __no_operation();                     // For debugger

          // On exiting LPM0
          if (TA0CCTL2 & COV)                   // Check for Capture Overflow
          {
              while(1);                         // Loop Forever
          }
          Period = REdge2 - REdge1;             // Calculate Period
          ON_Period = FEdge-REdge1;             // On period
          DutyCycle = (ON_Period*100/Period);
      }
    }


    #pragma vector = TIMER0_A1_VECTOR
    __interrupt void TIMER0_A1_ISR (void)
    {
      switch(__even_in_range(TA0IV,0x0E))
      {
          case  0: break;                 // Vector  0:  No interrupt
          case  2: break;                 // Vector  2:  TACCR1 CCIFG
          case 4: break;                  // Vector  4:  TACCR2 CCIFG
          if (TA0CCTL2 & CCI)      // Capture Input Pin Status
          {
              // Rising Edge was captured
              if (!Count)
              {
                  REdge1 = TA0CCR2;
                  Count++;
              }
              else
              {
                  REdge2 = TA0CCR2;
                  Count=0x0;
                  __bic_SR_register_on_exit(LPM0_bits + GIE);  // Exit LPM0 on return to main
              }
              if (First_Time)
                  First_Time = 0x0;
          }
          else
          {
              // Falling Edge was captured
              if(!First_Time)
              {
                  FEdge = TA0CCR2;
              }
          }
          break;
          case 6: break;                      // Vector  6:  TACCR3 CCIFG
          case 8: break;                      // Vector  8:  TACCR4 CCIFG
          case 10: break;                       // Vector 10:  TACCR5 CCIFG
          case 12: break;                       // Vector 12:  TACCR6 CCIFG
          case 14: break;                       // Vector 14:
          default:     break;
      }
    }

    On another note, I have also attempted to use a comparator with a internal ref voltage. Between two high signals of the comparator, I would count the amount of rising edges in a much higher frequency clock. The unknown frequency would be [(known high freq)/(count)] = (unknown freq).
    Unfortunately, while comparator works, I don't know how to implement counting rising edges of a known clock. I am guessing it would be nearly the same as above. I would use the timer capture.

    Edit:
    I'm sorry for making this long and asking what may be trivial to others, I am pretty much in the learning phase of coding and using the MSP430. I thank you for helping me thus far.

  • The break in case 4: break; should be deleted. Otherwise the if (... statement cannot be reached.

  • old_cow_yellow said:

    The break in case 4: break; should be deleted. Otherwise the if (... statement cannot be reached.

    /facepalm

    old_cow_yellow,

    Well, that's one glaring mistake, Thank you very much for pointing that out.

  • Quy Tran said:
    Unfortunately, while comparator works, I don't know how to implement counting rising edges of a known clock. I am guessing it would be nearly the same as above. I would use the timer capture.

    BTW it's possible to connect comparator output to timer capture so you can measure comparator output instead of I/O pin input.

  • Ilmars said:

    Unfortunately, while comparator works, I don't know how to implement counting rising edges of a known clock. I am guessing it would be nearly the same as above. I would use the timer capture.

    BTW it's possible to connect comparator output to timer capture so you can measure comparator output instead of I/O pin input.

    [/quote]

    Ilmars,

    EDIT:
    From the Comparator_D introduction section in my family user guide, it says the "output provided to Timer_A capture input." I just don't know how to set this up. Is it automatically internally setup to TImer_A or would I have to output COUT to a certain pin?

    TA0CCTL2 = CAP + CM_3 + CCIE + SCS + CCIS_0;
    // CAP, TA0CCR2 Capture mode; CM_3, Rising and Falling Edge; CCIE, interrupt enable; CCIS, capture input select CCIxA;

    Basically, how do I make the CCIS_0 select CDOUT as the capture input

  • Quy Tran said:
    From the Comparator_D introduction section in my family user guide, it says the "output provided to Timer_A capture input." I just don't know how to set this up.

    Here's some clues. Please read whole thread because initially Cow did not get question right.

  • Ilmars said:

    From the Comparator_D introduction section in my family user guide, it says the "output provided to Timer_A capture input." I just don't know how to set this up.

    Here's some clues. Please read whole thread because initially Cow did not get question right.

    [/quote]

    That actually raises more questions...

    In that thread, they use the MSP430G2213 chip. According to the MSP430Gx2xx Family's User Guide, the comparator can be outputted to CCI1B.

    But, according to (he is right in this regard), that the datasheet lists P2.2 TA1.1 (Timer1_A capture CCI1B input, compare: Out1 output)

    He assumes that the since the comparator is not mentioned here, there is no reason to assume that the comparator output is connected to this pin. Then, why does the block diagram show otherwise? Maybe, I am misinterpreting.

    Also....

    old_cow_yellow said:


    Q: ... I'm using the comparator with the output going to P1.3/CAOUT to trigger some external hardware. I also want to time the comparator. I see the timer output connects to Timer_A CCI1B, correct? ...

    A: There are two Timers (called Timer0 and Timer1), CAOUT is connected internally to Timer0_A3 CCI1B.
     
    Q: ... If I set up Timer1_A3 CCR1 to capture edges on CCI1B it looks like the comparator output will also appear on that pin (p2.2) - is that correct? …

    A: No. Only CCR1 of Timer0 (not 1) can be set up to capture edges on CAOUT with CCI1B.  There is no additional output at P2.2 or any other pin.

    Q: ... I thought I could connect the comparator output direct to the timer without a pin, but maybe not? ...

    A: Yes, it can be connected to Timer0_A3 CCR1 internally without a pin.

    This is also confusing to me. If that previous block diagram is right, then why does old_cow_yellow state that the comparator output is connected to Timer0_A3 CCI1B? Wouldn't it be Timer1_A3 CCI1B that the OP of that thread mentioned before?

    My final question would then be... is the comparator out automatically outputted to CCIB internally or do you have to set it up somehow? I could do what Jens mentioned at the end and just connect it externally from one pin (having comparator output) to another pin (where timer capture input is set).

  • According to your original posting:

    … I have a square wave signal coming out of a schmitt trigger that has a frequency range of 0-150Hz with max 3.3V going into the msp430.

    And you asked:

    Is it possible to do this the following
    “Have a known faster clock signal run and count the rising edges in one period of the input signal.

    “Then unknown freq= known/count”

    My answer is: “Yes that is a good way to do it.”

    But later on, you were sidetracked and asked about using Comparator output to feed the Timer Capture. This is entirely unnecessary for the kind of square wave you specified; and you were confused by discussions irrelevant to your case. If you do want to discuss that subject, please start another conversation.

  • Quy Tran said:
    According to the MSP430Gx2xx Family's User Guide, the comparator can be outputted to CCI1B.

    Which CCI1B? TA0.CCI1B or TA1CCI1B.
    "CCI1B" is a module input name, not a global signal name. And there could as well be a CCI1B of TimerB0. All different signals.
    It is unlucky that the users guide uses a module input name (which can exist multiple times even though not the same signal for all modules) is used as identifier for a conneciton between the comparator and a timer. The correct way would have been to just name it 'CDOUT" and leave it to the user to find this CDOUT listed as connected to a timer CCR register capture input. Well, it's difficult to write a common description for a modular system. I face dit myself, at  away lower complexity level, and still got gray hair.
     But for all but the TimerA0 signals, the timer would/should precede the signal name.

    If you look at the TimerA0/TimerA1 signal mapping table in the device specific datasheet (page 28 of slas639E) things are clear:

    For G2213:

    However, wasn't the thread about the FR5739? Here, the FR57xx family users guide needs to be used. And the datasheet tells that the comparator output is available for both TimerA as well as TimerB0 as CCI1B but not for TimerB1/2.

**Attention** This is a public forum