Zpět na domů

Stratum 1 NTP na Raspberry Pi s chrony a GPS

Článek popisuje vytvoření autonomního Stratum 1 NTP serveru na Raspberry Pi s použitím chrony, libgpiod v2, DCF77 a GPS NEO-M8T. Dosahuje se přesnosti 42 ns. Rozebrány jsou problémy migrace z ntpd a GPIO API.

Přesný NTP Stratum 1 na RPi: 42 ns s GPS PPS
Advertisement 728x90

Autonomní Stratum 1 NTP server na Raspberry Pi: chrony s DCF77 a GPS PPS v roce 2026

Na Raspberry Pi OS Bookworm/Trixie staré návody na NTP servery nefungují kvůli libgpiod v2, přechodu na chrony a změnám v GPIO čipech. Implementace v C++20 využívá DCF77 přijímač RC8000 na GPIO 17 a GPS modul ublox NEO-M8T s PPS na GPIO 18. Server zajišťuje přesnost <1 µs bez internetu, s nezávislou kontrolou časových zdrojů.

Problémy zastaralých implementací

libgpiod v2 rozbíjí GPIO kód

libgpiod v2 odstranila API v1 bez zpětné kompatibility. Starý kód s gpiod_chip_open_by_name a gpiod_chip_get_line se nezkompiluje:

// libgpiod v1 — NEKOMPILUJE se s v2
struct gpiod_chip *chip = gpiod_chip_open_by_name("gpiochip0");
struct gpiod_line *line = gpiod_chip_get_line(chip, 17);
gpiod_line_request_both_edges_events(line, "dcf77");

Nové API vyžaduje gpiod_line_settings_new() a gpiod_line_config_new():

Google AdInline article slot
// libgpiod v2 — správný přístup
const SettingsPtr settings(gpiod_line_settings_new());
gpiod_line_settings_set_edge_detection(settings.get(), GPIOD_LINE_EDGE_BOTH);
gpiod_line_settings_set_event_clock(settings.get(), GPIOD_LINE_CLOCK_REALTIME);

const LineCfgPtr line_cfg(gpiod_line_config_new());
gpiod_line_config_add_line_settings(line_cfg.get(), &offset, 1, settings.get());

const RequestPtr request(gpiod_chip_request_lines(chip.get(), req_cfg.get(), line_cfg.get()));

Klíčová výhoda — GPIOD_LINE_CLOCK_REALTIME: události získají časové značky od jádra v přerušení, jitter klesá z 40 ms na <5 ms.

Přechod z ntpd na chrony

ntpd byl nahrazen chrony v Bookworm. Srovnání:

| Parametr | ntpd | chrony |

Google AdInline article slot

|----------|------|--------|

| Konvergence | minuty | sekundy (makestep 0.5 3) |

| Ztráta signálu | degradace | holdover (local stratum 10) |

Google AdInline article slot

| PPS | patche | nativní refclock PPS |

| Přesnost PPS | ~100 µs | <1 µs |

Oba podporují NTP SHM pro výměnu dat přes sdílenou paměť.

GPIO čip na RPi 5

gpiochip0 je zastaralý. Na RPi 5/Trixie je potřeba gpiochip4 (ověřit gpiodetect).

Architektura systému

Dva zdroje času:

  • GPS NEO-M8T: PPS (/dev/pps0) + NMEA přes gpsd (NTP SHM #0)
  • DCF77 RC8000: GPIO 17 → dekodér → NTP SHM #2
  • chrony: stratum 1 s prefer PPS
  • Webový monitor: chronyc + journald na :8080

Konfigurace chrony:

refclock PPS /dev/pps0 refid PPS precision 1e-9 poll 0 dpoll -2 lock NMEA prefer
refclock SHM 0 refid NMEA precision 1e-3 poll 0 dpoll -2 offset 0.0 delay 0.2 noselect
refclock SHM 2 refid DCF7 precision 1e-2 offset 0.0 delay 0.008 poll 6 dpoll 5
local stratum 10

DCF77 slouží jako záložní zdroj a detektor GPS spoofingu (odchylka >několik sekund).

Dekodér DCF77

Timestamp od jádra

GPIOD_LINE_CLOCK_REALTIME poskytuje značku přerušení, nikoli userspace. StdDev v SHM: <5 ms.

NTP SHM pro 64-bit

Struktura s paddingem:

struct NtpShmTime {
    int32_t mode;
    int32_t count;
    int64_t clockTimeStampSec;
    int32_t clockTimeStampUSec;
    int32_t _pad;
    int64_t receiveTimeStampSec;
    int32_t receiveTimeStampUSec;
    int32_t leap;
    int32_t precision;
    int32_t nsamples;
    int32_t valid;
};
volatile NtpShmTime *shm_ = nullptr;

Protokol DCF77

59 bitů/minutu v BCD s paritou:

  • 100 ms HIGH → bit 0
  • 200 ms HIGH → bit 1
  • Pauza >1,5 s → značka minuty

Validace: 3 skupiny parity + timegm(). Bootstrap: 2 snímky s rozdílem 60 s.

Nastavení NEO-M8T

  • Firmware TIM: RAIM, nízký PPS jitter
  • dynModel=Stationary: jitter 5–10 ns
  • antCableDelay=50 ns: kompenzace kabelu
  • 4 konstelace: 20–30 satelitů
  • lpMode=Continuous: bez úspory energie

Webový monitor a nasazení

dcf77_web: HTTP :8080, chronyc v JSON, UI v binárce. API: /api/status, /api/prefer (pouze localhost).

Sestavení vcpkg + CMake:

cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)

Ansible nasazení s systemd hardening.

Výsledky

chronyc tracking:

  • Stratum: 1
  • Systémový čas: +42 ns
  • RMS offset: 51 ns
  • Root dispersion: 15 ns

DCF77: ~3 ms.

Co je důležité

  • libgpiod v2 vyžaduje nový objektový model s GPIOD_LINE_CLOCK_REALTIME
  • chrony překonává ntpd v přesnosti PPS (<1 µs) a holdover
  • NTP SHM na 64-bit potřebuje explicitní padding pod int64_t
  • NEO-M8T TIM + Stationary: PPS jitter 5–10 ns
  • DCF77 validuje GPS proti spoofingu

— Editorial Team

Advertisement 728x90

Číst dál