Author Topic: Yet another DIY GPSDO - yes, another one  (Read 300469 times)

0 Members and 5 Guests are viewing this topic.

Offline jmnlabs

  • Regular Contributor
  • *
  • Posts: 64
  • Country: pl
Re: Yet another DIY GPSDO - yes, another one
« Reply #1150 on: August 17, 2026, 09:13:48 pm »
Hi SJ,

Thanks for the careful experiments — the supply-break adapter test in particular is a useful data point. And congratulations on the 2e-10 at 10 s from a breadboard on a window sill; that is a respectable number against the Efratom.

Before we dig further into the firmware, could you post a photo or two of the breadboard? Wire lengths, where the grounds meet, and how the oven is fed will tell us more than a schematic at this stage.

One honest caveat up front: André's 006c and my build are not the same animal electrically. 006c is a simple superloop — it does one thing at a time, draws modest and fairly constant current, and is forgiving of wiring that a more active board would object to. The FreeRTOS version runs several tasks, the USB CDC console, the display and the health/statistics code in parallel, so it produces far more switching activity and current transients on the rails and grounds. On a proper PCB that is a non-issue; on a breadboard, the same marginal joint or long ground jumper that the superloop rides straight through can put the RTOS build into trouble. I develop and test on PCBs (Scrachi's layout, plus my own additions), and I have to be honest that I cannot guarantee the RTOS build will run on any tangle of wires — the breadboard becomes part of the circuit whether we like it or not.

Your own measurements point that way: with the power conductor broken, only ground and data remain, and the problem persists — so this is not two supplies fighting, it is something the connection of the USB ground and data does to the board. Two quick experiments would separate firmware from wiring:

1. Try a battery-powered laptop, or a USB data isolator, so that no earth path exists between your bench supply and the PC. If the freeze disappears, the culprit is the ground loop through the breadboard wiring, not the code.
2. Add a 100 n ceramic across the supply pins of every module and a bulk capacitor near the oven, and keep the ground jumpers short and star-shaped.

And the USB-only no-boot is almost certainly the oven: a cold oven pulls far more than a USB port is asked to give, so the rail sags and the MCU never starts. That one is physics, not firmware — 006c would do exactly the same.

Post the photos and the isolator/battery test result and we will take it from there.

Best regards,
Jaroslaw
 

Offline jmnlabs

  • Regular Contributor
  • *
  • Posts: 64
  • Country: pl
Re: Yet another DIY GPSDO - yes, another one
« Reply #1151 on: August 20, 2026, 07:04:01 pm »
GPSDO FreeRTOS v1.05 — multi-level accumulator working, 24-bit
dithered PWM, and a measurement that says our threshold scaling was wrong

v1.05 of the STM32F411 FreeRTOS GPSDO is up. Two substantial changes and one
result I think is worth more than either of them.

**Algorithm 12 — the multi-level accumulator, after MIS42N's Budget GPSDO.**
Readings accumulate into levels, level n covering 2^n seconds; a correction
fires at the *lowest* level whose error exceeds that level's limit. A large
error acts within two seconds, a small one waits for a longer average, and
there is no loop time constant to choose. The levels come out of the bit
pattern of a seconds counter rather than an array of buffers — eleven levels,
2 s to 2048 s, in 22 bytes.

It shipped in v1.04 with the arithmetic right and five faults in the machinery
around it, each hiding the next. With all five fixed, 23 hours:

```
phase RMS, settled     5-8 ns      (best previous: 10-23 ns)
|phase| < 10 ns        86.7% of samples
picDIV re-arms         1           (121 without the TIM2 frequency trim)
10 000 s frequency     4e-12       (previous: 1.4e-11)
```

**24-bit control voltage from a dithered PWM,** also Alan's idea: run the PWM
at fewer bits than you need and vary the duty from period to period so the
average carries the rest. The gain is the carrier, not the resolution — 13 bits
at 12.2 kHz instead of 16 bits at 2 kHz lets the filter corner move from 0.7 Hz
to 4.2 Hz for the same ripple, a six-fold shorter time constant, and filter
delay goes straight into a control loop as phase lag. Alan dithers in a timer
interrupt because a PIC has no DMA; on this part that would be 12 000
interrupts a second competing with the 1PPS capture, so the pattern — which is
periodic for a constant value — is computed once into a table and replayed by
DMA. 0.012% CPU, none of it in an interrupt, and the average is exact by
construction. The loop now keeps the fraction of each correction rather than
truncating it, which takes one step from 3.2e-11 to 1.25e-13.

**The measurement.** I tried to derive the per-level thresholds from the
measured phase noise rather than setting them by hand. The obvious way is to
assume the phase is white, so that averaging 2^L samples reduces the test
statistic by 2^(L/2), and scale the thresholds accordingly.

