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.

Is it possible to get actual number of pulses from a PWM (or Periodic) Timer?

Hello all.

I have set up both timers on Timer0: Timer A triggering the ADC and Timer B as an output PWM signal of that conversion clock in order to get synchronized with other devices.

   SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);
    GPIOPinConfigure(GPIO_PL5_T0CCP1);
    GPIOPinTypeTimer(GPIO_PORTL_BASE, GPIO_PIN_5);

  TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP | TIMER_CFG_B_PWM); //For ADC

    TimerLoadSet(TIMER0_BASE, TIMER_A, (g_ui32SysClock / g_uiSamplingFreq) - 1);
 
    TimerLoadSet(TIMER0_BASE, TIMER_B, (g_ui32SysClock / g_uiSamplingFreq) - 1);
    TimerMatchSet(TIMER0_BASE, TIMER_B, g_ui32SysClock / (g_uiSamplingFreq * 2));  //50% duty cycle at init

  TimerControlTrigger(TIMER0_BASE, TIMER_A, true);  //ADC trigger


TimerEnable(TIMER0_BASE, TIMER_A | TIMER_B);

Everything works fine, but we have some interruptions pins, that we would like to synch with our sampling Timer counter (in specific the number of sample=Timer_pulse that interruption on GPIO occurs). 

However when we try to read the Timer value with TimerValueGet(TIMER0_BASE,TIMER_B) we get a very different number from what we expect.

We have set a counter variable in the ADC_interrupt handler and we can count/time the interruption that way, but we think we should do it by reading the Timer directly and getting the number of pulse since the Timer was enabled last time.

Is there a way to do this?

