cancel
Showing results for 
Search instead for 
Did you mean: 

How to Achieve 0.1 Hz Resolution from 0 to 10 kHz Using STM32 Timer?

Sansel
Associate

 

Hi everyone,

I'm trying to generate output frequencies from 0 Hz to 10,000 Hz using STM32F407VET6 with Timer2 in Output Compare Toggle Mode. The timer clock is 84 MHz.

I need to achieve:

  • 0.1 Hz resolution up to 10 kHz

  • Ideally, also support 0.001 Hz resolution at lower frequencies

The problem is that at higher frequencies, the formula:

f_out = f_timer / (2 * ARR)
often results in a non-integer ARR. For example, to generate 9999.9 Hz, I get:

 

ARR = 84,000,000 / (2 * 9999.9) ≈ 4200.042

But since ARR must be an integer, I have to use 4200, which gives 10,000 Hz — a 0.1 Hz error.


i am using DDS (Direct Digital Synthesis) using a phase accumulator in software
With DDS, I can theoretically achieve very fine resolution, but when I measure the output using a CRO (oscilloscope), I notice jitter in the waveform.

Question:
How can I generate accurate frequencies with 0.1 Hz resolution across the full range (up to 10 kHz)?
Are there any techniques (e.g., fractional timers, clock tricks, advanced modes, combining timers) to overcome this limitation?

2 REPLIES 2
TDK
Super User

No, you can't have fractional ticks here. On STM32H7, you could adjust the PLL clock fractionally to achieve this.

You could set up DMA to update the ticks so that the average frequency is as desired, but there will be jitter of up to 1 tick.

If you feel a post has answered your question, please click "Accept as Solution".

Like TDK said if you cannot get the exact frequency you want using an integer period at your specific timer clock you can adjust your PLL and/or timer clock and/or clock source. Or live with jitter (switches between 9997.6Hz and 10000.0Hz to create 9999.9Hz on average).

9999.9Hz +- .1 Hz -> 10ppm
9999.9Hz +- .01 Hz -> 1ppm
so you would need very precise clock source to get an accuracy that is in the same ballpark as your resolution.

UPDATE:

I wrote a little python script to try some values for clock sources and PLLs

#HSE = 4-26MHZ
for hse in [10E6,16E6,25E6]:
   
    min_abs_error = 1
    best = {}
    for m in range(2, 63+1):
        m_out = hse / m    
        # M output >= 0.95MHz <= 2.1MHz    
        if m_out >=0.95E6 and m_out <= 2.1E6:
            for n in range(50, 432+1):
                n_out = m_out * n
                if n_out >= 100E6 and n_out <= 432E6:
                    for p in [2,4,6,8]:
                        p_out = n_out/p
                        if p_out >= 24E6 and p_out <= 168E6:
                            for ahb_prescaler in [1,2,4,8]: 
                                if ahb_prescaler == 1:
                                    timer_mult = 1
                                else: 
                                    timer_mult = 2

                                ahb1 = p_out / ahb_prescaler
                                if ahb1 <= 42E6:                   
                                    timer_clock = ahb1 * timer_mult

                                    prescaler_desired = timer_clock / (f_desired*2)

                                    prescaler = round(prescaler_desired)                      
                                    f_out = (timer_clock / prescaler)/2
                                    error = f_out - f_desired
                                    if abs(error) < min_abs_error:                                        
                                        error_ppm  = 1E6 * error / f_desired                                  
                                        best = {"error": error, "error_ppm":error_ppm, "hse":hse,"m":m,"n":n,"p":p,"ahb_prescaler":ahb_prescaler, "prescaler":prescaler}
                                        min_abs_error = abs(error)

    print(best)

 

This is the output:

{'error': -0.006950727800358436, 'error_ppm': -0.695079730833152, 'hse': 10000000.0, 'm': 9, 'n': 374, 'p': 6, 'ahb_prescaler': 2, 'prescaler': 3463} 
{'error': -0.004601416303557926, 'error_ppm': -0.46014623181811076, 'hse': 16000000.0, 'm': 11, 'n': 239, 'p': 6, 'ahb_prescaler': 2, 'prescaler': 2897}
{'error': 0.0024399761969107203, 'error_ppm': 0.24400005969166896, 'hse': 25000000.0, 'm': 21, 'n': 164, 'p': 6, 'ahb_prescaler': 1, 'prescaler': 1627}

So if you use a 25MHz clock source you can get 9999.902Hz. The rounding error is much smaller then the frequency error of the clock source at 0.2ppm so it is neglectable (or even correctable if you can shift the frequency of the clock source).

 

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.