That is wrong, and not marginally. Measured on two boards of the same design —
same PCB, same OCXO, different rooms — the exponent is **0.95 and 1.03, not
0.50**. The phase these loops fight is a slow wander with an autocorrelation of
0.96 at 60 s and 0.64 at 300 s; averaging barely reduces it. Spread over a 1 s
window: 26.6 ns. Over 1024 s: still 20.6 ns.

The consequence compounds with level. The white-noise table understates the
real spread about five-fold at level 0 and more than a hundred-fold at level
10, so it falls 32x across the hierarchy where the phase itself falls by 1.3x.
On a quiet board the crossing still lands somewhere sensible and the loop
behaves; on the same board in a noisier room it lands at the bottom of the
hierarchy, where each correction has the least averaging behind it.

If you are deriving thresholds from a noise measurement in your own design,
this is worth checking on your hardware: measure the spread of your test
statistic at more than one averaging time and see whether it actually falls the
way white noise says it should. On this design it does not, and a first
difference at 1 s tells you nothing about it — differencing is exactly what
removes the low-frequency part you care about.

v1.05 measures the exponent per level and fits the table to it. Selectable, and
honestly not always an improvement: on the quieter board the measured table
corrects a third as often and doubles the phase RMS, because it asks "is this
deviation unusual for this board" where the white-noise version asks "is this
deviation above the measurement noise" — and for control the second question is
often the more useful one. Which is right depends on the site, so it is a
setting rather than a replacement.

**Also in this release:** a cold-start hang (a `vTaskDelay()` reached before
the FreeRTOS scheduler exists — a hard fault with no output, and it only bit
when the GPS receiver was still booting, so a reset always appeared to fix it);
the frequency digits now follow the loop's own lock state instead of waiting
for a 1000 s average; and the 320x240 and 480x320 screen layouts finally match.

Credit where it belongs: algorithm 12, the zero-crossing correction, the
dithered PWM and the self-assessment idea are all **MIS42N's**, from his Budget
GPSDO. Measurements against a rubidium reference on algorithms 10 and 11 by Dan
Wiering. PCB by Scrachi. Original GPSDO v0.06c by André Balsa.

Source, three-language manual and a changelog that explains the reasoning
behind each change:
https://github.com/jmnlabs/GPSDO_FreeRTOS
 
The following users thanked this post: lucido

Offline Solder_Junkie

  • Frequent Contributor
  • **
  • Posts: 653
  • Country: gb
Re: Yet another DIY GPSDO - yes, another one
« Reply #1152 on: August 20, 2026, 07:44:32 pm »
Thanks to the Gerber and drilling files posted to Github, by vindoline, I was able to order a set of boards and front/rear panels (PCB material) from JLCPCB. I am currently running with the firmware by AndrewBCN, version 0.06c

A few points for potential builders of these units using the above board and case...
1. The 1306 OLED is too large for the space between the print board and the upper case. It just fits if you file down the edge of the upper case until it is the thickness of thin cardboard. Bend down the pins of the OLED to avoid shorting to the case.
2. If you mount the BNC sockets flush on the board the holes in the front panel do not line up, they need around 2.5 mm clearance under the body of the socket which is quite awkward to arrange.
3. I replaced some of the 100nF disc ceramic capacitors on the supply rail with 10uF electrolytic ones for improved smoothing.
4. The rear panel hole for the STM32 board USB-C socket is intended to align with an STM32 board soldered directly by its pins onto the PCB, it will not line up if you want to use a socket.
5. The very small GPS module cannot easily be re-configured once soldered on the board, however, the holes in the board are large enough to allow easy removal if you really need to. I used a Ublox Neo M8N module from AliExpress, it was 12 GBP and seems more or less genuine, and I am using GPS+Galileo satellites, it came preset with GPS+Glonass. You can re-configure these "non USB" small modules using an FTDI to serial board, such as eBay UK item: https://www.ebay.co.uk/itm/205609674484
6. Most GPS modules come pre-soldered with angled pins on the wrong side of the board, they are easy to remove if you use solder wick and cut the plastic between pins with fine side cutters, heat each pin with a soldering iron and pull it out. I have quite a few of the straight pins, think they came with Raspberry Pi's

I am awaiting black nylon nuts and bolts for the display mounting, excuse the untidy and over long steel bolts used as a temporary measure.

The plot shows the above unit after a 24 hour warm up, compared to a Lars unit. Both are referenced to an Efratom FRS-C rubidium oscillator using a TinyPFA and TimeLab software. The harmonic suppression on the sine wave output is pretty good at -50 dB.

I have not tried the FreeRTOS version since mounting the parts on a PCB. Jaroslaw, have you run a plot against a rubidium with yours?

The link to the circuit, Gerber and drilling files from vindoline are here: https://github.com/vindoline/STM32-GPSDO_build

SJ
 
