今回は、Rock Pi SにGPSモジュールを接続し、NTPd(またはNTPsec)ではなくChronyを使ってPPS付きのNTPサーバを作成します。最近のLinuxディストリビューションではChronyが標準搭載されることが増えており、ChronyはNTPd(やNTPsec)よりも積極的に補正を行い、精度が高いとされています。以前はNTPd(やNTPsec)の統計ログとChronyの形式が異なり不便なため、「がとらぼ」の人はChronyを避けていましたが、今回はLAN用のNTPサーバで統計ログを分析する予定はないのでChronyを選ぶことにしました。
Chronyについては過去に3回ほど取り上げており、今回も基本的には同じ手順です。- 新しい中華GPSモジュールとChronyで作るNTPサーバ (前編)
- 新しい中華GPSモジュールとChronyで作るNTPサーバ (中編)
- 新しい中華GPSモジュールとChronyで作るNTPサーバ (後編)

今回のアンテナは、自動車用のGPSアンテナよりも一回り大きい、比較的背の低いモデルです。

アンテナの下部にはゴムカバーがありますが、このカバーは水が溜まりやすいため、使用しない方が良いでしょう。白い円盤は両面テープの保護シートです。黒いカバーを貼り付けることもできますが、10mm以上の穴があるプレートに固定することも可能です。さらに、内径10mmのパイプにねじ込んで固定することもできます。ただし、ケーブル穴の防水状態が不明なため、ゴム系接着剤を穴に流し込み固まった後にアンテナを設置するのが安全です。

購入したGPSチップは左側の「ATGM332D」と書かれたものです。右側は「u-blox NEO-M8N」とされていますが、左側のGPSとほぼ同じ価格の1000円前後の安価な製品であるため、本物ではない可能性が高いです。シールも汚れており、信頼性に疑問があります。モジュールの基板自体は似ていますが、搭載されている部品は微妙に異なります。
右側の「NEO-M8N」と表示されたチップは、出力されるNMEAメッセージに異常があり、u-blox GPSチップ用のコマンドをシリアル通信で送信しても機能しません。もし本当にu-bloxチップであれば、u-blox用のPCアプリなどで制御できる可能性がありますが、まだ試していません。
Rock Pi SとGPSモジュールの接続

