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.

frequency measurment

2260.freq-code.docx

hi,

i need to measure the 1k hz cro frequency.

In TI code examples i found this code.what i understood from this code is ,it is used to measure the 4 KHZ(ACLK/8).they captured the starting edge and ending edge and calculate the difference.But why they taken array to measure 4 k hz.

after exicuting this code where we can see the difference of edges.

can we see in diassembly or register in view menu.

plz help me.

regards

chandrika

  • The demo is not calculating any frequency. It is just capturing 16 edges into the array, so you can read them with the debugger after the 32th has been captured and the breakpoint is hit.

    I don't know what this count==32 is for - after 16 coutns you start overwriting the first 16 values (maybe it is for discarding the first run).

    To see the values, you have to look at diff_array or capture_array in the debugger.
    There is no output over a serial connection or such.

  • Hi JENSE,

    thank u for the reply.For frequency measurment i used the following code.intially i tried to measure the oscilloscope frequency(1khz). i connected the controller potr pin

    (taccr1 pin) to the positive of oscilloscope and ground pin of controller to the oscilloscope gnd.but i dont know where is the mistake buffer array is showing zero value.and one more doubt is in this buffer is all values (0-99) display same value?

    plz help me.it is very important for me it is  the part of my acadamic project.

    #include <msp430x22x4.h>


    #define CLRBIT(dest,mask)                             ((dest) &= ~(mask))
    #define CLEAR_INTERRUPT_FLAG()            (CLRBIT(TACCTL1,CCIFG))

    unsigned int buffer[100];
    unsigned int i=0;

    unsigned int Current_Edge_Time;
    unsigned int Previous_Edge_Time;

    void main(void)
    {
        WDTCTL = WDTPW + WDTHOLD;          // Stop WDT
       
        BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz
        DCOCTL = CALDCO_1MHZ;
       
        P2DIR &= ~BIT3;                                          //Port 1.2 - Input
        P2SEL |= BIT3;
       
        TACTL = TASSEL_2 + MC_2;                    // SMCLK = 1 Mhz, continuous mode
        TACCTL1 = CM_3+CCIS_1+SCS+CAP+CCIE;
           
        _BIS_SR(GIE);   
    }   
       
    // Timer A1 interrupt service routine
    #pragma vector=TIMERA1_VECTOR
    __interrupt void Timer_A (void)
    {      
        Current_Edge_Time = TACCR1;
               
         buffer[i++] = Current_Edge_Time - Previous_Edge_Time;            
        
        Previous_Edge_Time = Current_Edge_Time;   
       
        if (i>100)

      {

      i=0;
            __no_operation();                       // PLACE BREAKPOINT HERE
        
           
    }

  • (1) You said "i tried to measure the oscilloscope frequency(1khz)". What is the voltage of that signal from the oscilloscope? What is the voltage limits of MSP430 chip?

    (2) You said "i connected the controller potr pin (taccr1 pin) to the positive of oscilloscope" in your posting, But you told the compiler "P2DIR &= ~BIT3; P2SEL |= BIT3;". You also have the comment "//Port 1.2 - Input". What is going on? Was it taccr1 pin? P2.3? Or, P1.2?

    (3) You defined something you called "CLEAR_INTERRUPT_FLAG()". Yet you never used it. What is it for and why did you define it?

    (4) You said "this buffer is all values (0-99) display same value". But your break-point is hit after "if (i>100)". What happens when i=100?

  • thanks for the reply.

    actually i taken this code from one of forumn post.

    voltage of the oscilloscope is 5 volts.msp430 voltage range is 1.8 v to 3.5 v.S0 i divide the voltage using 2.7k and 1.8 k. resistors now iam giving voltage 3 v.

     

    sorry for mistake. iam using p2.3 to taccr1.

    really speaking i did not understand that buffer plz explain me how to use that.

  • old_cow_yellow said:
    What is the voltage of that signal from the oscilloscope?

    On my oscilloscope, the calibration output is 1V (which wouldn't trigger the MSP even if not further divided), but if he says that his Osczi is outputting 5V, then this should be okay.

     

    old_cow_yellow said:
    You said "this buffer is all values (0-99) display same value". But your break-point is hit after "if (i>100)". What happens when i=100?

    Good question. Depending on the placement of the variables, the function might put a 101th value into the array, overwriting index counter. But even if, the sampling will either continue again filling the buffer (or parts of it), or be >100 and hit the breakpoint. In any case, when the breakpoint is hit, there should be data in the array. So why isn't it?

     

    I think the problem is that the interrupt flag for CCR1 is not reset inside the ISR. Neither by manually setting it to 0 nor by reading the TA1IV vector register. So the ISR is executed immediately after exiting once mor, even if no new interrupt has occurred. This will fill the whole buffer right after the first interrupt and of course the differences are all 0 as there did no second capture interrupt happen in the short time required to fill the buffer up.

    It's important to know that the interrupt for CCR1 is a shared interrupt with multiple interupt sources (TAOV, CCR3,...) which must be checked (directly or by the TAIV register) and reset, while the CCR0 interrutp only has a single interrupt source (CCR0) and is automatically resetting the interrupt flag as soon as the ISR is entered.

  • hi,

    i have done some modifications in my programme eventhough iam not getting proper output iam getting some random numbers.

    iam confusing where i need to put break point.after putting brak point.

    plz tell me how to exicute the programme after placing breakponts.is there any method?

    and also CCIFG BIT IS SET IN ALL TACCR0 ,TACCR1 AND TACCR2 registers.

     

     

    #include <msp430x22x4.h>
    #include <intrinsics.h>
    #include <stdint.h>
    #define CLRBIT(dest,mask)                             ((dest) &= ~(mask))
    unsigned int i;
    void main(void)
    {
        WDTCTL = WDTPW + WDTHOLD;          // Stop WDT
        BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz
        DCOCTL = CALDCO_1MHZ;
        P2DIR &= ~BIT2;                                          //Port 2.2 - Input
        P2SEL |= BIT2;
        TACTL = TASSEL_2 + MC_2 + TACLR;                    // SMCLK = 1 Mhz, continuous mode
        TACCTL0 = CM_3+CCIS_1+SCS+CAP+CCIE;
        __bis_SR_register( GIE);
    }

    // Timer A0 interrupt service routine
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
        static uint16_t LastTime = 0;  // Last time captured
        i=(TACCR0 - LastTime );       //  (counts)
        LastTime = TACCR0  ;           // PLACE BREAKPOINT HERE
    }

  • chandrika surapaneni said:
    iam getting some random numbers

    No wonder. Capturing is a real-time process. If ou interfere with it by putting breakpoints into the code, you destoy any timing.

    You have to collect the individual readings into an array and check when teh array is filled. Then set a breakpoint there and look at the array from the debugger.

    Also, since you initialize the LastTime variable with 0, independently of teh real time when the last edge was coming, your first reading will always be random. (there is no crystal-orb-module in the MSP that can tell when there was a signal edge before the code started).

    chandrika surapaneni said:
    CCIFG BIT IS SET IN ALL TACCR0 ,TACCR1 AND TACCR2

    Sure. Since the CCRx registers always hold a value (usually 0) and the timer is always counting, sooner or later any CCRx unit will trigger a compare interrupt. It won't trigger an ISR as the IE bit isn't set, but the interrupt flags are set when the timer matches the CCRx register. Which will always happen sooner or later.

     

     

  • hi jense,

    now i can measure the frequency in the range of 100 hz to 2000 hz.iam getting the count range 1000 to 500 for frequency of 100hz to 2000hz..

    i calculated frequency in the following way

    known frequency=counts*unknown frequency.

    here i taken known frequency is SMCLK freq=1MHZ

    Thanks for ur support.

  • chandrika surapaneni said:
    iam getting the count range 1000 to 500 for frequency

    I guess you meant 10.000 :) Well, that's why one would expect for 1MHz timer clock. Looks good.

    chandrika surapaneni said:
    known frequency=counts*unknown frequency.

    Yep. Or (since the unknown frequency is what one wants to know):

    unknown frequency = known frequency / counts.

    Note that (since counts is an integer), the resolution gets more and more 'grainy' the higher the measured frequency is. So you can only separate 1MHz (counts = 1), 500kHz (counts = 2) and 330kHz (counts=3) but nothing in between. On the lower end, however, you'll get a minimum frequency of 16Hz (below you'll see a counter overflow) but with a resolution of 0.006Hz.
    Basically, for frequencies above 10kHz, your resolution error exceeds 1%, rapidly raising.

    Not to mention that there might be synchronisation problems, resulting an a +-1 counts reading.

  •  

    hi,

    iam developing maximum power point tracking algorithm for microgenerator using msp430 micro controllers. for geting maximum power  we derived pwm duty cycle equation (duty cycle=((0.00008)*s+0.354)).here 's' is speed.So iam giving speed input.speed range is 100RPM  to 2000 RPM.so i developed the following code .plz check it whether it is correct or not.

     

     

    #include <msp430x22x4.h>
    unsigned int s=100;
    void main(void)
    {
        WDTCTL = WDTPW + WDTHOLD;                     // Stop WDT
        BCSCTL1 = CALBC1_1MHZ;                       // Set DCO to 1MHz
        DCOCTL = CALDCO_1MHZ;
        P2SEL |= BIT3;                              //Port 2.3/TACCR1 - OUTPUT
        P2DIR | = BIT3;                            // PWM period
        CCR0 = 524-1;
        CCR1 = ((0.00008)*S + 0.354);              // pwm duty cycle  
        TACTL = TASSEL_2 + MC_1 + TACLR;           // SMCLK = 1 Mhz, up mode
        TACCTL1 = outmod_7+CCIE;                  // CCR1 used for timer compare
        s=100;
      __bis_SR_register(CPUOFF + GIE);          // LPM0, ADC10_ISR will force exit
        __no_operation();
       
    // Timer A1 interrupt service routine
    #pragma vector = TIMERA1_VECTOR
    __interrupt void TA1_ISR(void)
    {
      switch (__even_in_range(TAIV, 10))        // Efficient switch-implementation
      {
        case 0: break;
        case 2:                              
          for(s=100;s<=2000;s++)
          {
          CCR1=((0.00008)*S+0.354);             //duty cycle variation
          }
          if (s>2000)
          {
            s=100;
            __no_operation();                  
          }
          break;
        case 4: break;                          // CCR2 interrupt
        case 6: break;                          // Reserved
        case 8: break;                          // Reserved
        case 10: break;                         // Timer Overflow
      }
    }


     

  • chandrika surapaneni said:
    CCR1 = ((0.00008)*S + 0.354);              // pwm duty cycle  

    Ah, this, cannot work. I guess, teh result of this equation is in the range of 0..1 adnd represents the duty cycle you want. However, CCR1 takes a comparison value (this is what CCR stands for: Capture/Compare Register). It compares its content against the timer value.
    So if you wrote 524-1 to CCR0 (which is basically the same as CCR1 except for the side effect of resetting the timer when the compare is triggered), you'll need to write a value in the range of 0..(524-1) to CCR1 too for a DC of 0..100%

  • Sir,

    thanks for ur reply.i agree with ur point the TACCR1 should be in the range of 0 to TACCR1..

    Actually i need to write the programme for different duty cycleswith different frequencies.frequency range is 100 to 2000 hz. For this i think i need to use 2 lookup tables .one for setting FREQUENCY(TACCR0) and other one is for setting DUTY CYCLE (TACCR1).

    How to use lookup table in MSP430 micro controllers.

    can u share any example codes using lookup tables.

  • chandrika surapaneni said:
    How to use lookup table in MSP430 micro controllers.

    Exactly as you do it on other processors. it depends on teh language (which is usually C/C++).

    But due to limitations of the resources (limited ram), it is advisable to put the taples in flash. Depending on the compiler/linker this is done by just declare them const:

    const unsigned char inverse[256] = {255,254,253,253....};

    so

    unsigned char x = reverse[0];

    will assign 255 to x.

    The MSP uses von-Neumann-Architecture, this means for hte processor ther eis no difference whether data is in ram or flash. It's the same instruction and the same addressing range. Car emut be taken if you have an MSP that has a 20 bit addressing range (>64k flash). Then it is important that the constant data resides below 64k, else accessing it might not work as expected. It depends on the compiler and the toolchain/IDE (project settings, special syntax etc.)

     

  • hi,

    i need to write a programme for different periods and with different duty cycles.i have written the following code.plz verifiy this is it correct?

    #include<msp430x22x4.h>
    #define values 20

    //**********************************************************************************************
    / look up tables for different frequencies and corresponding duty cycles.
    /***********************************************************************************************
    int period[values]={10486,5243,3495,2621,2097,1748,1498,1311,1165,1049,953,879,807,749,699,655,617,583,552,524}
    int duty cycle[values]={3712,1940,1321,1011,826,703,548,496,455,421,393,369,349,331,315,302,290,279,269}
    int index_values=0,
    void main (void)
    {
    WDTCTL=WDTPW+WDTHOLD;            //stop watchdog timer
    PESEL =0X08;                     //p2.3 output                 
    P2DIR =0X08;
    TBCCRO=period[0];                 //pwm period
    TBCTL=TBSSEL-2+MC_1;
    TBCCTL1=OUTMOD_7;
    TBCCR1=duty cycle[0];             //pwm duty cycle
      _BIS_SR(GIE);
    }
    /*****************************************************************
    // Basic Timer Interrupt Service Routine.
    //*****************************************************************
    #pragma vector=BASICTIMER_VECTOR
    __interrupt void basic_timer_ISR(void)
    {
         TBCCR0 = period[index_values];      // get next note
         TBCCR1 = duty cycle[index_values];     // set duty-cicle
        
         index_values++;        // manage note point
         if (index_values == values)
         index_values = 0;
    }

  • chandrika surapaneni said:
    plz verifiy this is it correct?

    It isn't. At least not completely. I didn't check the values itself, but...

    chandrika surapaneni said:
    _BIS_SR(GIE);
    }

    Here the code falls off of main. It is undefined what happens now. It completely depends on the compiler and the provided startup/shutdown code. It may shut down the MSP, trigger a reset, enter a low power mode or simply jump on the place. Better place a while(1); at the end of your main.

    Besides this, the program might work except for one thing: you change the duty cycle and the period without any synchronisation with th ecurrently active PWM signal. This can lead to a large number of glitches in the generated PWM signal.
    Let's say, the period is current 2000. Now you change it to 1000. Wha thappens, if the timer is at 1500 just in this moment? It will not end the cycle at 2000 (since you changed it to 1000) but is already past 1000. Th etiemr will continue until it rolls over at 65535 and begins with 0 again, giving you a loooooong period.
    Same for the duty cycle, you'll probably get a single period with a DC >100% instead of reducing the DC.
    When increasing the period, you risk getting a DC that is too small (since the meaning of the DC value changes with the changed period setting, when increasing the DC on fixed period setting, all that may happen is that you don't know whether the DC will change in the current period (if you increased it before the timer has hit the old value) or in the next one (if you increased it after the timer has already passed the old value)

    Depending on the basic timer period and the SMCLK, you'll get interesting patterns

  • hi,

    i compiled and debug the programme by putting while(1) in my main.well its working and i can display all the values(period and duty cycle).but problem is when i interfaced microcontroller and oscilloscope only first pwm pulse is displaying remaing duty cycle pwm pulses are not displaying.what is the reason can u explain?

**Attention** This is a public forum