The following users thanked this post: jmnlabs

Offline jmnlabs

  • Regular Contributor
  • *
  • Posts: 64
  • Country: pl
Re: Yet another DIY GPSDO - yes, another one
« Reply #1153 on: August 20, 2026, 08:55:28 pm »
@Solder_Junkie

Hi SJ,

First of all — that is a really handsome build. The panel, the layout, and a clean 10 MHz peak with the harmonics well down on the tinySA: well done.

Your prod about the rubidium is fair, and I owe the thread an honest answer: I do not own one. My rubidium is called Dan. :-) He ran my RTOS firmware (v1.01, algorithm 11) on his own hardware — his board with a u-blox F9T and a Trimble T34210-T2 — for five days against his S250 rubidium standard on the tinyPFA. The attached plot is his measurement: my software, his hardware, his reference. About 8e-12 at 1 s, a plateau around 3e-12 out to about 1000 s, 7.5e-13 at 10,000 s and about 8e-14 at 100,000 s.

Your own comparison against Lars's unit and the Efratom is exactly the right way to do this, and 2e-10 at 10 s from a window-sill breadboard is a respectable number for 006c. Incidentally, that kind of direct comparison is exactly why I deliberately left André's original algorithms completely unchanged in the FreeRTOS firmware — so builders can run them on the exact same hardware and see the difference for themselves.

On running the new code on your board: earlier today I posted v1.05 with full sources — algorithm 12 (the multi-level accumulator) and the 24-bit dithered PWM are the highlights, and it is definitely worth trying on that fine PCB. Just remember the hardware limitations: viadoline's design has no LTIC and no picDIV, so the phase path that algorithms 10–12 rely on is missing and you would land on the simpler ones (though the dithered PWM and the new fixes still apply). If you want the full performance, consider adding the missing hardware on a small add-on PCB. To be precise, Scrachi's board actually already had the PICDIV, so I only had to build a small daughterboard for the LTIC, and it worked out very well.

And now that I have shown you my rubidium results, it is your turn: show us the prototype at last. Yes, I mean that tangle of wires on the breadboard. Unless you are now too ashamed of it to show it next to that beautiful new enclosure ;)

Best regards,
Jaroslaw
 

Offline Solder_Junkie

  • Frequent Contributor
  • **
  • Posts: 653
  • Country: gb
Re: Yet another DIY GPSDO - yes, another one
« Reply #1154 on: August 20, 2026, 10:19:58 pm »
Hi Guys
This is the tangle of wires on a breadboard. Looking at the Allan Deviation of my Lars at 500s, it's 7.38E-12 and the version 0.06c is 2.17E-11
It would be interesting to see a frequency difference plot of your unit Jaroslaw. The jitter of most low cost GPSDO units is quite high when you look a low averaging plots.

SJ
« Last Edit: August 20, 2026, 10:31:49 pm by Solder_Junkie »
 
The following users thanked this post: jmnlabs

Offline jmnlabs

  • Regular Contributor
  • *
  • Posts: 64
  • Country: pl
Re: Yet another DIY GPSDO - yes, another one
« Reply #1155 on: August 20, 2026, 10:29:17 pm »
Hi SJ,

Ha — that is a perfectly respectable tangle. Every wire clearly knows where it is going, and I can spot electrolytic and ceramic decoupling where it matters, which puts it ahead of half the breadboards in this thread. 2e-10 at 10 s from exactly this board on a window sill is a number some PCB builds never reach. Wear it with pride.

While it is on the bench: the screen says 006c, so when you move the FreeRTOS build across, run the USB test with the battery-powered laptop or the isolator first — the ground returns here run the length of the board, which is exactly the kind of path that bites when enumeration starts.

And the only question that matters: which wire is the one you tug first when the display goes dark? ;)

Best regards,
Jaroslaw
 

Offline jmnlabs

  • Regular Contributor
  • *
  • Posts: 64
  • Country: pl
Re: Yet another DIY GPSDO - yes, another one
« Reply #1156 on: August 20, 2026, 11:32:03 pm »
Hi SJ,

Attached is the compressed 23-hour log of algorithm 12 (.txt report plus the raw 1 Hz .csv, so anyone can plot the frequency difference themselves). Headline figures, oscillator a Vectron C4550A1-0213 at +319.5 µHz/LSB: overlapping ADEV from the LTIC phase record 3.6e-9 at 1 s, 3.7e-10 at 10 s, 1.1e-10 at 100 s, 1.4e-11 at 1000 s, 1.5e-12 at 10 000 s; phase RMS over the run 11.0 ns, peak-to-peak 738 ns; 325 corrections, 257 zero-crossings, 1 picDIV re-arm.

Why this and not a rubidium plot: because I do not own a rubidium. The five-day ADEV against the S250 I attached earlier is Dan's measurement — my software on his hardware, his reference. What I can produce on my own bench is what the attached file is: a closed-loop self-assessment, the loop measured against the GPS 1PPS it steers from, and the file says plainly what that means. Below ~100 s it is the detector and the receiver's sawtooth, not the oscillator; above ~1000 s it shows how well the loop tracks GPS, which is the useful part. An independent ADEV against a rubidium would be worth more — it is the measurement this run is asking someone to make.

Best regards,
Jaroslaw
 

Offline jmnlabs

  • Regular Contributor
  • *
  • Posts: 64
  • Country: pl
Re: Yet another DIY GPSDO - yes, another one
« Reply #1157 on: August 21, 2026, 08:37:14 pm »
**GPSDO FreeRTOS v1.05 — three fixes, and a warning if you build without the phase detector**

Sources attached, zipped.

Dave (Solder_Junkie) has been building v1.05 for a board with an SSD1306, an
AHT/BMP combo module and a NEO-M8N — **no picDIV, no LTIC phase detector** — and
in the process found three separate faults, each of which was hiding the next.
Two of them are build failures that make the firmware impossible to compile in
that configuration at all. If you are building without the detector, take this
package rather than the released one.

I should say plainly why these survived as long as they did: **almost everyone
building this, myself included, compiles with `GPSDO_LTIC` enabled.** The
detector is on every board I have and on every board I have had reports from, so
the configuration that fails is one none of us was building. It compiled and ran
perfectly on the bench for months. Dave's is the first board without a detector,
and all three faults surfaced in a single afternoon.

---

**1. The firmware would not build with `GPSDO_LTIC` off**

Turning the detector off gives fourteen `was not declared in this scope` errors
and an orphaned closing brace. The algorithm-12 state and globals are defined
*outside* the `#ifdef GPSDO_LTIC` block in `GPSDO_algorithms.cpp`, and the CLI
reads them unconditionally — but every one of their declarations sat *inside*
that block in `GPSDO_algorithms.h`. Separately, the `#endif` closing the guard
around `multi_level_accum()` sat one line above that function's closing brace,
so with the guard off the brace had nothing to close.

A declaration costs nothing when the definition is absent, so the guard now
covers the two functions that genuinely need the hardware and nothing else.

**2. And then it would not link**

`g_freq_damp_win_dpll` and `g_freq_damp_win_lock` — the FA / FAD / FAL damping
windows — are defined inside the same guard, but they belong to the persisted
settings block and the CLI prints and sets them unconditionally. So
`settings_store.cpp` and `gpsdo_cli.cpp` reference them whatever the
configuration:

```
undefined reference to `g_freq_damp_win_dpll'
  from snapshot_full(), settings_recall(), settings_save_partial(), dispatch()
```

Four bytes of RAM against a firmware that cannot be built without a phase
detector is not a trade worth making. The definitions moved out of the guard.

**3. A blocking USB CDC write freezes the display — this one affects everybody**

This is the one worth reading even if your board has the detector.

`vDisplayTask` drives the OLED, LCD, TM1637 and TFT **and** writes the 1 Hz
telemetry report. STM32duino's `USBSerial::write()` spins in place while the
endpoint is busy for as long as the host is connected. So a host that has
enumerated the CDC port but is not draining it — a terminal opened and closed, a
serial monitor that went away, some Windows drivers — stops that task dead,
inside the write, on the far side of the 30 ms serial-mutex timeout. There was
no `availableForWrite()` guard anywhere in the firmware; I checked, it was zero
occurrences.

The thing that freezes is therefore the **display**, which reads as a crashed
board and is nothing of the kind: the frequency and control tasks never touch
serial and go on disciplining the oscillator throughout. If you have ever
plugged in a USB cable and had the display stop while the 10 MHz stayed good,
this is why.

**A test that settles it in ten seconds:** the blue LED on PC13 is toggled
directly in the 2 Hz timer ISR and owes nothing to any task. If it keeps
blinking while the display is frozen, the MCU is alive and a task is blocked in
a USB write. If it stops too, the board hung earlier still — in `setup()` while
printing the boot banner, before the timers start. I have fixed the first; if
anyone can reproduce the second, please say so, because I have not fixed it on a
guess.

The report now asks how much room the port has and drops the whole line if it
will not fit. Telemetry is a live stream, not a log — a report nobody is reading
is worth dropping, and the next one is a second away. `TeeSerial` gained its own
`availableForWrite()` returning the smaller of its two ports, because `Stream`'s
default returns 0 and would otherwise silence a `GPSDO_BLUETOOTH_PARALLEL` build
completely.

---

**About the config in the zip**

`gpsdo_config.h` is set up for **Dave's** hardware, not for a generic board:

```
GPSDO_OLED_SSD1306        on     SSD1306 128x64 I2C
GPSDO_AHT10               on     temperature + humidity
GPSDO_BMP280_I2C          on     temperature + pressure (combo breakout)
GPSDO_BLUETOOTH_PARALLEL  on     output on BOTH USB CDC and Serial2
GPSDO_GPS_TIMING          off    NEO-M8N is not a timing receiver
GPSDO_PICDIV              off
GPSDO_LTIC                off    no hardware phase detector
GPSDO_PWM_DITHER          on     24-bit dithered PWM on PB9 (TIM4 CH4)
GPSDO_GEN_2kHz_PB5        on     test square wave, so PB5 is busy
```

Set your own switches before building. The compiled binaries in `build` are for
exactly the above and nothing else.

`GPSDO_BLUETOOTH_PARALLEL` is worth knowing about generally: with it on,
everything the firmware prints goes to the USB CDC port **and** to Serial2 on
PA2/PA3 at 57600. A cheap USB-TTL adapter there gives you a console that does
not depend on the CDC port at all — useful in its own right, and doubly so while
we are chasing a USB fault.

Without a phase detector, **algorithms 10, 11 and 12 cannot run** — they work on
the detector's phase in nanoseconds and there is no fallback. A fresh flash comes
up on algorithm 0, the simple stepped controller, which uses the frequency
counter alone and is the right place to start. Everything from 0 to 9 runs
without a detector.

If you are running a u-blox timing receiver and want plain navigation mode
instead of survey-in, you do not need to edit any source: comment out
`#define GPSDO_GPS_TIMING`, or use `SV 0` at the CLI, which is stored in flash.

