Skip to content

Add $PMTXTS PPS timestamping (opt-in host timing telemetry)#5

Draft
peterlewis wants to merge 1 commit into
mitxela:masterfrom
peterlewis:pcc-firmware-proposals
Draft

Add $PMTXTS PPS timestamping (opt-in host timing telemetry)#5
peterlewis wants to merge 1 commit into
mitxela:masterfrom
peterlewis:pcc-firmware-proposals

Conversation

@peterlewis

@peterlewis peterlewis commented Jun 30, 2026

Copy link
Copy Markdown

Draft. One feature for the Mk IV: opt-in per-PPS host timestamping, found while building a host companion. Source-only — mk4-time/Core/Src/main.c and one documented config.txt key. Built and flashed on an STM32L476 time board and left running; it stays a draft because the qspi/output/*.bin release images still need rebuilding from the diff (see To do).

The two unrelated firmware fixes this branch used to carry — the charger-power hard-fault and the date-board text OOB — have moved to the hardening PR (#7), so this one is just the feature.

$PMTXTS per-PPS host timestamping (opt-in)

The clock disciplines to the PPS edge to sub-µs, but a host over CDC only ever sees NMEA, which arrives a few hundred ms after the second and is smeared by USB framing — so there is no host-visible timing-stability metric. (The stale cdc-pps branch approached this by toggling the CDC DCD line, which is capped at the ~1 ms USB framing floor.)

With pps = on in config.txt, one proprietary sentence per PPS edge over the existing CDC stream:

$PMTXTS,<seq>,<epoch>,<subms>,<systick>,<load>,<calerr>,<sincecal>,<temp>,<flags>*CC
field meaning
seq per-edge counter (gap detection)
epoch currentTime at the edge (Unix s, UTC)
subms/systick/load modelled sub-second position captured at the edge, before the SysTick reload — the phase error between the firmware's second and the true GPS edge
calerr the LSE cycle error calibrateRTC() already computes → ppm
sincecal seconds since last RTC calibration (holdover age)
temp STM32 internal die temperature (°C)
flags data_valid / had_pps / rtc_good

Time-critical fields are snapshotted in the PPS ISR (a handful of register reads); the sentence is snprintf-formatted and submitted to CDC from the main loop, never the ISR, serialised against the existing NMEA passthrough. With no enumerated host the record is dropped before any formatting, so the feature costs nothing when nobody is listening. The host's arrival time is USB-jittery, but the measurement is captured in firmware at the edge and carried in the payload, so transport jitter does not corrupt it. Absolute offset to UTC is not recoverable over USB — a host derives jitter, stability and drift, not absolute offset. mk4-time/Core/Src/main.c: capturePPS(), emitPPSTimestamp(), measure_temp(), the pps key, one main-loop hook.

Temperature

The die-temperature field made it cheap to characterise the oscillators against temperature on the unit. The 10 MHz HSE — which holds time through a running GPS-loss holdover — measured flat, ≈ 0.011 ppm/°C (R² ≈ 0.37) over a ~6 °C sweep, i.e. running-holdover drift from temperature is sub-millisecond over any realistic outage, so no compensation is included. The 32 kHz LSE has a real tempco but it only bites across power-loss recovery, where the MCU is off and cannot compensate. The die-temp telemetry is kept because it is useful and proven; the steering code is not. (The sweep is narrow — see To do.)

Data (STM32L476 time board, GPS-locked)

$PMTXTS,24,1782815319,0,87,79999,0,112,33,7*0A
$PMTXTS,25,1782815320,0,85,79999,0,113,33,7*02
$PMTXTS,26,1782815321,0,85,79999,0,114,33,7*07
$PMTXTS,27,1782815322,0,85,79999,0,115,33,7*04
$PMTXTS,28,1782815323,0,85,79999,0,116,34,7*0E
  • boots clean; $PMTXTS streams at 1 Hz interleaved with NMEA; checksums valid; seq contiguous
  • phase jitter ≈ 10 ns RMS / 25 ns pk-pk (systick 85 ± 2 counts)
  • die temp 33–34 °C; full lock (flags = 7)

To do

Before this leaves draft:

  • Rebuild the qspi/output/*.bin release images from the source diff. The diff is source-only; the committed binaries are unchanged and would need regenerating to match.
  • Widen the HSE temperature characterisation. The "flat" conclusion rests on a ~6 °C sweep at R² ≈ 0.37 — enough to rule out a large tempco, not to state a firm coefficient. A broader range would confirm or revise it.
  • Confidence-gated display (proposed, not in this diff — kept here as the intended use of the telemetry): dim then blank the sub-second digits as holdover uncertainty grows. calerr and sincecal give a live time-uncertainty, so the display can show only the digits it can still stand behind, degrading like an analogue needle.

With `pps = on` in config.txt, emit one proprietary NMEA sentence per PPS edge
over the existing CDC stream, carrying the sub-second phase captured at the edge
plus calibration / holdover / die-temperature telemetry. Time-critical fields are
snapshotted in the PPS ISR; formatting and CDC submission happen in the main loop,
serialised against the NMEA passthrough. With no enumerated host the record is
dropped before any formatting.

mk4-time/Core/Src/main.c: capturePPS(), emitPPSTimestamp(), measure_temp(), a
`pps` config key and one main-loop hook. qspi/config.txt documents the key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@peterlewis peterlewis force-pushed the pcc-firmware-proposals branch from 4f901ab to 02671b2 Compare July 4, 2026 09:00
@peterlewis peterlewis changed the title Fix charger-power hard-fault & date OOB write; add $PMTXTS PPS timestamping Add $PMTXTS PPS timestamping (opt-in host timing telemetry) Jul 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant