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

Thread Starter

Kumar san

Joined Jan 5, 2023
16
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?
 

Attachments

BobTPH

Joined Jun 5, 2013
11,463
You can achieve higher frequency accuracy by dithering. This involves changing the period on each pulse up or down by one so that, over time, it averages out. But, of course, this results is jitter (unequal periods.) I believe this is how DDS chips do it.
 
Last edited:

MrChips

Joined Oct 2, 2009
34,628
You are approaching it incorrectly.

If you divide 84 MHz by 84, you have 1 MHz or 1 μs resolution (or 1 part in 1000000) and you only need 100 μs.
If you divide 84 MHz by 21, you have 4 MHz or 250 ns resolution (or 1 part in 4000000).
Note that accuracy and resolution are two different things. For accuracy, you need to trim the crystal against a known standard.

The other thing to note is that the STM32 is usually clocked with an 8 MHz crystal and a PLL is used to generate 168 MHz. You would have to examine the jitter of the PLL.
 

ronsimpson

Joined Oct 7, 2019
4,646
I think in frequency. When I worked on a cellphone project (digital radio) those engineers think in time not frequency. It hurt my head to think of RF in time. This is like looking at the project upside down. Some time thinking in time simplifies the problem. Listen to MrChips.
 

nsaspook

Joined Aug 27, 2009
16,250
I think in frequency. When I worked on a cellphone project (digital radio) those engineers think in time not frequency. It hurt my head to think of RF in time. This is like looking at the project upside down. Some time thinking in time simplifies the problem. Listen to MrChips.
Yes, it's the same with the very slow, for a star tracking telescope I needed micro Hz resolution for the motor drives. The 32-bit timer for pwm had 9ns timing resolution. The sine wave generator of the pmsm drive was designed with that as the limiting factor for frequency generation.
https://github.com/nsaspook/vcan/blob/fixes/firmware/src/freqgen.c

https://forum.allaboutcircuits.com/threads/pic32mk-mc-qei-example.150351/post-1530400

1746720771097.jpeg
1746721216776.jpeg

Third harmonic injection.
https://forum.allaboutcircuits.com/threads/pic32mk-mc-qei-example.150351/post-1550621
1746720980595.jpeg

Two pwm phase shifted signal waveforms (top/bottom) and the center MATH line waveform (clean sine-wave) that drives a set of motor windings on the 3-ph motor.
 

Papabravo

Joined Feb 24, 2006
22,058
Only way I know is to match the integers with the frequencies by changing the frequency of the timer clock. Were you expecting some kind of magic here?
 

BobTPH

Joined Jun 5, 2013
11,463
c
You are approaching it incorrectly.

If you divide 84 MHz by 84, you have 1 MHz or 1 μs resolution (or 1 part in 1000000) and you only need 100 μs.
Please explain how that helps.

To get 10000Hz you would use 50 of your 1uSec ticks for each half period.

If you use 49 ticks, you get 9803.9Hz.

So how do you get 9999.9Hz?

I believe you need 1GHz to get the needed frequency resolution, 2GHz if the waveform must be symmetric.
 
Last edited:

sparky 1

Joined Nov 3, 2018
1,218
I had an old Global Specialties Max100A frequency counter that was designed mostly for high frequency.
The unit had a fair 10 MHz clock that was divided down, that was the heart of the circuit, it was for gate speed.

A magazine article caught my interest, it suggested that for low frequency measurement I could divide the clock further,
So why not try the divide by 100 so I went to radio shack and bought a few LM7490 decade counters and it worked ok but the
decimal place was off and it was really not high accuracy like they said. I recall 60Hz no longer measured 58Hz, the other decimal places
drifted with the temperature of the circuit board.

In compensating a microcontroller type frequency counter. I might consider sensing the board temperature (smd thermistor) near the crystal
If the same temperature drift issues are occurring. By allowing the unit to warm up 25 minutes definitely improved the accuracy and repeatability.
Trying to resolve 0.001 might need higher than 10bit.
 
Last edited:

ronsimpson

Joined Oct 7, 2019
4,646
So how do you get 9999.9Hz?
Most counters require 10 seconds to read that.
I have an old counter that, at low frequencies, switches to counting time and converting that to frequency. I think it can measure 500 times/ second and reads out to 0.001hz. I got the counter just for measuring slow signals at a fast rate.
 

Futurist

Joined Apr 8, 2025
721
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?
So you're seeking to devise a setup that can gen 0.1, 0.2, 0.3 --- 9,999.9 Hz, that's 100,000 possible frequencies. The resolution isn't the same as accuracy though, if resolution is all that's being asked then I guess accuracy isn't too important.

The docs say in fact that TIM2 can actually do exactly what you want.
 

Thread Starter

Kumar san

Joined Jan 5, 2023
16
Thanks for your reply.

I need to generate a frequency from 0 to 10,000.0 Hz with a resolution and step size of 0.1 Hz. I'm using a microcontroller, but PWM generation isn't accurate enough due to timer limitations (integer values only).

Is there any hardware solution available to achieve this level of precision, or are there any alternative ideas or approaches you would recommend?
 

Thread Starter

Kumar san

Joined Jan 5, 2023
16
What is the time base of the microcontroller that you are using based on? How accurate and stable is it?
I’m using an STM32F407VET6 microcontroller running at 168 MHz. The clock source is either an 8 MHz external crystal , which is multiplied using the PLL to reach 168 MHz.
 

WBahn

Joined Mar 31, 2012
32,703
I’m using an STM32F407VET6 microcontroller running at 168 MHz. The clock source is either an 8 MHz external crystal , which is multiplied using the PLL to reach 168 MHz.
Sigh... Let me try this again.

How accurate and stable is the time base you are using?

And you say "either" an 8 MHz crystal, but then don't say what the other option is. Either an 8 MHz crystal or... what?

Assuming your time base is accurate and stable enough (which is far from established), there are some games you can play.

For example, you can run two accumulators, one for the integer portion and one for the fractional portion. Each time the fractional portion overflows unity, you advance the integer accumulator by one. You can also do a linear interpolation between the integer waveform value and the next one using the fractional accumulator. In principle, you could do a higher-order fit to get even better results, but that probably isn't worth it.

When you say you are trying to generate output frequencies between 0 and 10 kHz, output frequencies of what? Sinusoid? Triangle? Squarewave? Arbitrary waveform?
 

Thread Starter

Kumar san

Joined Jan 5, 2023
16
Sigh... Let me try this again.

How accurate and stable is the time base you are using?

And you say "either" an 8 MHz crystal, but then don't say what the other option is. Either an 8 MHz crystal or... what?

Assuming your time base is accurate and stable enough (which is far from established), there are some games you can play.

For example, you can run two accumulators, one for the integer portion and one for the fractional portion. Each time the fractional portion overflows unity, you advance the integer accumulator by one. You can also do a linear interpolation between the integer waveform value and the next one using the fractional accumulator. In principle, you could do a higher-order fit to get even better results, but that probably isn't worth it.

When you say you are trying to generate output frequencies between 0 and 10 kHz, output frequencies of what? Sinusoid? Triangle? Squarewave? Arbitrary waveform?
square wave output
 

atferrari

Joined Jan 6, 2004
5,001
Not what you asked, I know.

My Siglent signal generator IIRC, is built around a full fledged chip as the AD9833 or one of the DDS family. Control seems simple with a simpler PIC.
 

BobTPH

Joined Jun 5, 2013
11,463
Period of a 10Khz signal is: 0.0001 sec

Period of a 9999.9Hz signal is:
0.000100001000001

Difference is about 1nsec.

You certainly cannot get that using a fixed 84MHz clock.

If the PLL has 1nsec period resolution, you could change the clock frequency for each output, but I doubt that it does.

In post #2 I talked about dithering to get an average frequency that accurate but accompanied by clock jitter. TS never stated whether that was acceptable.

Here is how the dithering would work:

Say you a 100Mhz clock. To get 10KHz you would set the period to 10000 cycles. To get 9999.9Hz you would use 9 periods at 10000 cycles, then one at 10001 cycles. The individual periods are not correct, but they average to nearly correct over each 10 cycles.

Edited to add: The fractional counter mentioned by @WBahn in post 16 is a good way to implement dithering.
 
Last edited:
Top