All three fixes are also in v1.06, which is in progress.

---

**Dave** — two things when you get a chance, and thank you for the patience:

- **Does the OLED show a UTC time?** Time and position come from different
  places: time follows RMC, position follows an actual fix. Time shown with
  "GPS: acquiring" and Sat: 0 means the module is talking to the STM32 and
  simply has no fix yet — antenna, sky view, cold start; an M8N with no almanac
  indoors can sit like that indefinitely. No time either means no NMEA is
  reaching the firmware at all, which is a completely different hunt.
- **The boot output**, from `GPS init: probing baud rate...` down to `GPS init
  done`. Those six or seven lines say which baud was detected, how many NMEA
  sentences were disabled and whether the UBX config was ACKed. With the
  parallel output enabled you can capture it from Serial2 even if USB is being
  difficult.

`T 9600` at the CLI is tunnel mode, if you want to point u-center straight at
the receiver — it bridges the console through to the module for 300 s.

- Jaroslaw
« Last Edit: August 21, 2026, 08:47:36 pm by jmnlabs »
 

Offline jmnlabs

  • Regular Contributor
  • *
  • Posts: 64
  • Country: pl
Re: Yet another DIY GPSDO - yes, another one
« Reply #1158 on: August 22, 2026, 11:13:15 am »
Hi everyone,

Today I found another bug that was causing reports to freeze in certain hardware configurations.
I'm posting the fix on the forum.

Best regards,
Jaroslaw
 
The following users thanked this post: Solder_Junkie

Offline Solder_Junkie

  • Frequent Contributor
  • **
  • Posts: 653
  • Country: gb
Re: Yet another DIY GPSDO - yes, another one
« Reply #1159 on: August 22, 2026, 01:27:02 pm »
Firstly thanks to Jaroslaw for moving this project forward and to vindoline for offering the Gerber and drilling files for the PCB and front/rear panels.

Most plots of GNSS disciplined oscillators only show Allan Deviation, and then generally over several hours to several days. IMO that is marketing rather than engineering. Any GPSDO over a long time period will look impressive as it will follow the stability of the satellite system.

For practical purposes what matters is (a) how close is the oscillator output to being "on frequency" after warming up and stable, (b) how quickly can it be considered stable when turning on from cold, and (c) how much does it vary over a few seconds to a few minutes. These GPSDO units have uses to hold test equipment or radio equipment on frequency. Most will easily stay within 1 part in 10^9 (1 Hz at 1 GHz), which is generally good enough for home workshop or radio amateur use.

I have a rubidium oscillator and a TinyPFA (phase frequency analyser). The rubidium is around 1 part in 10^11 off frequency at the moment. The attached plots are a comparison run against the rubidium.

Firstly, these are the GPSDO units I have been testing recently:

A Lars Walenius GPSDO with an NEC TCO-6703N oven and a genuine UBlox Neo M8T GNSS module. It is used with a loop time of 120 seconds.

A Simple GPSDO based on the work of AndrewBCN and Jaroslaw, built on a PCB designed by vindoline, with a CTI OSC5A2B02 oven, AliExpress "Ublox Neo M8N" (possibly fake), and no LTIC fitted. Currently using FreeRTOS v1.05

A Leo Bodnar LBE-1420, which only uses a TCXO