Rock Pi SとGPSモジュールはGPIOピンを利用して接続します。
- ピン番号17: GPSモジュールVCCに接続します
- ピン番号20: GPSモジュールGNDに接続します
- ピン番号23: GPSモジュールTX(送信)に接続します (RXとTXを接続)
- ピン番号24: GPSモジュールRX(受信)に接続します (RXとTXを接続)
- ピン番号13: GPSモジュールPPSに接続します
一般的なシングルボードコンピュータでは、右上のUART(このボードではUART0)を使用してシリアル通信を行います。しかし、Rock Pi SのUART0はデバッグ専用UARTであり、このピンにGPSモジュールなどを接続するとOSが起動しません。OSが起動した後にUART0に接続すれば通常のUARTとして使用できますが、これは不便ですし、瞬間的な停電などで再起動がかかると、OSが起動できずにダウンタイムが長引くことになります。そのため、素直にUART1(右下)などを使用するのが良いでしょう。
ArmbianのOSイメージ
8月中旬に最新のArmbianソースを使って、Rock Pi S用のDebian Bookworm OSイメージをビルドしました。PPSやタイマー周りは、これまで通りNTPサーバ向けの設定でビルドしています。OSイメージは以下で共有します。
置き場所(Google Drive):
Armbian-unofficial_24.8.0-trunk_Rockpi-s_bookworm_current_6.6.46.zip
PPSデバイスの有効化
Armbianでは、デバイスツリーによるデバイス周りの設定の追加や変更が比較的簡単に行えます。今回は、デバイスツリーソースでRock Pi SのGPIO0_C0 GPIO13番ピンをGPIO-PPSとして利用する設定を作成しました。
# vim ~/pps-overlay.dts (新規作成)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /dts-v1/; /plugin/; / { compatible = "rockchip,rk3308"; fragment@0 { target-path = "/"; __overlay__ { pps: pps@0 { compatible = "pps-gpio"; gpios = <&gpio0 16 0>; assert_falling_edge; }; }; }; }; |
重要なのは11行目です。今回はピン番号13を使用しますが、これはGPIO0のGPIO番号16番に対応しているため、このように記述します。もしピン番号15を使用する場合は、GPIO0のGPIO番号17番に対応するので、&gpio0 17 0のように記述します。対応表がないと理解しづらい部分です。
最近のArmbianには、デバイスツリーのソースを変換・配置・設定を自動で行うツールが含まれています。
# armbian-add-overlay ~/pps-overlay.dts
これにより、変換されたpps-overlay.dtboファイルがboot/overlay-userディレクトリに配置され、/boot/armbianEnv.txtに次の1行が追加されます。
user_overlays=pps-overlay
システムを再起動することでGPIO13番ピンに紐付いた/dev/pps0が生成されます。
# dmesg | grep pps [ 0.254397] pps_core: LinuxPPS API ver. 1 registered [ 0.254406] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it> [ 9.320594] pps pps0: new PPS source pps@0.-1 [ 9.320742] pps pps0: Registered IRQ 44 as PPS source [ 23.940029] pps_ldisc: PPS line discipline registered # lsmod Module Size Used by pps_ldisc 16384 2 sunrpc 483328 1 8723ds 1327104 0 cfg80211 802816 1 8723ds hci_uart 135168 0 btqca 20480 1 hci_uart btrtl 28672 1 hci_uart btintel 40960 1 hci_uart btbcm 20480 1 hci_uart pps_gpio 12288 1 bluetooth 663552 6 btrtl,btqca,btintel,hci_uart,btbcm rfkill 24576 4 bluetooth,cfg80211 rockchip_rng 16384 0 rng_core 16384 1 rockchip_rng cpufreq_dt 16384 0 lz4hc 12288 0 lz4 12288 0 zram 32768 3 binfmt_misc 20480 1 dm_mod 126976 0 ip_tables 28672 0 x_tables 36864 1 ip_tables autofs4 40960 2 realtek 32768 1 dwmac_rk 28672 0 stmmac_platform 20480 1 dwmac_rk stmmac 233472 3 stmmac_platform,dwmac_rk pcs_xpcs 20480 1 stmmac
lsmod コマンドを使って、pps_gpio モジュールが表示されることを確認します。なお、上記の lsmod の結果は、NTPサーバーの動作に不要なカーネルモジュールを /etc/modprobe.d/blacklist-rockpi-s.conf でブラックリストに登録済みの状態です。ブラックリストに登録していない場合は、表示されるモジュールがこれよりも多くなります。
# apt install pps-tools # ppstest /dev/pps0 trying PPS source "/dev/pps0" found PPS source "/dev/pps0" ok, found 1 source(s), now start fetching data... source 0 - assert 1724375360.627367312, sequence: 120015 - clear 0.000000000, sequence: 0 source 0 - assert 1724375361.710659761, sequence: 120016 - clear 0.000000000, sequence: 0 source 0 - assert 1724375362.794035625, sequence: 120017 - clear 0.000000000, sequence: 0 source 0 - assert 1724375363.877368518, sequence: 120018 - clear 0.000000000, sequence: 0
次に、pps-tools をインストールし、/dev/pps0 をデバイスとして指定してテストを実行します。1秒ごとに1行ずつ表示され、問題がないことを確認したら、[Ctrl]+[C] で終了します。
シリアルポートUART1の有効化と設定
Rock Pi Sでは、UART0がデバッグUARTとして設定されており、UART0にGPSモジュールなどを接続した状態で電源を入れるかシステムを再起動すると、OSが起動しないことがあります。Armbianでは、UART0が ttyS0 として有効化されているのですが、このポートを使用するとOSが起動しないため、UART1(それ以降)をGPSモジュールとの通信用に使用するのが良いでしょう。今回はUART1を使用することにしますが、Rock Pi S用Armbian BookWormではUART1(ttyS1)が無効になっているため、これを有効化する必要があります。(次)
# vim ~/uart1-overlay.dts (新規作成)1 2 3 4 5 6 7 8 9 10 | /dts-v1/; / { compatible = "rockchip,rk3308-uart\0snps,dw-apb-uart"; fragment@0 { target-path = "/serial@ff0b0000"; __overlay__ { status = "okay"; }; }; }; |
# armbian-add-overlay ~/uart1-overlay.dts
これにより、変換されたuart1-overlay.dtboファイルがboot/overlay-userディレクトリ下に配置され、/boot/armbianEnv.txtのuser_overlays行が次のようになります。
user_overlays=pps-overlay uart1-overlay
システムを再起動することでUART1の/dev/ttyS1が有効化されます。
# stty -F /dev/ttyS1 9600 ←RockPi Sのシリアル速度をGPSモジュールのシリアル速度に合わせる # cat /dev/ttyS1
NMEAメッセージが表示され続けることを確認できれば成功です。[Ctrl]+[C]で終了します。
/dev/pps0と/dev/ttyS1を後述のgpsdとchronyが利用できるようにします。
# vim /etc/udev/rules.d/10-gps.rules (新規ファイル作成)1 2 | KERNEL=="ttyS1",MODE="0666" KERNEL=="pps0",MODE="0666" |
手動で即時有効にするのは
# chmod 0666 /dev/ttyS1 # chmod 0666 /dev/pps0
シリアルポートのgettyを停止・無効化します。
# systemctl stop serial-getty@ttyS0.service # systemctl disable serial-getty@ttyS0.service # systemctl stop serial-getty@ttyS1.service # systemctl disable serial-getty@ttyS1.service # systemctl stop serial-getty@ttyS2.service # systemctl disable serial-getty@ttyS2.service # systemctl stop serial-getty@ttyS3.service # systemctl disable serial-getty@ttyS3.service # systemctl stop serial-getty@ttyS4.service # systemctl disable serial-getty@ttyS4.service # systemctl stop serial-getty@ttyS5.service # systemctl disable serial-getty@ttyS5.service # systemctl stop serial-getty@ttyS6.service # systemctl disable serial-getty@ttyS6.service # systemctl stop serial-getty@ttyS7.service # systemctl disable serial-getty@ttyS7.service実行は、GPSモジュールと通信するttyS1だけでも良いかもしれません。
gpsdのインストールと設定
chrony はGPSモジュールから送信されるNMEAメッセージを直接読み取ることができないため、gpsd を使って受信し、メモリ共有で chrony に日時を渡すようにします。そのために、gpsd と gpsd-clients をインストールします。
# apt update # apt install gpsd gpsd-clientsgpsdの設定ファイルは/etc/default/gpsdです。
1 2 3 4 | START_DAEMON="true" USBAUTO="false" DEVICES="/dev/ttyS1" GPSD_OPTIONS="-n -s 9600" |
$ sudo systemctl restart gpsd.socket
gpsdが正常に動作し、GPSモジュールから衛星データを受信しているか確認するには、 gpsmon や cgps -s コマンドを実行します。表示される日時や座標が正しければ、正常に動作しています。
chronyの設定
最近のLinuxでは、NTPの標準としてChronyが採用されることが増えています。Chronyの設定ファイルは通常 /etc/chrony/chrony.conf にあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # NTP Servers (mfeed) server ntp1.jst.mfeed.ad.jp server ntp2.jst.mfeed.ad.jp server ntp3.jst.mfeed.ad.jp server ntp1.v6.mfeed.ad.jp server ntp2.v6.mfeed.ad.jp server ntp3.v6.mfeed.ad.jp # Access loopback address allow 127.0.0.1 allow ::1 # Allow access from your IPv4,IPv6 networks allow 192.168.0.0/24 allow 2001:xxxx:xxxx:xxxx::/64 # Allow mfeed servers but restrict their actions allow 210.173.160.27 allow 210.173.160.57 allow 210.173.160.87 allow 2001:3a0:0:2001::27:123 allow 2001:3a0:0:2005::57:123 allow 2001:3a0:0:2006::87:123 # NMEA GPS refclock SHM 0 refid NMEA # PPS (Pulse Per Second) refclock PPS /dev/pps0 refid PPS lock NMEA |
$ sudo systemctl restart chrony
PPSを使う場合は、最初の時刻合わせに時間がかかるためchrony 起動後しばらく待ちます。
$ chronyc sources
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#x NMEA 0 4 377 22 +413ms[ +413ms] +/- 2700us
#* PPS 0 4 370 72 +9308ns[ +13us] +/- 3294ns
^- ntp1.jst.mfeed.ad.jp 2 10 377 115 -1347us[-1332us] +/- 61ms
^- ntp2.jst.mfeed.ad.jp 2 10 377 788 -193us[ -246us] +/- 52ms
^- ntp3.jst.mfeed.ad.jp 2 10 377 53 -385us[ -385us] +/- 61ms
^- ntp1.v6.mfeed.ad.jp 2 10 377 498 -1075us[-1068us] +/- 55ms
^- ntp2.v6.mfeed.ad.jp 2 10 377 655 -1998us[-2029us] +/- 54ms
^- ntp3.v6.mfeed.ad.jp 2 10 377 785 -1297us[-1352us] +/- 75ms
$ chronyc tracking
Reference ID : 50505300 (PPS)
Stratum : 1
Ref time (UTC) : Fri Aug 23 14:09:03 2024
System time : 38248.757812500 seconds slow of NTP time
Last offset : +0.000002095 seconds
RMS offset : 0.000305083 seconds
Frequency : 26.998 ppm fast
Residual freq : +0.008 ppm
Skew : 0.082 ppm
Root delay : 0.000000001 seconds
Root dispersion : 0.000023679 seconds
Update interval : 16.0 seconds
Leap status : Normal
このような表示になります。
GPSから時刻を取得しているため、最上位のStratum 1として表示されます。Stratumの数字が大きくなるほど、大本の時刻ソースからの間にホストが増えることを示します。これは、伝言ゲームのように、間に入る人が増えるほど伝言が不正確になるのと似ています。
PPS (パルスパーセカンド)での秒合わせにより、誤差はナノ秒単位に迫ります。
時刻の正確さが求められる環境では、GPSのPPS信号を利用して時刻合わせを行うNTPサーバがLAN内に1台は必須です。NTPサーバは、ネットワーク内の全てのデバイスが同じ正確な時刻を持つようにするための重要な役割を果たします。GPSのPPS信号は、高精度な時刻合わせを可能にし、ネットワーク全体の時刻のずれを最小限に抑えることができます。この記事のようにシングルボードコンピュータを使用すれば、GPSモジュールとPPS機能を搭載したNTPサーバのセットが、6〜7千円程度で手に入ります。この価格で一式を揃えることができるため、コストパフォーマンスに優れており、多くの企業や技術者にとって非常におすすめです。高精度な時刻同期が求められるシステムには、このようなNTPサーバの導入を検討してみる価値があります。
関連記事:- Rock Pi SとChronyでPPS付きNTPサーバを作る ←いまここ
- NanoPi NEO3にGPSモジュールを接続してNTPサーバとして使用する
- 新しい中華GPSモジュールとChronyで作るNTPサーバ (後編)
- 新しい中華GPSモジュールとChronyで作るNTPサーバ (中編)
- 新しい中華GPSモジュールとChronyで作るNTPサーバ (前編)
- NanoPi NEOでNTPサーバ再構築 (全まとめ)
- NanoPi NEOとGPSモジュールでNTPサーバ PPS検証編
- NanoPi NEOとGPSモジュールでNTPサーバ PPS解決編
- NanoPi NEOの時刻のズレを直したい
- NanoPi NEOとGPSモジュールでNTPサーバ 高精度PPS編
- NanoPi NEOとGPSモジュールでNTPサーバ 簡易PPS編
- NanoPi NEOにGPSモジュールを繋いでNTPサーバ
- GPSモジュール
- GPSレシーバーでStratum 1なNTPサーバ