Thank you

  • Hello PAk,

    The TimerValueGet is to read the running value of the counter. In this case it is TIMERB which is generating PWM Pulses. Hence what it would be reading is the value of the Timer's Internal counter which is used to generate the High and Low Period of the PWM.

    The other way to do is to use a 3rd timer in Input Edge mode to count the number of PWM Pulses. Of course it has to be made sure that the PWM Frequency and Width of ON and OFF time can be captured by the Timer running of the System Clock.,

    Regards

    Amit

  • Thank you Amit

    Amit Ashara said:
    The TimerValueGet is to read the running value of the counter. In this case it is TIMERB which is generating PWM Pulses. Hence what it would be reading is the value of the Timer's Internal counter which is used to generate the High and Low Period of the PWM.

    1. By this, you mean to check periodically the  Timer's Internal counter. I am supposing that to do this, you need more interruptions/readings than the actual PWM frequency.

    Amit Ashara said:
    The other way to do is to use a 3rd timer in Input Edge mode to count the number of PWM Pulses. Of course it has to be made sure that the PWM Frequency and Width of ON and OFF time can be captured by the Timer running of the System Clock.,

    2. I assume that you need to reroute the ouput of the PWM signal to the 3rd timer input, right?

    Regards.

  • Hello PAk,

    1. No. The user of the TimerValueGet will not give the number of PWM frequency pulses, but the counter which is being used to generate the PWM High and Low Period.

    2. Yes. That is to be done.

    Regards

    Amit

  • Amit Ashara said:
    The other way to do is to use a 3rd timer in Input Edge mode to count the number of PWM Pulses. Of course it has to be made sure that the PWM Frequency and Width of ON and OFF time can be captured by the Timer running of the System Clock.,

    I am trying to implement this configuration, we need to capture the actual number of PWM pulses from a GPIO interrupt from another.

    However I cannot capture the number of pulses without setting an interruption for it.

    Our code is:

    void Init_Timer5A_cnt()
        {
       
    
        SysCtlPeripheralEnable (SYSCTL_PERIPH_TIMER5);
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOM);
    
        GPIOPinTypeTimer (GPIO_PORTM_BASE, GPIO_PIN_6);
        GPIOPinConfigure (GPIO_PM6_T5CCP0); 
    
    
         TimerConfigure (TIMER5_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_COUNT_UP);
    
        // Freeze the timer counting if we are debugging (the counting is enabled automatically with the cpu).
        TimerControlEvent (TIMER5_BASE, TIMER_A, TIMER_EVENT_POS_EDGE);
    
        TimerLoadSet (TIMER5_BASE, TIMER_A, 0);
    
    
        }

    And in the GPIO interupt we call:

    ..........
    
    
    	CNT_pwm=TimerValueGet(TIMER5_BASE, TIMER_A);
    
    	TimerDisable(TIMER5_BASE, TIMER_A);
    
    	TimerLoadSet(TIMER5_BASE, TIMER_A,0);
    
    	TimerEnable (TIMER5_BASE, TIMER_A);
    
    ..........

    Do we need anything else?

    Thank you.

  • PAk said:
    ...cannot capture the number of pulses without setting an interrupt for that... 

    Is that really true?  Are you saying that the MCU timers - when in edge count mode - must be bound to an interrupt? 

    I've not used the timers in edge count mode - from vendor here - in quite awhile - but can report that no such "hostage holding by interrupt" is required by other ARM M4 devices we've used.  Burdening the timer with an interrupt service seems w/out merit in this specific case - and clearly "slows/retards" the max frequency count capability.

    I note that you, "TimerLoadSet()"with a "0" - again I've not used in some time - but does not that clear the timer - upon each/every interrupt?   Sorry - your logic escapes my (few) brain cells on this one...

    I'd add that while you know the specific MCU you're using - there is a new one here - with substantial additions - which runs with critical differences.   Minus your presentation of MUT (Micro under test) time/energy (in your behalf) may be misdirected...

  • Hello PAk,

    In the edge count mode, the timer will give an interrupt when a number of edges have been counted. So if you wish to capture the number of pulses in PWM mode between two GPIO interrupts then it may not be possible.

    Regards

    Amit

  • Greetings Amit,

    To clarify - if we provide 10 good, clean, square wave pulses (well w/in timer's frequency input range) - and then block any further timer input - into a Timer pin configured as, "Timer in Edge Count Mode" - might that Timer's count register reveal those 10 edge count events - without use of interrupts?  And sustain that value - until we order some change?

    Thank you and regards.  (our posts - this subject - likely just crossed.  My earlier one details this point...)

  • cb1_mobile said:

    Greetings Amit,

    To clarify - if we provide 10 good, clean, square wave pulses (well w/in timer's frequency input range) - and then block any further timer input - into a Timer pin configured as, "Timer in Edge Count Mode" - might that Timer's count register reveal those 10 edge count events - without use of interrupts?  And sustain that value - until we order some change?

    Thank you and regards.  (our posts - this subject - likely just crossed.  My earlier one details this point...)

    Yes you can cb1.... please, read below

    BTW, we are using 129x MCU, usually we say that on our first post of the thread, missed this one (sorry about it!!).

    Amit Ashara said:

    In the edge count mode, the timer will give an interrupt when a number of edges have been counted. So if you wish to capture the number of pulses in PWM mode between two GPIO interrupts then it may not be possible.

    Regards

    Amit

    Yes you can.

    Our error before was that we were using 

    TimerLoadSet (TIMER5_BASE, TIMER_A, 0);

    so the Timer stopped inmediately. If you set TimerLoadSet (TIMER5_BASE, TIMER_A, 0xFFFF) then you start counting.

    And here is where the magic comes:

    TimerDisable(TIMER5_BASE, TIMER_A);
    
    Count_value=TimerValueGet(TIMER5_BASE, TIMER_A);
    
    //RESETTING Timer Value to 0
    HWREG(TIMER5_BASE + TIMER_O_TAV)=0;
    
    
    TimerLoadSet(TIMER5_BASE, TIMER_A,0xFFFF);
    
    TimerEnable (TIMER5_BASE, TIMER_A);
    

    The instruction HWREG(TIMER5_BASE + TIMER_O_TAV)=0 makes everything work without interruptions needed, so you get a nice performance boost.

    NOTE:  


    One funny thing we have discovered if that if we set the PWM output up to a specific frequency (i.e. we want to count the 512 positive edges of the 512 PWM generated pulses at 300kHz) all the pulses edges  are detected, however, once  we start to increase the frequency we get more edges (i.e. 513 edges count at 500kHz and  514 edges at 800kHz). 

    Actually it depends on the IntPrioritySet for the GPIO interrupt function.

    Which is the maximum recommended pulse frequency input for counting its edges without errors?

    Regards

     

     

  • cb1_mobile said:
    I note that you, "TimerLoadSet()"with a "0" - again I've not used in some time - but does not that clear the timer

    Pak - mon ami - appears that "Verify Answer" did not (yet) attach to your faithful, remote (always helpful {well sometimes") diagnostician...

    Marrying the normal/customary Timer count capability to an interrupt service routine did seem w/out merit - glad that you made the time to verify & confirm. 

    Cordialement (& Go Rafa!)

  • Hello PAk,

    There is a note in the data sheet for the Edge Count Mode

    For rising-edge detection, the input signal must be High for at least two clock periods
    following the rising edge. Similarly, for falling-edge detection, the input signal must be Low
    for at least two clock periods following the falling edge. Based on this criteria, the maximum
    input frequency for edge detection is 1/4 of the frequency.

    Regards

    Amit

  • Amit Ashara said:
    Based on this criteria, the maximum
    input frequency for edge detection is 1/4 of the frequency.

    What is the frequency? Clock frequency or Timer frequency?

  • Hello PAk,

    It is the timer frequency. The timer clock and the system clock are the same.

    Regards

    Amit

  • Amit Ashara said:

    Hello PAk,

    It is the timer frequency. The timer clock and the system clock are the same.

    Regards

    Amit

    Hello Amit.

    If that is true, then the max input clk is 30MHz, so we shouldn't have any problem reading a 800kHz input signal edges.

    The rare thing is that if PWM frequency is higher, then we are getting more edges than pulses are.

     

    Any advice?

    Regards.

     

  • Hello PAk,

    Can you check if there are no overshoots or undershoots on the PWM signal? That may cause the values to be change.

    Regards

    Amit

  • Amit Ashara said:

    Hello PAk,

    Can you check if there are no overshoots or undershoots on the PWM signal? That may cause the values to be change.

    Regards

    Amit

    Hello Amit, actually the counter is working properly.

    Those 514 edges come from the PWM timer (which is linked to the ADC Timer).

    Everytime we enter the ADC interrupt and  is attended via uDMA when 512 samples are captured, we stop the Timers, however in that little time when we check the uDMAChannelModeGet,the Timer runs for 2 clock cycles (at 800kHz).

    void ADCIntHandler(void)
        {
    
     ulMode = uDMAChannelModeGet(UDMA_CHANNEL_ADC2 | UDMA_PRI_SELECT);
    
        if (ulMode == UDMA_MODE_STOP){
    TimerDisable(TIMER0_BASE, TIMER_A | TIMER_B);//ADC and PWM Timer
    
    TimerDisable(TIMER5_BASE, TIMER_A);
    	Total_samples = TimerValueGet(TIMER5_BASE, TIMER_A);
    	HWREG(TIMER5_BASE + TIMER_O_TAV) = 0;
    
    .............
    
    ..........
    
    	TimerLoadSet(TIMER5_BASE, TIMER_A, 0xFFFF);
    	TimerEnable(TIMER5_BASE, TIMER_A);
    
    
    	ROM_uDMAChannelEnable (UDMA_CHANNEL_ADC2);
    	TimerEnable(TIMER0_BASE, TIMER_A | TIMER_B);
    
    }

    Is there a way to solve this issue?

    I know the TM4C129X micro is near its limits.

  • Hello PAk,

    When stopping the timers it takes finite number of clocks because it has to be synchronized to the core. There is not much that can be done

    Regards

    Amit

  • cb1_mobile said:

    I note that you, "TimerLoadSet()"with a "0" - again I've not used in some time - but does not that clear the timer

    Pak - mon ami - appears that "Verify Answer" did not (yet) attach to your faithful, remote (always helpful {well sometimes") diagnostician...

    Marrying the normal/customary Timer count capability to an interrupt service routine did seem w/out merit - glad that you made the time to verify & confirm. 

    Cordialement (& Go Rafa!)

    [/quote]

    Of course, 99% of the time you are of great help!!

    Go Rafa and Go the rest of the Armada (David Ferrer, Verdasco, Garcia Lopez and Garbiñe Muguruza).

    Amit Ashara said:

    When stopping the timers it takes finite number of clocks because it has to be synchronized to the core. There is not much that can be done

    But the core timer is supposed to be much higher than the ADC timer (120MHz vs 800kHz), shouldn't be enough to execute the instructions?

  • Hello cb1_mobile,

    The point was on the Timer-B running the edge count mode.

    --EDIT START

    The 120MHz is with Flash Prefetch. So depends on how the code is linked, we can have delays as well during code execution for branch statements. This of course assumes that the code is being changed every time to make subtle changes.

    --EDIT ENDS

    Regards

    Amit