In all cases the antenna is a survey grade "flying saucer" shaped outdoor antenna with a clear sky view. All these units are configured to use both GPS and Galileo satellites combined without SBAS compensation. The M8T in the Lars unit operates in "survey-in" fixed mode, the other two are not operated in fixed site mode.

Firstly, the Lars unit is stable to around 2 parts in 10^11 after an hour from cold, that is 2 Hz at 100 GHz. These can be regarded as the "gold standard" of home made GPSDO units. With the high stability oscillator it is easy to see the difference between using a navigation grade Neo 6M unit and a Neo M8T timing module, and also the improvement of an outdoor antenna over a "window sill" hockey puck type antenna.

The Leo Bodnar unit is very small and powered from USB. The relatively fast warm up make these units ideal for occasional use with test equipment and the ability to configure them for any output frequency from 1 Hz to 1.1 GHz is extremely useful. The small size and low power consumption are probably unique among GPSDO units. They are stable to around 1 part in 10^10, which is 1 Hz at 10 GHz.

Lastly my Simple GPSDO, this is powered by 5 Volts from a "wall wart" power supply. The warm up time is lengthy, typically around 8 to 12 hours to settle. My unit uses a low cost surplus Chinese CTI oven which is the limiting factor in this unit. Using a window sill antenna, or an outdoor antenna, makes little difference to stability as the oven wanders up and down in frequency more than the difference an indoor/outdoor antenna makes. The loop time of 429 seconds is easy to see on a TimeLab plot from a cold start as the frequency steps every 429 seconds. After fully warming up, the display showed PWM 33675 and uF+, then over the next 30 minutes it showed 33677 and hit... however, the output frequency wandered up and down quite noticeably. The attached image shows this 30 minute plot running disciplined against another 30 minute with "hold" turned on with the antenna disconnected, which is the oven free running with no control. You will find it difficult to determine whether the green or the magenta trace is the disciplined one or the hold one, mischievously I cut off the legend to leave you guessing. The stability is mostly to within 1 part in 10^10, but note the very long warm up time. The hold mode is very effective. In the case by vindoline, this little GPSDO looks very impressive.

Plots attached
SJ (Dave)
« Last Edit: August 22, 2026, 01:56:48 pm by Solder_Junkie »
 
The following users thanked this post: jmnlabs

Offline jmnlabs

  • Regular Contributor
  • *
  • Posts: 64
  • Country: pl
Re: Yet another DIY GPSDO - yes, another one
« Reply #1160 on: August 22, 2026, 06:26:42 pm »
Hi Dave,

Thank you for this — and for the kind words. You are right that a multi-day ADEV is mostly a plot of the satellite ensemble; the engineering lives in your three questions: where does it sit after warm-up, how fast does it get there from cold, and what does it do over seconds to minutes. Those are the numbers a user actually lives with.

Your three units sit at three different corners of the same trade-off, and the plots show it cleanly. The Lars unit is what a good oven and a timing receiver buy you: 2e-11 an hour from cold. The Leo Bodnar is the portable corner — 1e-10, but small, USB-powered and usable in minutes. And your simple GPSDO is the honest corner: 1e-10, with the surplus CTI oven setting both the 8–12 hour settling and the wander envelope.

I am not going to guess which trace is disciplined and which is hold — and I would argue that not being able to tell *is* the result. When the oscillator is the limiting factor, a well-behaved loop should add nothing on top of it, and that is exactly what your plot shows: at 30 minutes the loop is neither helping nor hurting, because the oven wanders faster than a 429 s loop can usefully correct, and the receiver's sawtooth limits how hard it may push. The loop's real contribution — absolute accuracy and days-long hold — is invisible in a 30-minute window by design.

On the 429 s steps: with no phase detector the loop steers on the frequency counter, so the rhythm you see is the controller deciding, not the DAC quantising — the dithered PWM in v1.05 has already taken the step size down to about 1.25e-13. The envelope around those steps is the oven, and no loop setting will shrink it. Algorithms 3, 5 and 8 will change the rhythm and are worth trying on that board, but they will not change the ceiling.

And when you do try them, remember that the firmware together with the GPSDO Tuner script exposes every algorithm parameter for live modification. Wherever I could, the firmware computes sensible values automatically, and in most cases they work well — but optimal? That is exactly why the tuner is part of the project: so that anyone can consciously improve (or break ;-) ) my "optimal" settings. Half the pleasure in this hobby is turning the knobs and watching what comes out. ;-)

So the engineering conclusion from your own data is the one you already drew: the next improvement on that board is the oscillator, not the firmware — a better surplus OCXO will do more than anything I can ship. Posts like this, with short windows, cold starts, hold mode and warts included, are what this thread should have more of.

Best regards,
Jaroslaw
 
The following users thanked this post: Solder_Junkie

