How to configure a PLL?

Sharing thoughts and experience (not a question).
How to configure a PLL - the Multiplier and Divider values?

The "question" come from: dealing with audio, setting a "perfect" clock for audio (e.g. 48 KHz).
I see multipliers and divider values on PLL config - but how to choose the right combination?
There are different pairs of values to get 48 KHz - but which one is the "best"?

Overview about PLL:

  • PLL gets a clock from system input (can be a multiplied XTAL clock, let's say any system clock comes to a PLL
  • a PLL, e.g. needed to clock a peripheral/device, e.g. SAI, SPDIF, has a pair of a multiplier and a divider (for one output)
  • this combinations sets the PLL out clock speed, e.g. 48 KHz - exactly 48 KHz or a bit off
  • I want to make it perfect for 48 KHz - but I have different combinations of multiplier and divider value pairs possible
  • which one is the best?

So, my conclusion:
I want to trim the PLL later a little bit: instead of exactly 48 KHz - I want to run with 47.9 or 48.1 KHz. What does give me the most "fine-tunable" value pair?

It turns out as:

  • if multiplier value is the largest value possible (in valid range!)
  • and divider is the largest possible to provide the required output clock
    it gives me the most "fine-tunable" clock: the multiplier can be changed now to a plus/minus value with the smallest change in speed: the "clock resolution" is better, more fine granular.
    I can now trim the PLL by adjusting the multiplier by just few KHz difference.

If I would chose the opposite: a small multiplier but also a small divider:

  • the clock frequency step (when changing multiplier) is much larger (resolution smaller)
    It covers now a larger range to change the frequency but with less resolution (steps).

Larger range with less resolution vs. smaller range but finer resolution.

So, I use this approach:

  • find a setting with largest multiplier and largest divider to get my nominal frequency
  • it gives me more fine tuning steps on multiplier to adjust the frequency

On the Portenta H7 there is the "beauty" to have also fractional part of multiplier. It let's you even more fine tune the frequency, e.g. for my nominal audio clock I need to be in sync with the sender. The "free running audio clocks" is a separate issue, just my goal: tweak the clock frequency to stay in sync with incoming audio (e.g. SPDIF) for the longest period "possible".

When using fractional divider - you will realize that the "range" how they can vary the clock speed depends on the main integer multiplier (and associated divider):
the larger the multiplier (and divider) - the smaller the fine tuning range with fractional, but now much more fine granular.

Assuming you know, that PLL parameters such as multiplier and divider depend on the input frequency, also the voltage range selector for the PLL - you can choose PPL config with different pairs of multiplier and divider (depending on your "resolution" to trim a clock frequency).
Just use the right pair (combination) for your goal.

BTW:
The Portenta H7 with the fractional multiplier value is pretty cool: it allows to adjust the clock via this fractional multiplier "on the fly": no need to stop PLL (no need to stall the audio), just to set a new value, e.g. for "adaptive clock recovery".

Also good approach: make the audio buffers as largest as possible (based on available memory). The larger the buffers, assuming audio runs in DMA mode - the less sensitive for "clock jitter":
If the audio clock is not very stable, it changes up and down in frequency ("jitter") - a larger buffer makes it less sensitive for this issue. But it creates also latency: now the audio is a bit behind, not "lip sync" anymore.
If you have a clock difference - now with larger buffers the audible "clicks" come more spread apart (not so often).
Smaller buffers, worst case: an audio frame for 48 KHz, with 48 stereo samples only, every 1 ms - is more sensitive for clock drifts, jitte, clock speed difference. This makes the fine tuning of PLL (or even using "adaptive clock recovery") more challenging.

Larger buffers are better sound but also much more delay (not "lip sync" anymore).\

Have fun with PLLs and Audio Applications.

Fast, tunable, and exact synchronization reminds me of using a Bresenham algorithm for PLLs:

"hmmmm" what is it?

The PLLs are fixed in MCU (how they work, in HW, not related to SW).
HW-wise: it is a loopback controlled oscillator, in HW.
They take an input clock, multiply (N times the input frequency) and divide again to get any ratio in relation to input clock frequency. But lock the phase.
The feedback (loopback tries to "lock the phase" with input clock, therefore PLL = Phase Locked Loop.

The "accuracy", esp. jitter or how long it takes to lock - is a HW design feature, not related to any SW.
A PLL takes a while until the lock is done (now clock is "correct"). And they are ratios from the original clocks (multiplied, divided, but always in relation to input clock).

If the input clock is not stable, e.g. it has huge jitter: the can have trouble to lock. At least: they forward the input clock jitter or even add some more jitter (due to the control loopback).

I do not understand the relation of this article to the topic here. It talks about two clocks with "incorrect" frequency. And when doing an average - it comes to the "right" frequency.
But this is not a PLL works (it has just one input frequency).
And what if when one source jitters a lot (drifts a low), so that the average also jitters?

A PLL is a device which generates a new clock (faster or slower) where the phases (edges) of input and output clock are tried to remain in sync. So: the PLL cannot be better as the input clock (in terms of clock drift, jitter). And the PLL takes time to adjust (not correct at the beginning: I have seen: my audio clock is wrong for several seconds, slightly wrong).
A PLL can have a range where it "accepts" a bit of input jitter (now running freely as before, but waiting for a new lock). When it locks again - it can "jump" on phase. So, it "amplifies" jitter.
Only an atomic clock as reference makes it really stable. Using two jittering clocks does not improve. Over a long period of time you can disintegrate the jitter, maybe it is the topic of this "paper. (But it was not the topic here).

BTW (addressed to DaveX): if you need an accurate 1sec clock, "trust" the LOC (32KHz oscillator), used to clock your RTC (to keep time and date accurate for days even you power down the MCU).

If this is not accurate enough:
Take the clock from the GPS system: a "GPS Disciplined Clock":
GPS discipline clock
There are GPS receivers which provide a 1pps clock output, e.g. as 1 Hz, but often also 10MHz. And this clock is derived from an "atomic clock", very accurate and stable.

But if you want to generate another clock from it, e.g. the MCU core clock, as 480 MHz - you need a PLL again (and back to the topic).

With a 480MHz Portenta, you could write a software PLL that handles a 48kHz output, and keeps track of phase. The bresenham trick is that if the choice of the input clock's multipliers and divisors don't give the required ratio to get the output clock, you can keep track of the phase error in a bresenham accumulator to stay in sync.

Maybe the Portenta H7's silicon fractional multiplier PLL hardware implements something similar to the software on those pages.

WHAT??
How to lock a phase in SW?
If my clock input is: assume 10 MHz (from a GPS Disciplined Clock): how to make sure I toggle a GPIO clock output really in sync with the 10 MHz input? NO WAY!
10 MHz is 100 ns (how the edges come and must be seen and toggled). 100 ns are just very few instructions.

I need several instructions just to find the input edge and toggle a GPIO. I am not convinced a PLL works really in SW only. 480 MHz vs. 10 MHz input clock = 48 single cycle instructions - potentially not enough to be fast enough.

And what if I run other SW, an RTOS? My clock starts to fade, to jitter?

And tracking a phase? Nyqist theorem! I have to run 2x faster as the input clock.
Even I do so, I can get the right frequency - but not yet where the clock edge was. So, for Phase Locking (edge detection) - I might need 10 times the input clock as performance speed on SW.

I CANNOT imagine PLL in SW is working.

Maybe, with a 100 KHz, 1 Hz clock input. But it remains the issue: I will add jitter to the clock due to the "timing inaccuracy" via the SW (and the speed of the SW jitters also by the MCU clock). The average clock speed might be correct - but the jitter!!!!
I have to be in sync with the reference clock: audio uses a world clock and all what matters is the stability, the low jitter, not really the frequency.

It will not solve any issue (which I do not have, I was giving hints how to use the MCU internal PLLs, not looking for a SW-substitution of HW-PLLs (which work much better and great)).
All this is off-topic.

Yes, hardware is faster than software. But the hardware PLL isn't magic, it is running an algorithm implemented in silicon, and your fractional divisor highlight reminded me of that Bresenham PLL implementation in software.

As to on-topic, what is the topic? How is someone supposed to use the Portenta's HW-PLLs without code or good reference materials? What explicit parameters do you actually recommend for a 48kHz output?

Yes, I know PLLs in silicon (I do chip design, silicon).
Topic was just a "hint", not a question:
"how to choose multiplier and divider values for PLL config - for best fine tuning the frequency?"

Sure, when talking about multiplier and divider for PLL, you have to know from reference manual (or API documentation) what does it mean.

Here an example (but for a DISCO-STM32F769I board):

    /* SAI clock config
    PLLI2S_VCO: VCO_344M
    SAI_CLK(first level) = PLLI2S_VCO/PLLSAIQ = 344/7 = 49.142 Mhz
    SAI_CLK_x = SAI_CLK(first level)/PLLI2SDivQ = 49.142/1 = 49.142 Mhz */
    RCC_ExCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI2;
    RCC_ExCLKInitStruct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S;
    RCC_ExCLKInitStruct.PLLI2S.PLLI2SP = 8;
    //TJ: this is correct and exact 48 KHz - trim it exactly for 48 KHz!
    //fine tune on N value: 432 is actually max.! - but it seems to work best
    /*
     * trim it so that we see a stable red LED off or on, this happens just after a while
     */
    RCC_ExCLKInitStruct.PLLI2S.PLLI2SN = 432;	//335;	//336   //384;	//was 344   N is multiplier
    RCC_ExCLKInitStruct.PLLI2S.PLLI2SQ = 9;		//7;			//8;	//was 7		Q is divider
    RCC_ExCLKInitStruct.PLLI2SDivQ = 1;

    HAL_RCCEx_PeriphCLKConfig(&RCC_ExCLKInitStruct);
1 Like