インフラ・DevOps
1995年製GPSタイムサーバーを「Telstra化」されないように再構築する
Rebuilding a 1995 GPS Time Server so I don't get Telstra'd (jeffgeerling.com)
要約
筆者は、1995年製のTrueTime XL-AK GPSタイムサーバーをRaspberry Pi 5とGNSS HATを使用して、Stratum 1 NTPタイムサーバーとして再構築しました。このプロジェクトでは、Raspberry Piのハードウェア設定、Chronyによる時刻同期、LCDディスプレイやLEDの活用、そしてPPS割り込みの最適化など、高精度な時刻同期を実現するための詳細な手順が解説されています。最終的な目標は、このサーバーをNTP Poolに追加することです。
全文翻訳
1995年製GPSタイムサーバーを「Telstra化」されないように再構築する
2026年9月4日
6月にTrueTime XL-AKタイムサーバーを購入し、GPSベースの時刻の歴史についてもっと学びたいと思いました。
6月22日に届きましたが、わずか16日後にオーストラリアのセルサービスが12時間停止するという、同様のGPSタイムサーバーによる障害が発生しました。それについて短いビデオを作成しましたが、TrueTimeの調査は後回しにしていました…が、今です。
過去数週間で、このデバイスをRaspberry Piで「レストモッド」し、Stratum 1 NTPタイムサーバーを構築しました。これは最終的にNTP Poolに追加したいと考えています。Pi 5とGNSS HATを組み込み、内蔵の16x2 LCDに時刻とGPSステータスを表示し、バイカラーLEDでステータスを示し、このボックスを再び使えるようにする方法を見つけました。
今日のYouTubeビデオで、ハードウェアの詳細をさらに説明します。
しかし、この記事では、Raspberry Piを次のようにStratum 1 NTPタイムサーバーとして機能するように設定した方法を示します。
Jimmy PaputtoのL1 GNSS HAT
Chrony(時刻同期およびNTPサービス用)
TimeおよびDaytimeプロトコル
TrueTime XL-AKに組み込まれたDensitron LCD
TrueTime AL-AKに組み込まれたバイカラーLED
私のTrueTime Piマウンティングブラケット
Raspberry Pi 5(RAM 4GB)を使用しましたが、このプロジェクト(小規模ネットワーク向けのタイミングサービスのみを実行する場合)には、44ドルのPi 5(RAM 1GB)を使用しても問題ありません。
このサーバーの当面の必要性は、来週末のVCF Midwestに時刻サービスを提供することです。私のすべてのプロジェクトと同様に、部品は数ヶ月前から集まっており、組み立ては通常、締め切りの1〜2週間前に始まります。
Jimmy Paputto L1 GNSS HAT
付属のGPIOライザーと取り付けネジを使用して、GNSS HATをPiの上にマウントしました。底部のネジを使用して、Raspberry Piバンパーを下に固定しました。
Pi OS 'Lite'(GUIなし)をmicroSDカードにフラッシュした後、Jimmy Paputto GNSS HATソフトウェアをソースからビルドしました。
```
sudo apt -y install build-essential cmake libgpiod-dev python3-dev git
clone https://github.com/jimmypaputto/gnsshat.git
cd gnsshat
mkdir -p build && cd build
cmake .. -DBUILD_PYTHON=ON -DBUILD_EXAMPLES=ON
make -j$(nproc)
sudo make install
```
このソフトウェアには、NMEAセンテンス(時刻と日付情報)をgpsdおよびchronyに転送するGNSSデータブリッジが含まれています。GNSS HATのUSB-CポートをPiのUSB-Aポートに接続して、u-blox NEO-M9Nに直接アクセスすることもできます。
インストールが完了した後、Raspberry PiタイムサーバーをPPSでセットアップするガイドに従いました。
Chrony
Chronyを設定する時期が来たら、/etc/chrony/chrony.conf内で次の設定を使用しました。
```
# GNSS + PPS time server
# GPS time via shared memory from gpsd
refclock SHM 0 offset 0.0 delay 0.05 refid NMEA noselect
# PPS — precise edge timing
refclock PPS /dev/pps0 refid PPS lock NMEA prefer trust poll 3 filter 16
# The Pi's XO is fairly stable, but not quite TCXO-level.
maxclockerror 0.5
# Hardware timestamping for more precision on Pi 5
hwtimestamp *
# Fallback internet pools
pool 0.pool.ntp.org iburst
pool 1.pool.ntp.org iburst
# Allow all LAN clients
allow 10.0.0.0/16
# Allow requests routed through Twingate container.
allow 172.17.0.0/16
maxupdateskew 100.0
makestep 1000 3
rtcsync
# Ignore clock updates >100ms (fixes gpsd reporting time 1s off every ~31 min)
maxchange 0.1 1 -1
```
Twingateを介してNTPデモセットアップにリモートでアクセスしています。テスト中に複数のWANを扱っており、プロキシサービスでダブルNATなどを通過する方が簡単でした。
設定を更新した後、chronyを再起動します。
```
sudo systemctl restart chrony
```
次のコマンドですべてが機能していることを確認します。
```
chronyc sources -v
chronyc tracking
```
数日間chronyメトリクスを測定した後、セットアップに合わせて設定の一部を調整しました。maxclockerrorは、Piの設定のいくつかの調整で発振器の周波数を安定させることができたため、デフォルトから減らしました。
Piの時刻同期の調整
特に役立った変更点:
ファンを一定のデューティサイクルで実行する
PiのSoCをフルスピードで強制的に実行し、ターボをかける
カーネルPPS割り込みをCPUコア4にピン留めする(そのコアを分離した後)
Piの底面を断熱し、発振器をより安定した熱環境にする
Piの残りの部分をTrueTimeエンクロージャーに収めて断熱する
試した他のいくつかのことは、少なくとも6〜12時間のテスト期間では、測定可能な影響はないようでした。
この件に興味がある場合は、Austin's Nerdy Thingsのブログ記事を読むことを強くお勧めします。
安定したPiクロック
Piを2.4GHzに維持して、より安定した熱環境にするために(発振器はSoCの近くにあり、バースト的なCPUアクティビティの影響を大きく受けるため)、force_turboオプションを設定できます。これは連続して約1W多く電力を消費しますが、安定した発振器周波数(タイミングにとって重要)が必要な場合はそれだけの価値があります。
次の行を/boot/firmware/config.txtに追加してPiを再起動します。
```
# Force performance governor so CPU maintains a more stable temperature.
force_turbo=1
```
一貫したファンスピード
PiのSoC温度を安定させるためにNTPheatのようなものをテストするのにかなりの時間を費やしました。それらのツールは、特にPiを断熱した場合に機能します。特にHVACシステムからの空気の流れは、Piの発振器を不安定にします。安定したクロックは、測定可能であるため、一貫したドリフトを好みます。
しかし、多くのテストの結果、Piの底面を断熱し(クリスタルが物理的に存在する場所)、Piの残りの部分をエンクロージャーに入れ、一貫したファン速度と大きなヒートシンクで実行することが、少なくともこれまでの6〜12時間のサイクルでは、より安定した周波数をもたらすことがわかりました。
私が使用している小さなファン制御ユーティリティは、Time Piリポジトリにコミットしました。必要であれば使用できます。75%のデューティサイクルは実際には少しパフォーマンスが良かったですが、テスト中にデスクでそのレベルではファンがうるさすぎたので、50%にしました。
オンボードRTCバッテリー充電
公式のML2020 Raspberry Pi RTCバッテリーがインストールされていると仮定して、オンボードRTCのバッテリー充電回路を設定します。
Pi 5 RTCバッテリーを適切なヘッダーに接続します。
`/boot/firmware/config.txt`に`dtparam=rtc_bbat_vchg=3000000`を追加してPiを再起動します。
(`vcgencmd pmic_read_adc BATT_V`でバッテリー電圧を読み取ることができます)
RTCバッテリーはPiの時刻同期の安定性には役立ちませんが、Piを数日間シャットダウンした場合でも、リアルタイムから1〜2秒以内の精度を保つのに役立ちます(数ヶ月間オフにしない限り)。
単一CPUコアでのPPS割り込みの分離
1つのCPUコアをPPS割り込みの処理専用に割り当てると役立つかどうかを確認したかったのですが、それは役立ちました。真剣なタイミング機器がFPGAで実行される理由(またはタイミング固有のネットワークカードのようにPHCを使用する理由)の1つは、決定論的なPPS処理です。LinuxカーネルのPPS機能を使用する場合、最良の場合でも、割り込みが処理されるのを待つ数百ナノ秒の遅延が発生します。
PPSがチャンスを得られるように、単一の専用CPUコアにPPS処理を割り当てることができます。私の場合は、すべてのPPS処理をCPU3(4番目のコア)に割り当てたいと思いました。
`/boot/firmware/cmdline.txt`を編集し、オプションに`isolcpus=3`を追加します。
再起動します。
```
sudo reboot
```
次の内容で`/usr/local/sbin/pin-pps-irq.sh`を作成します(実行権限を付与します)。
```
#!/bin/sh
irq=$(awk '/pps@/ {sub(":", "", $1); print $1}' /proc/interrupts)
[ -n "$irq" ] && echo 3 > /proc/irq/$irq/smp_affinity_list
```
次の内容で`/etc/systemd/system/pin-pps-irq.service`を作成します。
```
[Unit]
Description=Pin PPS GPIO IRQ to isolated CPU3
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/pin-pps-irq.sh
[Install]
WantedBy=multi-user.target
```
サービスを開始し、起動時に有効にします。
```
systemctl enable --now pin-pps-irq.service
```
次のコマンドで機能していることを確認します。
```
$ watch grep pps /proc/interrupts
```
(1秒ごとに4番目の列が増加しているはずです:`166: 860 0 0 34 pinctrl-rp1 5 Edge pps@0`)
1〜6時間程度chrony統計を監視し、その影響を確認してください。私の場合は、目立ったものではありましたが、ゲームチェンジャーとまではいきませんでした。
監視と物理的な時刻表示
この時点で「TrueTime Pi」と名付けたPiのパフォーマンスを監視するために(シャーシが内部にあることを称えて