Offline jmnlabs

  • Regular Contributor
  • *
  • Posts: 64
  • Country: pl
Re: Yet another DIY GPSDO - yes, another one
« Reply #1161 on: Yesterday at 01:00:44 am »
A user manual for the GPSDO — a small present for the thread

Hi everyone,

I've finished a complete user manual for this GPSDO, in three languages — English, Polish and Spanish (attached as PDFs). It was written for people building it, not for reading cover to cover: pick the part you need.

What's inside:

Building the firmware — Arduino IDE setup, every compile-time option in gpsdo_config.h explained (displays, sensors, LTIC detector, timing receivers), and the two Tools-menu settings people get wrong.
Flashing — ST-Link, DFU and friends, plus the one rule that really matters: settings and calibration live in flash sector 7; a routine upload never touches them, but "Erase Chip" destroys an hour of tuning.
First start — the calibration sequence (CT first, then LC — the order matters), choosing the algorithm, saving, and what a healthy unit looks like.
All thirteen algorithms 0–12 with their parameters and what each knob actually changes — including a tuning guide for the multi-level accumulator.
Every display and every field, the 1 Hz telemetry report line by line, a full command reference, the PC tuner, logging, and a troubleshooting table.
Two appendices for the curious: how a GPSDO works in plain words, and PID for the reluctant — so you know what you're turning before you turn it.
It documents v1.06, but almost everything applies to v1.05 as well.

Why post it without the code? The firmware isn't published yet — a few things in this version are still work in progress, the external DAC support among them. The manual describes what already works, and that part barely changed between versions.

One honest caveat: I proofread all three language versions myself — and where the author is also the proofreader, something always slips through. If you spot an error, whether a wrong number, a command that doesn't match the firmware, or a paragraph that makes no sense, please say so in the thread. I'll keep an errata and fold the corrections into the next revision.

And honestly — the manual was written so that the answer to most questions is already within reach before you ask. Worth a read before posting; for everything that's not in it, ask away, that's what the thread is for.

Cheers, Jaroslaw
 
The following users thanked this post: Solder_Junkie, lucido

Offline jmnlabs

  • Regular Contributor
  • *
  • Posts: 64
  • Country: pl
Re: Yet another DIY GPSDO - yes, another one
« Reply #1162 on: Yesterday at 04:05:47 pm »
v1.05-rtos package update — field fixes and v1.06 backports

Hi everyone,

Time to post the updated package. It is the v1.05-rtos firmware with my generic configuration, refreshed with everything field testing has shaken out since the last drop — much of it thanks to Solder Junkie's bench work, the rest backported from the v1.06 line I'm still working on.

What's new:

USB serial reporting fixed. A host that connected without reading could wedge the display or silence the 1 Hz telemetry outright (the USB CDC queue was smaller than one status report). Reports are now written in bounded chunks and the queue is 1 KB — logging over USB behaves.

GPSDO_FAKE_UBLOX — a new compile switch for the Chinese u-blox clones most builders actually receive from eBay/AliExpress. Clones ignore the binary configuration and some go silent after the failed config round (the "acquiring forever" trap); with the switch defined, the firmware probes the baud rate and sends nothing else. Discipline is unaffected — the 1PPS never cared about UBX. Not hardware-tested yet (my only cheap module, a NEO-6N, happens to behave), so reports welcome.

BOOT0, current boards. WeAct v3.1 has a button, not a jumper — the manual now gives the reliable USB recipe (hold BOOT0 while plugging in, release after a few seconds) instead of the hold-and-tap-NRST folklore.

