[Hackrf-dev] Precise synthesizer tuning

Phil Karn karn at ka9q.net
Mon Jan 14 00:57:07 EST 2019


I revisited this problem yesterday and have it *almost* completely
resolved. By running the synthesizer programming formulas in parallel, I
am able to determine the actual tuned frequency as a function of a
requested frequency and adjust my software local oscillator to compensate.

The synthesizers in *both* the MAX2837 and the RFFC5072 have some weird
behaviors that made it difficult to figure out what was really going on.
(My signal generator stops at 2100 MHz so I was unable to test with the
MAX2837 alone, which requires a signal between 2150-2750 MHz.)

Digging into the firmware source and the synthesizer data sheets, I
found that the tuning step for the MAX2837 is:

30 MHz / 2^20 = 28.610229492... Hz

However, the synthesizer occasionally settles one step away from the
specified one. Reprogramming the same frequency seems to usually fix it.
Could this be a timing problem in how the firmware writes the registers?

The RFFC5072 step size depends on the frequency range, but is some small
multiple (or fraction) of

50 MHz / 2^24 = 2.980232239... Hz

But the RFFC5072 synthesizer always seems to settle one *half* step
above the desired frequency. This seems very strange, but maybe there's
something I don't understand about fractional-N synthesizers. (So far my
tests have been limited to frequencies where the step is 100 MHz/2^24 Hz).

In the source file firmware/common/max2837.c is the following mysterious
comment:

/* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */

This implies the internal synthesizer reference is 30 MHz despite 40 MHz
being applied to the part by the Si5351C. This appears correct, but I
can't find any mention of this 4/3 (or 3/4) factor anywhere in the
MAX2837 documentation or register settings. Where does it come from?

Also in the firmware, when the RFFC5071 is used, an approximate
frequency that's an integer multiple of 1 MHz is passed to
rffc5071_config_synth_int in rffc5071.c. That function returns the
actual frequency, which is then used to adjust the tuning frequency
passed to the max2837. However, rffc5071_config_synth_int returns an
integer, so this also introduces a slight error. (It should probably
return a double).

I'd like to put in a plea to the designers of SDR front end APIs: please
have your "tune" function return its best estimate of the radio's actual
tuned frequency, taking into account synthesizer step sizes and TCXO
offset estimates.

It's perfectly OK for a radio to not give me the exact frequency I ask
for *PROVIDED* I know the actual frequency, because I can then easily
compensate for it in my software local oscillator.

Thanks!

Phil Karn

PS. One of the reasons I'm interested in precise frequency knowledge is
that I'm comparing local ATSC pilot carriers to my GPSDO. ATSC pilots
have attracted some interest as poor-man's frequency references, but my
observation is that only *some* TV stations actually use high stability
oscillators to control them. The others can be a few hertz off (not
counting those still operating with transition-era frequency offsets.)



More information about the HackRF-dev mailing list