2
\$\begingroup\$

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?
\$\endgroup\$
5
  • 3
    \$\begingroup\$ Do you measure the jitter before or after the analog reconstruction low pass filter you need to have? How large is the phase noise (what appears as jitter to you)'s variance (or standard deviation)? Does making the DDS table larger make it sufficiently small for your application? \$\endgroup\$ Commented May 8 at 8:55
  • \$\begingroup\$ I'm generating a square wave using DDS on an STM32F4, and measuring jitter directly on PA1 with a CRO. This is before any analog filter, since it's a digital square wave output. I haven't measured phase noise, but I do see some jitter at higher frequencies (above 10 kHz). I haven’t calculated the exact variation yet. I'm not using a sine lookup table — I use the MSB of a 32-bit phase accumulator for square wave generation: phase_accumulator += phase_increment; uint8_t bit = (phase_accumulator >> 31) & 1; GPIOA->BSRR = (bit) ? GPIO_PIN_1 : (GPIO_PIN_1 << 16); \$\endgroup\$ Commented May 8 at 9:16
  • \$\begingroup\$ any hardware filters available for remove Jitter? \$\endgroup\$ Commented May 8 at 9:18
  • \$\begingroup\$ @kumar I don't know enough about your application, but thanks for what you've provided. It looks like you want 10 ppm. Or better. And that's a lot to expect., Common and cheap crystals are often spec'd at 100 ppm over temp. So you are pushing things. Also, I don't know what you can tolerate in terms of short-term jitter vs long-term. The MSP430 DCO for example, can switch between two close, alternate divisors and achieve very good results (if calibrated) but there will still be short-term jitter that you cannot avoid using their system. Best wishes, regardless. \$\endgroup\$ Commented May 8 at 9:26
  • \$\begingroup\$ @kumar yes as said, a DDS is not generally different than other DAC applications, you need an analog reconstruction filter, which is a low-pass filter. \$\endgroup\$ Commented May 8 at 10:04

3 Answers 3

2
\$\begingroup\$

In the general case, edges of a squarewave at a general frequency will not align with edges of your MCU clock, so purely digital methods where you can only select which edges have an output transition must produce edge jitter.

If you can tolerate edge jitter, but want the mean frequency to be correct, then there are various ways to update either a counter doing a pure digital division, or a phase accumulator DDS, with fractional-N data, to get the exact frequency you want.

If you want to avoid edge jitter, then you must have an analogue filter at some point in your system. It may be doing timing interpolation in a PLL, or amplitude interpolation as an anti-alias filter following a DAC, but it will be needed somewhere.

For a jitter-free squarewave - the DDS analogue method

  • Have enough bits of resolution in your accumulator so that errors due to integer truncation are negligible
  • OR arrange the modulus of your accumulator so that integer programming will give you exactly the resolution you want
  • AND generate an analogue output of reasonable amplitude resolution of either the phase accumulator sawtooth, or that converted to a cosine, with a DAC into an analogue anti-alias filter, which you then threshhold with a comparator to give you a squarewave output. If you are outputting the sawtooth, threshold at the top, to maximise the delay through the AA filter. If outputting a cosine, threshold at the middle.

For a jitter-free squarewave - the DDS digital method

More or less as for the analogue method, except that instead of outputting the sawtooth or cosine with a DAC, you output a band-limited squarewave into your anti-alias filter. See US patent 7702707 for details of two ways to do that, of which the second is more practical in an MCU as it uses less or no calculation on the fly. And yes, it is the same Neil.

\$\endgroup\$
1
\$\begingroup\$

To generate low-jitter square waves hardware DDS implementations (for example, this one) typically use an analog-filtered sine wave output followed by an analog comparator. That can't really be done in software, but it's not a lot of hardware.

Some of the STM32 models include some very sophisticated clock generation hardware on-board- fractional-N divider feedback PLLs. Perhaps you could fiddle the input frequency to the timers to get what you need directly from an output pin. (screenshot from STM32CubeIDE). Might be a bit complex, but interesting.

enter image description here

\$\endgroup\$
1
  • \$\begingroup\$ I thought of the same to use the internal PLL to generate suitable frequency for timer to divide by integer, but the problem is that the timers still runs in the sysclk-derived busclocks when detecting external input counting edges, so anyway output will update based on the 84 MHz clock. The only solution would be to adjust the main system clock if possible. \$\endgroup\$ Commented May 8 at 20:32
1
\$\begingroup\$

Take a look at the 63 bit PTP timer register inside the STM32F407 Ethernet MAC block - you can persuade it to generate pulses which are a little jittery (e.g. about 20nS) but have an average period settable to a fraction of one nanosecond.
It implements a fractional-n division of e.g. a 52MHz update clock.

It is possible to trick it into generating interrupts/pulses at fairly high rates, certainly up to 10kHz, if you keep updating the count compare register with the next count value every time it pulses.

I was able to use it to generate a precision 1PPS in a simple NTP server, where I software phase locked it to a 1PPS from a uBlox GPS receiver, so that when GPS went down, it would count on accurately for a reasonable length of time.

Basically you enable the Precision Time Protocol in the MAC block, you can carry on using the MAC for Ethernet at the same time , it simply sends some extra IEEE-1588 bytes every time it sends a frame over the wire.

I believe that the MAC block in the STM32F407 is an off-the shelf Synopys IP core for the ARM ecosystem so other ARM based microcontrollers with Ethernet and IEEE-1588 may be able to do the trick.

ALTERNATIVE: Directly use the fractional-N concept in programming the period of the divider. In simple terms, if you want to program an integer divider to divide by say 12.234, you tell it to divide by 12 for 1000-234 = 766 times, then tell it to divide by 13 for 234 times. This will average out to be the correct ratio but of course there will be a strong frequency modulation.

A better way is to calculate on each cycle whether the next pulse of the output signal should be closer to the N'th clock or (N+1)th clock from the previous clock pulse, and set the division ratio appropriately, basically you accumulate the time error in an accumulator and when the error exceeds one cycle of the timer clock, you program a N+1 in the reload register and subtract one clock period from the time error accumulator.

This also produces FM tones and squeaks. Noise shaping is possible where you start adding random values to the N/N+1 decision system that average out to zero, but which spread the "tones" across the spectrum to become lower level broad band noise.

The next level up is to use a DAC, sampling at over 2x the 10kHz max frequency, and directly generate the sine wave values you would get for each sample, same as a DDS chip.

At the extreme this turns into a 1 bit DAC clocked in the MHz region , where the spectrum of the signal round DC includes your wanted signal, but up in the above audio region there is a lot of noise produced which you filter out with a simple analog filter. Some microcontrollers have these building blocks in the chip, so you can get a "nice" 48kHz sampled version of your up to 10Khz sinewave.

\$\endgroup\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.