GPS-disciplined 10 MHz OCXO with stratum-1 NTP server, flip-clock, and a graphical UI for the Raspberry Pi Pico 2 W (RP2350).
- 10 MHz OCXO with GPS-disciplined frequency correction
- Resolution: 1 Hz single-sample (100 ppb), <1 ppb after averaging
- Drift: typically below 10 ppb when locked
- PI controller with gain scheduling (ACQUIRE for large errors, TRACKING after convergence)
- Median-of-5 filter on the 1PPS samples for robustness against GPS jitter
- Holdover mode on GPS signal loss (DAC frozen at the average of the last 300 s)
Nine pages reachable with the rotary encoder:
- Main — EFC / UTC time / drift / temperature / lat-lon
- GPS satellites — PRN, elevation, azimuth, SNR per satellite
- BeiDou / GNSS satellites — multi-constellation overview
- Phase graph — cumulative TIE in nanoseconds over time
- EFC graph — DAC value history
- ADEV — Allan Deviation at τ = 10, 100, 300, 1000 s
- Network — WiFi status / IP / NTP request counter
- Flip-clock — full-screen digital clock with split-flap animation
- GPS Info — Maidenhead 12-character locator, lat/lon precision, altitude/geoid, HDOP/VDOP/PDOP, fix type
- Stratum 1 on UDP/123
- Precision: ~1 µs (PPS-anchored to the OCXO-disciplined cycle counter)
- Auto-sync of the Unix second on every fresh GPS timestamp
- Reachable over both WiFi and USB Ethernet
- Port 10110, forwards GPS NMEA sentences to up to 4 clients
- Web interface on port 80, JSON polled every second by the embedded JS
- Shows lock status, EFC, frequency error, drift, satellites per constellation, ADEV values, NTP request counter, uptime
- Reachable via the WiFi IP (shown on the Network page) or
http://192.168.7.1via USB - Multilingual (EN / NL / DE / FR), follows the language selected in the on-device menu
- 8 s timeout via the RP2350 hardware watchdog
- Resets on hangs (e.g. lwIP deadlock, infinite reconnect loop)
- Auto-pauses when a debugger is attached
The Pico enumerates as two devices on Windows 10/11 with no driver install required:
- COM port (CDC ACM) — debug serial output
- Network adapter "TenMeg Network" (CDC-NCM) — virtual ethernet
- Pico IP:
192.168.7.1 - Host receives
192.168.7.2via DHCP - All services (NTP, NMEA TCP, HTTP) are reachable without WiFi
- CDC-NCM is native on Windows 10 (1809+), Windows 11, Linux and macOS
- Pico IP:
- AP
TenMeg_Setupfor first-time configuration - Scans available networks and shows signal strength
- Rescan button in the web UI
- Credentials are stored in flash
| Pin | Function |
|---|---|
| GP0 / GP1 | UART0 TX/RX to ATGM336H GPS |
| GP2 | 1PPS input from GPS |
| GP3 | 10 MHz OCXO signal (PWM counter input) |
| GP4 / GP5 | I2C0 SDA/SCL to MCP4725 DAC |
| GP6–9 | Status LEDs (Lock, GPS, WiFi, Power) |
| GP10–15 | SPI1 to ST7789V2 display |
| GP16–18 | Rotary encoder (CW, SW, CCW) |
| GP28 | ADC2 — EFC voltage monitoring |
- Raspberry Pi Pico 2 W (RP2350)
- ATGM336H-5N GPS module (1PPS + NMEA)
- 10 MHz OCXO (user-supplied, e.g. Isotemp OCXO 134)
- MCP4725 12-bit I²C DAC (0–4.096 V EFC)
- ST7789V2 1.9" 320×170 IPS TFT
- Flash the firmware over USB (drag-and-drop the .uf2 from
Firmware/build/) - The device starts in AP mode if no WiFi credentials are stored yet
- Connect a phone or laptop to
TenMeg_Setup - The captive portal opens automatically
- Pick a WiFi network, enter the password, save
- Rotate in page mode: switches between the nine pages
- Press in page mode: opens the settings menu
- Rotate in the menu: scrolls through items
- Press in the menu: selects an item
- Brightness — display brightness (0–100%)
- Language — EN / NL / DE / FR
- UTC offset — time zone for the flip-clock (−12 to +14 hours)
- WiFi Setup — start the configuration portal
- Close — save all settings and return
- Default: NMEA passthrough on the USB CDC port (compatible with VisualGPSView, etc.)
- Debug mode: boot with the encoder button held, or type
debugover the CDC link
Stored automatically:
- Brightness
- Language
- UTC offset
- WiFi credentials
- Last visited page (3 s debounce after the last change)
- Last lock DAC value (every 10 minutes while locked, for fast recovery after reboot)
# Verify the server is reachable
ntpdate -q <pico_ip>
# Windows Time sync
w32tm /stripchart /computer:<pico_ip>
# Permanent chrony entry
server <pico_ip> iburstRequires the Raspberry Pi Pico SDK 2.2.0+ and the ARM GCC toolchain 14.2.Rel1.
Before the first build, copy the WiFi credentials template:
cp Firmware/src/wifi_config.h.example Firmware/src/wifi_config.hEdit Firmware/src/wifi_config.h to fill in any SSID and password. These values
are only used as a compile-time fallback; the captive portal stores
user-entered credentials in flash and overrides them from the second boot
onward. wifi_config.h is git-ignored so it never reaches a public
repository.
Then build:
cd Firmware/build
cmake ..
ninjaThe output Firmware/build/tenmeg.uf2 can be drag-dropped onto a Pico in
BOOTSEL mode.
For automated picotool flashing on Windows the reset interface needs a
WinUSB driver:
- Flash once manually via BOOTSEL (drag-drop
tenmeg.uf2) - Install Zadig → Options → List All Devices
- Select TenMeg GPSDO (Interface 4) (USB id
2E8A:000AMI_04) - Choose WinUSB driver → Install Driver
After that the VS Code Run button works, or use:
picotool reboot -f -u
picotool load build/tenmeg.elf -x
Note: picotool load -fx in a single command is broken on Windows. The
VS Code tasks split the operation into reboot -f -u followed by load -x.
Any 10 MHz OCXO with an EFC input (0–5 V) and a TTL output works. Typical choices include:
- Isotemp OCXO 134-10
- Morion MV89
- Vectron MX-060
- Oscilloquartz BVA 8607
The EFC input is driven from the MCP4725 DAC output (0–4.096 V). A 100 µF electrolytic from the DAC output to GND acts as a noise filter.