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: Frequency Capture on MSP430FR5969

Part Number: MSP430FR5969

Hi experts,

I want to capture frequency using external timers on MSP430FR5969. How can I do it? any suggestions shall be appreciated.

  • Hi Manish,

    if I understand you correctly, you like to measure an external frequency. Right?

    What is the frequency you are going to measure?

    Can you please check some e2e threads which may help you.

    for example:

    Link1

    Link2

    Let me know if that helps as first.

    regards

    kostas

  • Hi Manish,

    here another link which may help.You would need to adapt to your device.

    https://forum.43oh.com/topic/3317-msp430f550x-based-frequency-meter

    Regards

    Kostas

  • hey Kostas,

    your understanding is correct I need to capture external frequency I have set my clock source as SMCLK to 8mhz Here is my complete code please correct me if I misconfgured anything

    #include <MSP430FR5969.h>

    #define NUMBER_TIMER_CAPTURES       40

    volatile unsigned int timerAcaptureValues[NUMBER_TIMER_CAPTURES];
    unsigned int timerAcapturePointer = 0;

    int main(void)
    {
      WDTCTL = WDTPW | WDTHOLD;                 // Stop watchdog timer
      P1OUT &= ~0x01;
      P1DIR |= 0x01;  
      P1DIR |= BIT2;                     // P1.2
      P1SEL0 |= BIT2;
     
      P2DIR |= BIT0;
      P2SEL0 |= BIT0;                           // Output ACLK
      P2SEL1 |= BIT0;
     
      P3DIR |= BIT4;
      P3SEL0 |= BIT4;                           // Output SMCLK
      P3SEL1 |= BIT4;
     
        PJSEL0 |= BIT4 | BIT5 | BIT6 | BIT7;      // For XT1 and XT2

      PM5CTL0 &= ~LOCKLPM5;
      // Clock System Setup
    CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers
      CSCTL1 = DCOFSEL_6;                       // Set DCO to 8MHz
      CSCTL2 = SELA__LFXTCLK | SELS__HFXTCLK | SELM__DCOCLK;
      //CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
      CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;     // Set all dividers to 1
      CSCTL4 |= LFXTDRIVE_3 | HFXTDRIVE_3;
      CSCTL4 &= ~(LFXTOFF | HFXTOFF);
      do
      {
        CSCTL5 &= ~(LFXTOFFG | HFXTOFFG);       // Clear XT1 and XT2 fault flag
        SFRIFG1 &= ~OFIFG;
      }while (SFRIFG1&OFIFG);                   // Test oscillator fault flag
      CSCTL0_H = 0;
     
      __delay_cycles(1000);                     // delay for Clock init
     
      TA0CCTL2 = CM_1 | CCIS_1 | SCS | CAP | CCIE;
      TA0CTL = TASSEL__SMCLK | MC__CONTINUOUS;
      __bis_SR_register(LPM0_bits | GIE);
      __no_operation();
    }

    // Timer0_A3 CC1-4, TA Interrupt Handler
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = TIMER0_A1_VECTOR
    __interrupt void Timer0_A1_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(TIMER0_A1_VECTOR))) Timer0_A1_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
      switch (__even_in_range(TA0IV, TA0IV_TAIFG)) {
        case TA0IV_TA0CCR1:
          break;
        case TA0IV_TA0CCR2:
          timerAcaptureValues[timerAcapturePointer++] = TA0CCR2;

          if (timerAcapturePointer >= 40) {
            while (1) {
              P1OUT ^= 0x01;                    // Toggle P1.0 (LED)
              __delay_cycles(100000);
            }
          }
          break;
        case TA0IV_TA0IFG:
          break;
        default:
          break;
      }
    }

  • Hi Manish,

    short question.

    Have you tested the code on your setup? does it work so far?

    Regards

    Kostas

  • Hey Kostas,

    I have tested the code on my setup but I'm unable to capture current frequency.

  • Hey kostas and all experts,

    I need to ask a simple question I have configured my device on SMCLK as 8Mhz and I need to capture external frequency which I have measured from Oscilloscope and it is around 390Khz will my code will able to measure that? Here is my code please give any suggesetions as I'm unable to move further. I shall be grateful for that act. Here is my code.

    #include <MSP430FR5969.h>

    #define NUMBER_TIMER_CAPTURES       40

    volatile unsigned int timerAcaptureValues[NUMBER_TIMER_CAPTURES];
    unsigned int timerAcapturePointer = 0;

    int main(void)
    {
      WDTCTL = WDTPW | WDTHOLD;                 // Stop watchdog timer
      P1OUT &= ~0x01;
      P1DIR |= 0x01;  
      P1DIR |= BIT2;                     // P1.2
      P1SEL0 |= BIT2;
     
      P2DIR |= BIT0;
      P2SEL0 |= BIT0;                           // Output ACLK
      P2SEL1 |= BIT0;
     
      P3DIR |= BIT4;
      P3SEL0 |= BIT4;                           // Output SMCLK
      P3SEL1 |= BIT4;
     
        PJSEL0 |= BIT4 | BIT5 | BIT6 | BIT7;      // For XT1 and XT2

      PM5CTL0 &= ~LOCKLPM5;
      // Clock System Setup
    CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers
      CSCTL1 = DCOFSEL_6;                       // Set DCO to 8MHz
      CSCTL2 = SELA__LFXTCLK | SELS__HFXTCLK | SELM__DCOCLK;
      //CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
      CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;     // Set all dividers to 1
      CSCTL4 |= LFXTDRIVE_3 | HFXTDRIVE_3;
      CSCTL4 &= ~(LFXTOFF | HFXTOFF);
      do
      {
        CSCTL5 &= ~(LFXTOFFG | HFXTOFFG);       // Clear XT1 and XT2 fault flag
        SFRIFG1 &= ~OFIFG;
      }while (SFRIFG1&OFIFG);                   // Test oscillator fault flag
      CSCTL0_H = 0;
     
      __delay_cycles(1000);                     // delay for Clock init
     
      TA0CCTL2 = CM_1 | CCIS_1 | SCS | CAP | CCIE;
      TA0CTL = TASSEL__SMCLK | MC__CONTINUOUS;
      __bis_SR_register(LPM0_bits | GIE);
      __no_operation();
    }

    // Timer0_A3 CC1-4, TA Interrupt Handler
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = TIMER0_A1_VECTOR
    __interrupt void Timer0_A1_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(TIMER0_A1_VECTOR))) Timer0_A1_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
      switch (__even_in_range(TA0IV, TA0IV_TAIFG)) {
        case TA0IV_TA0CCR1:
          break;
        case TA0IV_TA0CCR2:
          timerAcaptureValues[timerAcapturePointer++] = TA0CCR2;

          if (timerAcapturePointer >= 40) {
            while (1) {
              P1OUT ^= 0x01;                    // Toggle P1.0 (LED)
              __delay_cycles(100000);
            }
          }
          break;
        case TA0IV_TA0IFG:
          break;
        default:
          break;
      }
    }

    Please Correct my understanding if I'm wrong.

  • Hi Manish,

    At a first look the code will not work.

    What is your input pin for the external signal?

    Also the

        CSCTL0_H = 0;                             // Lock CS module

    is missing.

    I will check that in detail, but can you please have a look into the LINK1 given above.

    This should be a good starting point.

    Regards

    Kostas

  • hey kostas,

    my input pin for external frequency is port1.2.

    Can you say why my code will not work? Any in my code

    CSCTL0_H = 0;                             // Lock CS module

    is not missing I have used it please cross verify once again? Can you specify me why this will not work and is there an alternative solution for that? If yes then please let me know as soon as possible, I shall be grateful for that.

  • Trying to capture a 390kHz signal directly at 8MHz is infeasible, since that only gives you 20 CPU clocks to process each capture.

    The recommended method for a fast signal is frequency-counting by connecting the signal to the clock input for the timer.

    Perhaps you already knew this, since most of the infrastructure for doing this is already present in this program. But you haven't set TA0 for TACLK, so you need:

    >  P1DIR |= BIT2;                     // P1.2
    >  P1SEL0 |= BIT2;

    should be:

    >  P1DIR   &= ~BIT2;                     // P1.2 as TA0CLK per SLAS704G Table 6-49
    >  P1SEL1 |=    BIT2;

    and

    >  TA0CTL = TASSEL__SMCLK | MC__CONTINUOUS;

    should be:

    >  TA0CTL = TASSEL__TACLK | MC__CONTINUOUS; // Clock from P1.2 (TA0CLK)

    For the archaeologists: What's happening here is that TA0 is clocking from the external signal, and the capture (CCIS=1) is triggering on ACLK, every ~32usec. The capture counts can be used to measure the input frequency over a fairly short fixed period. The program has about (32us at 8MHz)=256 CPU clocks to process each capture.

    -------------------

    Are you using the Launchpad? As delivered, the high frequency crystal (Y1) is not populated. Is it possible your program is stuck waiting (forever) for the HFXT to start up?

  • Hi Manish,

    I agree with what Bruce stated above.

    But this is what was implemented in the LINK1 I sent you already twice. You should have had looked in that. There is this implementation described.

    Below an example code which I tested with 250kHz external signal on the P1.3 pin.

    You can use also the P1.2 input as described above by Bruce.

    =====================================

    // MSP430FR5969
    // External Frequency capture on P1.3

    #include <msp430.h>

    #define NUMBER_TIMER_CAPTURES       20

    volatile unsigned int timerAcaptureValues[NUMBER_TIMER_CAPTURES];
    unsigned int timerAcapturePointer = 0;
    unsigned int result = 0;


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

        // Configure GPIO
        P1DIR &= ~BIT3;                           // Use Timer A1 and CCR 2 register
        P1SEL1 &= ~BIT3;                          // Set P1.3 to input direction
        P1SEL0 |= BIT3;                           // (TA1.CCI2A)
                                                  // Use Timer A1 and CCR 2 register
        // Optional SMCLK output to pin
        P3DIR |= BIT4;                            // P3.4 set to dir output (DS Table 6-57)
        P3SEL1 |= BIT4;                           // select Output for SMCLK


        // Disable the GPIO power-on default high-impedance mode to activate
        // previously configured port settings
        PM5CTL0 &= ~LOCKLPM5;

        // Clock System Setup: Set DCO frequency. Set divider and source for ACLK, SMCLK, MCLK
        CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers
        CSCTL1 = DCOFSEL_6;                       // Set DCO frequency to option 6: ->8MHz
        CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;  // Set source for SMCLK = MCLK = DCO, ACLK = VLOCLK
        CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;     // Set all dividers to 1
        CSCTL0_H = 0;                             // Lock CS module (use byte mode to upper byte)

        __delay_cycles(1000);                     // Allow clock system to settle

        // Timer0_A3 Setup
        TA1CTL = TASSEL__SMCLK | MC__CONTINUOUS;    // Use SMCLK as clock source,
                                                    // Start timer in continuous mode

        TA1CCTL2 = CM_1 | CCIS_0 | SCS | CAP | CCIE;// (Timer A1, CC block 2)
                                                    // CM_1: Capture mode rising edge,
                                                    // CCIS_0: Use CC input CCI2A=P1.3, see DS
                                                    // SCS: Synchronous capture,
                                                    // CAP: Mode 1->Capture, 0->Compare, Enable capture mode,
                                                    // CCIE: Enable capture interrupt


        __bis_SR_register(LPM0_bits | GIE);         // Enable LPM and General Interrupt
        __no_operation();
    }

    // Timer1_A3 CC1-4, TA Interrupt Handler
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = TIMER1_A1_VECTOR
    __interrupt void Timer1_A1_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(TIMER1_A1_VECTOR))) Timer1_A1_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
      switch (__even_in_range(TA1IV, TA1IV_TAIFG))
      {
        case TA1IV_TA1CCR1:
          break;
        case TA1IV_TA1CCR2:
          timerAcaptureValues[timerAcapturePointer++] = TA1CCR2;    // Store values in the array
          if(timerAcapturePointer == 20)
          {
              timerAcapturePointer = 0;
    //        Example calculation of two consecutive values
              result = ((timerAcaptureValues[11]) - (timerAcaptureValues[10]));
              __no_operation();           // Set a breakpoint here

          }

          break;
        case TA1IV_TA1IFG:
          break;
        default:
          break;
      }
    }

    I hope that helps to solve your problem.

    Regards

    Kostas

  • Due respect: It's not the same. The LINK1 example (above) uses TASSEL=SMCLK and CCIS=CCI2A (signal pin), This is the "direct" approach I referred to, which I believe is not feasible at 390kHz (I'm a bit surprised it succeeded at 250kHz).

    What I was suggesting was a reversal, with TASSEL=TACLK and CCIS=CCI2B (ACLK). This clocks the timer with the input signal, and gathers the counts at a fixed (ACLK) interval, a much more leisurely pace. The arithmetic is slightly different, but not more complex.

  • Bruce, thank you for the clarification and  for the good inputs. I think it's worth for me to try that out.

    Regards Kostas

  • Hey Kostas,

    The code which you gave is not entering into the ISR itself.

    Thanks Bruce and Kostas for the help

  • Hi Manish,

    Have you connected the input signal to the correct pin?

    P1.3

    Regards

    Kostas

  • Hi Kostas,

    I did but it was not entering into the ISR. So, I have dropped that method and adopted a new method. In that code I was using DCO now I want to use external clock 8MHz as SMCLK. Can you please help me to do so? I also need to user dividers for Timers can anyone help me to do so. I did not get any example for that. Please share if you have any such kind of example.

  •  Manish,

    sad to hear that. I re-tested on my side and it works.

    It would be good to find-out the reason for not working, but if you don't interested or do not have time to do that, let's close that thread.

    For the new request, I would suggest to open a new thread, just  to keep the requests separated.

    Thanks

    Best Regards

    Kostas

  • Hey Kostas,

    I will re check that code why it is not working.

  • Hi Kostas,

    Thanks for the code.

**Attention** This is a public forum