NTPコメントを残す使い古されたネタだとは思うが、意外と情報は少なく躓いたところも多かったので記録に残しておきます。「みちびき」3機受信対応を使いました。MT3339が使われているようです。この受信機でGPSのL1電波を受信して、NMEAのフォーマットでシリアル信号にして出してくれます。電池ホルダーとピンヘッダだけはんだ付けしました。ピンヘッダーは5V,GND,RXD,TXD,1PPSの順に並んでいます。Piの適当なGPIOにつなぎます。電池はGPSをコールドスタートさせると時間がかかるので、衛星のデータ(アルマナックとエフェメリス)を保持しておくためのものです。GPIOは2,4,6,8,10番ピンがうまい具合に、5V,GND,UART_TXD0,UART_RXD0,GPIO18と並んでいます。今回のGPSモジュールを順番につなげて、GPIO18を1PPSの入力に使えば、なんの工夫もなくフラットケーブルでちょうど繋げれます。UARTという回路で実装されています。OSでは、シリアルポート(ttyS0)はデフォルトでオフになっていて使えないが内部的にはminiUARTにつながっています。PL011はBluetooth用に使っています。Architectureのことらしい。この実装がPL011ということ。UARTはGPUとコアクロックを共有しています。UARTをシリアルポートに使うとボーレートが変化してしまい、これでは外のデバイスからデータを取得するには不都合があります。PL011はGPUのクロックの影響を受けません。前述のとおり、PL011はBluetoothで使用中のため、次の3つのいずれかの方法を取る必要があります。Bluetoothの運用を止めPL011をシリアルポート用に使う。UARTを使い、PL011をシリアルポート用に使う。UARTのクロックを固定して使う。UARTをシリアルポートとして使うには制限が多いので今後の事を考えて使わないことにします。取れる方法はa)かb)の二択になります。Raspbianでは/dev/serial0はLinuxのコンソールに割り当てらていて、これを別の目的で使うには/dev/serial0とコンソールを切り離さなければなりません。設定コンソールとシリアルの切断Linuxのコンソールがシリアルに割り当てられているので、これを切り離します。(実際にはttyサービスが動いていないので、シリアル経由でログインはできない設定になっている。)切り離す方法として、1)raspi-configコマンドでやる方法と、2)マニュアルで/boot/cmdline.txtを編集する方法法があります。これをやることによって、シリアルでのコンソール接続が不能になりますが、通常はsshなどでログインしていると思うのでなんの問題もないと思います。Options、Serialと進みNoを選択する。2)/boot/cmdline.txtを編集する場合は適当なエディタで開いて、console=serial0,115200を探し出してこれを削除する。他の記述はそのまま残しておく。どちらの方法でも有効化するには再起動が必要となります。次に先に述べたGPSをシリアルにつなぐいずれかの方法を実行します。今回はb)を選びました。Bluetoothを停止する方法/boot/configを変更する必要があります。dtoverlay=pi3-disable-btを追加します。再起動後これによりBluetoothが停止されます。して再割り当てされます。hciuartをします。UARTを使ってBluetoothを動かす方法です。これも/boot/config.txtを編集して、dtoverlay=pi3-miniuart-btを追加します。クロックを固定するためにcore_freq=250の記述も追加しておきます。/dev/ttyAMA0として再割り当てされます。UARTのクロックは自動的に固定化されるため、core_freq=250の記述は必要ありません。b)の操作によってシリアルとBluetoothの関係は以下のようになります。今回のGPSモジュールは上段のserial0につながることになります。bluetoothPPS信号の受信PPS信号の受信は前述したとおりGPIO18(ピン番号12)で入力する。後でわかったことですが、PPSのありなしで、NTPの安定度(offsetやJitter)にほとんど影響はありませんでした。設定は/boot/configにdtoverlay=pps-gpio,gpiopin=18,assert_falling_edge=trueを追加するのと、/etc/modulesにpps-gpioを追加してppsのカーネルモジュールを読み込んでおきます。assert_falling_edge=trueはアクティブLowで、つまりパルスは立ち下がりのときに発信されるので、その設定です。関連ツールのインストールシリアル経由でGPSのNMEAフォーマットもPPSの信号も取り出せるようになったので、このままNTPのソースに使ってもいいのですが、NTP以外でも使えるようにしたり(直接シリアルから読んでしまうとNTPがシリアルを専有してしまい、時刻以外の位置情報などが全く取れなくなってしまう。)、NMEAのフォーマットを読みやすい形に変換してもらうために、gpsd,gpsd-clientsのインストールを行います。gpsdはシリアルに吐き出されるGPSからの信号をtcpの2947番ポートを通して使えるようにしてくれ、また、NTPにおいては127.127.28.uのシェアードメモリ経由で時刻の情報を提供してもらえるようになります。gps-clientsはgpsdで配信してくれる情報をモニターしてくれるgpsmonコマンドなどが提供されます。/dev/pps0"の設定を追加しました。GPSD_OPTIONS="-n"としてシェアードメモリを介してNTPを同期させるための設定を入れておきます(参考)。gpsdなどで自動起動の設定をしておきます。-pなどで見てもいつまで経ってもGPSがdelay,offset,jitterが0.000のままで同期しません。gpsmonなどで確認するとgpsdが動いてしまうので、問題ないように見えてしまう。-mコマンドで見ることができます。10x4e545030から始まるメモリーがgpsdのシェアードメモリで、最後の一桁がユニット番号(u)で、ここでは7まで見えています。0,1はownerがrootでpermsが600なので、root権限がないと読めません。今回はユニット2が使えそうなのでこれを使うことになります。NTPの設定とインストールパッケージのNTPをインストールします。設定は/etc/ntp.confですが、追加で記述したのは以下になります。PPS1行目と2行目がGPSの設定です。gpsdのシェアードメモリから読む設定で、ユニット番号は2です。このとき参照するアドレスが127.127.28.2になります。ntpのドキュメントが参考になります。gpsdは127.127.46.0でも時刻情報を出しているようですが、こちらは試していません。minpollとmaxpollの値はgpsdの推奨のままです。この値だと2^4で16秒間隔で読みに行きます。preferは必須のようです。fudgeのtime1は手動でoffsetを設定するときの設定ですが、今回は0です。3行目と4行目がPPSの設定です。/dev/pps0で読めるデータですが、ntpでは127.127.22.0がそれに当たるようです。gpsdでもserverのモードを指定すれば読めるようですが、今回は直接127.127.22.0で読みました。あと、他のNTPの設定でもやるアクセスコントロールやインターネットのサーバ指定などはお好きにどうぞです。起動させたあとしばらくするとGPSが衛星を補足して、reachが377になる頃(3分ほど)経つと、GPSで時刻同期が実現します。-pコマンド確認します。2.2751行目のSHMがGPSの状態です。先頭に*がついているので、同期サーバになっています。2行目のPPSの先頭にoがついているので、参照されていることがわかります。rvコマンドでも状態がわかります。leapsec=201701010000,expire=2019122800001行目でsync_ppsとなっているので、PPSで同期していることがわかります。インターネット経由のNTPだとここがsync_ntpとなります。second)の精度が出えているようです。インターネット経由はNICTのサーバを使用していますが、だいたい3桁のオーダで正確なようです。参照してきたときの、DelayとOffsetとJitterのグラフ。前後は、0のように見えますが、GPSを参照していたときのグラフで、数μsecです。ほとんど0に見えます。Photoshopで「仮想タイルはこれ以上割り当てられません。Photoshopで「仮想タイルはこれ以上割り当てられません。