Boot banner now carries a build timestamp and per-algorithm credits (0–2 after André Balsa, 3–9 mine, 10 after Dan Wiering's concept and measurements, 11 after Lars Walenius, 12 after Alan Cashin) — when someone reports a problem, the first log line says which build they run.

The updated manuals (EN/PL/ES) are in the zip — operation, calibration, every command, every algorithm and how to tune it, including the algo-12 limit table and Alan's scheduled-corrections philosophy. Worth a read before asking; the thread will be gentler for it.

Why not v1.06 itself? Two things left on it: the AD5680 external-DAC driver (bit-banged, pins under discussion) and the automatic level-limiting of algo 12 — that machinery still misbehaves on some installations, so it stays behind the door until it works. Hand-set limits are usable today; the design goal is the automatic table, and I would rather ship it when it's the automation that's excellent, not the instructions for working around it.

As always: Dan's rubidium-referenced ADEV runs keep the algorithms honest, Alan's design notes keep me honest, and Lars' loop keeps the oscillator honest.

Cheers, Jaroslaw

Fix 3 — clone GNSS detection and ns-based limit table

Two fixes for the package posted above — same download spot, new build timestamp in the banner.

The "acquiring forever" clone bug, take two. Solder Junkie's cold-start logs showed the earlier switch wasn't the whole story: even with zero UBX configuration, some Chinese clones still never produced a fix. The culprit turned out to be the baud probe itself — it sends a binary poll and accepts any response byte as "found", and a clone's auto-baud will happily adapt its input to that poll and ACK it at 38400 while its NMEA output keeps running at its own rate. The firmware then listened to silence. The fix: the firmware now passively listens for NMEA traffic at every candidate baud before sending a single byte — nothing leaves the STM32 until the module's own announcements are heard. Active polling remains only as the fallback for receivers that output pure UBX. On a cold start you should now see GPS: NMEA traffic at <baud> naming the rate the module actually speaks.

Algo-12 limit table now speaks nanoseconds. The MLP command always claimed to take ns while actually expecting internal accumulator units — a trap that bit me first (a table entered 25× too tight, corrections chasing noise). MLP and ML (and the Tuner roundtrip) now work in ns end to end; the stored format is unchanged. Alan's table from his e-mail enters 1:1 — MLP 0 462 through MLP 10 63 — and ML shows ns first, so what you read is what you set.

As before: reports welcome, especially clone owners — the first boot line tells us everything.
« Last Edit: Yesterday at 06:45:30 pm by jmnlabs »
 
The following users thanked this post: Solder_Junkie

Offline lucido

  • Contributor
  • Posts: 41
  • Country: es
Re: Yet another DIY GPSDO - yes, another one
« Reply #1163 on: Yesterday at 06:47:21 pm »
Hi Jaroslaw.
Version 1.05 works correctly. It locks in six minutes and the fix is ​​almost instantaneous. I'm trying version v1.05_fix2 with algorithm 12, but it doesn't fix the GPS. From the serial port, I get GPS: no position fix yet. I tried deselecting the #define GPSDO_FAKE_UBLOX instruction, but it doesn't fix the GPS. The yellow LED stays off. Everything else works. Do you have any suggestions? ok try fix3
Thanks a lot.
lucido
 
The following users thanked this post: jmnlabs

Offline jmnlabs

  • Regular Contributor
  • *
  • Posts: 64
  • Country: pl
Re: Yet another DIY GPSDO - yes, another one
« Reply #1164 on: Yesterday at 07:00:23 pm »
Hi Lucido,

Thanks for the report — but "it doesn't fix the GPS" alone doesn't give me anything to work with, I'm afraid. To diagnose it I need three things:

The full boot log — everything the unit prints from power-up until about a minute in. The GPS lines in it tell the whole story: which baud was detected, whether NMEA traffic was heard, whether any configuration was ACKed. Without it I'd be guessing.
Your gpsdo_config.h — the file as you compiled it (the relevant part is which GPSDO_* lines are active). Note that GPSDO_FAKE_UBLOX changes nothing unless it is defined, so deselecting it only matters if you had it enabled before.
Which GNSS module you are actually using — exact marking from the shield, and whether it is a genuine u-blox or one of the Chinese copies (eBay/AliExpress). The behaviour differs a lot between them, and the new baud detection treats them differently on purpose.
One observation meanwhile: you say v1.05 locks in six minutes, and v1.05_fix2 shows "GPS: no position fix yet". If the module is a clone, look for the line GPS: NMEA traffic at <baud> in the boot log — if it names a baud the module isn't actually outputting, that's the bug and the log will prove it.

For the future, let's make this the rule for bug reports: full boot log + the config you compiled + the exact module. With those three, almost everything is solable in one exchange; without them, it's folklore.

Thanks, Jarosław
 

Offline Solder_Junkie

  • Frequent Contributor
  • **
  • Posts: 653
  • Country: gb
Re: Yet another DIY GPSDO - yes, another one
« Reply #1165 on: Yesterday at 07:02:22 pm »
Hi Jaroslaw

version 1.05 fix 3 has fixed the problem I had with the fake GPS module.

Well done!  :-+

SJ
 
The following users thanked this post: jmnlabs

Offline jmnlabs

  • Regular Contributor
  • *
  • Posts: 64
  • Country: pl
Re: Yet another DIY GPSDO - yes, another one
« Reply #1166 on: Yesterday at 07:09:29 pm »
Hi, Dave

Show me full bootlog, please.

-Jarosław
 

Offline lucido

  • Contributor
  • Posts: 41
  • Country: es
Re: Yet another DIY GPSDO - yes, another one
« Reply #1167 on: Yesterday at 07:18:11 pm »
Hi Jarosław.
The GPSDO_FreeRTOS._v1.05_fix3 version works correctly. It first does the survey and then fixes it immediately. The GPSDO_FreeRTOS._v1.05_fix2 version did the warmup but not the survey, and it didn't fix it. I figured out. The next time I find a problem, I'll send you the log of everything.
Lucido.
 
The following users thanked this post: jmnlabs


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf