RaspberryPi に GPSレシーバー と RTC をつけて GPS 1PPS 対応 NTPサーバ にする

何番煎じネタかというぐらい、RaspberryPiにGPSレシーバをつけてNTPdにするというネタではありますが、今回はRTCも（そこまで意味はないけど）つけてしまおうという話です。
別にGPSが受信できてればRTCは必要ないですが、たまたま停電とかで再起動直後とかビルの法定点検で1日停電とかの後を想定しつつ、気持ちRTC積んどくかぐらいのお話です。
正直RTCはおまけです。
なので、RTC部分を読み飛ばしてGPSレシーバでのNTPサーバ構築として読んでも大丈夫です。



# 1.用意するもの
- RaspberyPi (なんでもよし。今回は余っていたRaspberryPi 4B）
- 秋月の　ＧＮＳＳ（ＧＰＳ・ＧＬＯＮＡＳＳ・ＱＺＳＳ）受信機キット　１ＰＰＳ出力　みちびき３機対応　アンテナセット付キット　[AE-GNSS-EXTANT+ANT_SET]
    - https://akizukidenshi.com/catalog/g/gK-13850/
- DS3231 AT24C32 高精度時計モジュール
    - https://amzn.to/3CYF9r5
- コネクタ付ケーブル　２０ｃｍ　４０Ｐ　メスメス
    - https://akizukidenshi.com/catalog/g/gC-15868/


GPSモジュールが入手不可の場合、秋月で販売してる下記のものが代替できます。
- ＧＰＳ受信機キット　１ＰＰＳ出力付き　「みちびき」２機受信対応　[AE-GYSFDMAXB]
    - https://akizukidenshi.com/catalog/g/gK-09991/
こちらでも代替可能ですが、GPSアンテナが内臓のため、ラズパイの設置場所を窓際などにする必要があります。
また、GPS側の基盤パターンがRXDとTXDが本説明で使ってるAE-GNSS-EXTANTと逆になるため、注意が必要です。（むしろ2ピンから12ピンまで入れ子にせずストレート配線できるのでわかりやすい。）

- ＧＰＳ／ＧＬＯＮＡＳＳ受信機（Ｇａｌｉｌｅｏ／ＢｅｉＤｏｕ可）ｕ‐ｂｌｏｘ　Ｍ８搭載　みちびき３機受信対応 [GT-902PMGG]
    -  https://akizukidenshi.com/catalog/g/gM-12905/
こちらの場合、GPSアンテナが外付けですので非常におすすめです。
配線が剥き出しのため、ピンヘッダに刺すために
    - ケーブル用コネクタ　（１０個入） https://akizukidenshi.com/catalog/g/gC-12160/
    - コネクタ用ハウジング　５Ｐ https://akizukidenshi.com/catalog/g/gC-12154/
あたりも入手しておくと良いです。
さらに、このユニットの1PPS信号はアクティブHighなので、本説明での設定を行う際に注意が必要です。
(pps設定時のdtoverlay=pps-gpio,gpiopin=18 のみになり assert_falling_edge=true は不要です。)


# 2.GPS受信キットの配線

```
pi@gps:~ $ pinout
Description        : Raspberry Pi 4B rev 1.5
Revision           : b03115
SoC                : BCM2711
RAM                : 2GB
Storage            : MicroSD
USB ports          : 4 (of which 2 USB3)
Ethernet ports     : 1 (1000Mbps max. speed)
Wi-fi              : True
Bluetooth          : True
Camera ports (CSI) : 1
Display ports (DSI): 1

,--------------------------------.
| oooooooooooooooooooo J8   +======
| 1ooooooooooooooooooo  J14 |   Net
|  Wi                    12 +======
|  Fi  Pi Model 4B  V1.5 oo      |
| |D     ,---. +---+          +====
| |S     |SoC| |RAM|          |USB3
| |I     `---' +---+          +====
| |0                C|           |
| oo1 J2            S|        +====
|                   I| |A|    |USB2
| pwr   |hd|   |hd| 0| |u|    +====
`-| |---|m0|---|m1|----|x|-------'

J8:
   3V3  (1) (2)  5V    
 GPIO2  (3) (4)  5V    
 GPIO3  (5) (6)  GND   
 GPIO4  (7) (8)  GPIO14
   GND  (9) (10) GPIO15
GPIO17 (11) (12) GPIO18
GPIO27 (13) (14) GND   
GPIO22 (15) (16) GPIO23
   3V3 (17) (18) GPIO24
GPIO10 (19) (20) GND   
 GPIO9 (21) (22) GPIO25
GPIO11 (23) (24) GPIO8 
   GND (25) (26) GPIO7 
 GPIO0 (27) (28) GPIO1 
 GPIO5 (29) (30) GND   
 GPIO6 (31) (32) GPIO12
GPIO13 (33) (34) GND   
GPIO19 (35) (36) GPIO16
GPIO26 (37) (38) GPIO20
   GND (39) (40) GPIO21

J2:
GLOBAL ENABLE (1)
          GND (2)
          RUN (3)

J14:
TR01 TAP (1) (2) TR00 TAP
TR03 TAP (3) (4) TR02 TAP

For further information, please refer to https://pinout.xyz/
pi@gps:~ $ 

```

pinoutコマンドを叩くとピン配列が出てきます。
秋月のAE-GNSS-EXTANTには
動作用の
- VDD5V
- GND

通信用の
- UART TXD
- UART RXD

1PPS信号(3.3V 100ms アクティブLow)の
- 1PPS

というピンが出ていますので、ラズパイの対応するピンと配線する必要があります。

ラズパイでUARTが使えるのは
GPIO14,GPIO15となっている8番(UART TX)、10番(UART RX)
この辺りで電源として使える 5vPowerの4番、Groundの6番
ちょうど1直線に配線できそうなので、PPSはGPIO18の12番ピンに入れると良いでしょう。

なので
- VDD5Vを4番ピン
- GNDを6番ピン
- TXDを10番ピン
- RXDを8番ピン
- 1PPSを12番ピン

に配線します。

![GPS配線.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54205/5de7ef7b-7984-f01e-6e59-caf2391275ca.png)

# 3.Raspberry Pi OSインストール
今回は Raspberry Pi OS Lite 32-bitで用意
（執筆時点では）
https://www.raspberrypi.com/software/
Raspberry Pi Imagerを使ってサクッと作ります。

![スクリーンショット 2022-09-15 22.01.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54205/0f74c37b-b1e8-d17a-40bc-7610698bd265.png)


イメージを燒く際に、詳細な設定からSSHを有効にしたりしていると、初手よりSSH接続できるようになるので良いかと。
パスワードやロケールも変えておくと良いです。
![スクリーンショット 2022-09-15 22.01.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54205/2e564d0c-5505-d182-a418-927179b05f67.png)
![スクリーンショット 2022-09-15 22.01.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54205/7adc9708-5036-fc38-7e74-ca747ed8385e.png)
![スクリーンショット 2022-09-15 22.01.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54205/38b3fdaa-365d-d129-0390-7b0a50203f08.png)


# 4.Raspberry Pi OSでGPSを使うためのの設定変更
執筆時点でのリリースバージョンである bookworm ベースで記載する

```
pi@gps:~ $ lsb_release -a
No LSB modules are available.
Distributor ID:	Debian
Description:	Debian GNU/Linux 12 (bookworm)
Release:	12
Codename:	bookworm
pi@gps:~ $ 
pi@gps:~ $ uname -a
Linux gps 6.6.47+rpt-rpi-v8 #1 SMP PREEMPT Debian 1:6.6.47-1+rpt1 (2024-09-02) aarch64 GNU/Linux
pi@gps:~ $ 
```

また、タイムゾーンは Asia/Tikyoにセットしてある

```
sudo timedatectl set-timezone Asia/Tokyo
```

## 4.1.UART有効にする
ラズパイのドキュメントにUARTの有効方法が書かれている

https://www.raspberrypi.com/documentation/computers/config_txt.html#enable_uart

/boot/firmware/config.txt に `enable_uart=1`を追記する

https://www.raspberrypi.com/documentation/computers/config_txt.html#init_uart_baud

これを読む限り、UARTはデフォルトで115200bpsで通信するようになっているようだ。
AE-GNSS-EXTANTはデフォルト9600bpsなので9600bpsになるよう

/boot/firmware/config.txt に `init_uart_baud=9600`を追記する

ここまでの２つを実行し、 /boot/firmware/config.txt に追記を行う
```
echo enable_uart=1 | sudo tee -a /boot/firmware/config.txt
echo init_uart_baud=9600 | sudo tee -a /boot/firmware/config.txt
```

### 4.1.ex Bluetooth内蔵RaspberryPiの場合 (非搭載の場合は読み飛ばしてOK)
RaspberryPiには、PL011とminiUARTという２つの回路が存在します。
https://www.raspberrypi.com/documentation/computers/configuration.html#configuring-uarts

Bluetoothを内蔵していないRaspberryPiの場合UART0がPL011に接続されており、miniUARTは無効になっています。
Bluetoothを内蔵しているRaspberryPi 3や ZeroWなどの場合PL011がBluetoothに接続されており、そのまま
/boot/firmware/config.txt に `enable_uart=1`を追記した場合、miniUART側にGPIOのUARTが接続されます。
このminiUARTというのはminiとついているように、機能が限定されています。
一番問題なのはGPUのクロックに依存してしまうため、ボーレートが変化する可能性が出るのですが、それを回避するためにGPUのコアクロックが250MHzへ固定し、性能を落として利用する必要があります。
https://datasheets.raspberrypi.com/bcm2835/bcm2835-peripherals.pdf

そのため、GPSモジュールを繋ぐ際は下記のいずれかの方法が必要になります。
A. Bluetoothを無効にする(無効化することで、PL011がUART0になる)
B. BluetoothをminiUART接続に変えてUART0にPL011を使う

#### 4.1.ex A. Bluetoothを無効にする
/boot/firmware/config.txt に `dtoverlay=disable-bt`を追記することでBluetoothを無効にします。

```
echo dtoverlay=disable-bt | sudo tee -a /boot/firmware/config.txt
```

#### 4.1.ex B. BluetoothをminiUART接続に変えてUART0にPL011を使う
/boot/firmware/config.txt に `dtoverlay=miniuart-bt`を追記することでBluetoothをminiUART接続に変えてUART0にPL011を使うようになります。
また、/boot/firmware/config.txt に `core_freq=250`を追記し、miniUARTのクロックが変動しないようにします。

```
echo dtoverlay=miniuart-bt | sudo tee -a /boot/firmware/config.txt
echo core_freq=250 | sudo tee -a /boot/firmware/config.txt
```

## 4.2.シリアルコンソールを無効にする
Raspberry Pi OSではデフォルトでシリアルコンソールが有効になっています。
そのため、せっかくUARTを有効にしてもシリアルコンソールの出力先として使われてしまいます。

/boot/cmdline.txt　の `console=serial0,115200`を削除し、シリアルコンソールを無効化します。

また `serial-getty@ttyS0.service` も停止、無効化する必要があります。

```
sudo sed -i 's/console=serial0,115200 //g' /boot/firmware/cmdline.txt
sudo systemctl stop serial-getty@ttyS0.service
sudo systemctl disable serial-getty@ttyS0.service
```

## 4.3.PPSを有効にする
GPIO18（ピン番号12番）にPPSを配線しましたが、設定を入れなければ有効になりません。
Linux　Kernelにある PPS Signal on GPIO を有効にします。

/etc/modules に `pps-gpio` を追加し、
/boot/firmware/config.txt に `dtoverlay=pps-gpio,gpiopin=18` を追加します。


GPSモジュールのPPSシグナルがアクティブLowな場合 `assert_falling_edge=true`が必要です。
そのため
`echo dtoverlay=pps-gpio,gpiopin=18,assert_falling_edge=true | sudo tee -a /boot/firmware/config.txt`
と置き換えてください



ここまで設定できたら一度リブートします。

```
echo pps-gpio | sudo tee -a /etc/modules
echo dtoverlay=pps-gpio,gpiopin=18 | sudo tee -a /boot/firmware/config.txt
sudo shutdown -r now
```

# 5.gpsdのインストールと設定
## 5.1.必要パッケージのインストール
上記まででGPSを利用するためのOS側設定が終わっているので、gpsdをインストールし設定します。

必要なパッケージ `gpsd` `gpsd-tools` `pps-tools` をaptで入れましょう

```
sudo apt update && sudo apt -y install gpsd gpsd-tools pps-tools
```

## 5.2.gpsmonを使ってGPS受信確認
`gpsmon` を使い、GPS信号の受信ができるかを確認します。
その前に　`ls /dev/ttyAMA0` でデバイスが認識しているかを確認します。

```
ls /dev/ttyAMA0
```

実行例
```
pi@raspberrypi:~ $ ls /dev/ttyAMA0 
/dev/ttyAMA0
pi@raspberrypi:~ $ 
```

ここで `ls: cannot access '/dev/ttyAMA0': No such file or directory` となった場合はOSでの設定ができていないので、　`4.1.UART有効にする` から設定を確認しましょう。

問題なければ `gpsmon -n /dev/ttyAMA0`を実行します。

```
sudo gpsmon -n /dev/ttyAMA0
```

実行例
```
raspberrypi:/dev/ttyAMA0 9600 NMEA0183>
┌──────────────────────────────────────────────────────────────────────────────┐
│Time: 2022-09-19T17:45:43.000Z   Lat: xx xx.xxxxxx' N   Lon: xxx xx.xxxxxx' E │
└───────────────────────────────── Cooked TPV ─────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│ GLGSV GNRMC GPVTG GPZDA GPGGA GNGLL GNGSA GPGSV                              │
└───────────────────────────────── Sentences ──────────────────────────────────┘
┌───────────────────────┌─────────────────────────┌────────────────────────────┐
│ SVID  PRN  Az El SN HU│Time:     174543.000     │Time:      174544.000       │
│GP  1    1 209 35 19  Y│Latitude:    xxxx.xxxx N │Latitude:  xxxx.xxxx        │
│GP  8    8  13 73 26  Y│Longitude:  xxxxx.xxxx E │Longitude: xxxxx.xxxx       │
│GP 14   14 308  9 17  Y│Speed:    0.21           │Altitude:  xx.x             │
│GP 16   16 126 25 18  Y│Course:   124.33         │Quality:   1   Sats: 10     │
│GP 21   21 202 66 23  Y│Status:   A        FAA:A │HDOP:      x.xx             │
│GP 23   23  38 11 28  Y│MagVar:                  │Geoid:     xx.x             │
│GP 27   27  67 42 36  Y└───────── RMC ───────────└─────────── GGA ────────────┘
│GP 30   30 301 28 18  Y┌─────────────────────────┌────────────────────────────┐
│GL 12   76 168 51 24  Y│Mode: A3 Sats: 1 8 14 +  │UTC:           RMS:         │
│GL 14   78 328 14 22  Y│DOP H=0.85 V=0.81 P=1.17 │MAJ:           MIN:         │
│GP  7    7 264 41  0  N│TOFF:  0.327112748       │ORI:           LAT:         │
│GP 10   10  66 25 11  N│PPS: N/A                 │LON:           ALT:         │
└───v──── GSV ──────────└────── GSA + PPS ────────└─────────── GST ────────────┘

```
実際には LatやLonには自分の場所の緯度経度が表示されます。
表示がない場合、TXやRXが逆転している可能性がありますので、配線などを確認しましょう。

現時点で `PPS: N/A` は正常です。
 
`quit` と入力しエンターで閉じるか、 `Ctrl+c` で閉じることができます。

## 5.3.ppstestを使ってPPS受信確認
`ppstest` を使い、PPS信号の受信ができるかを確認します。
その前に　`ls /dev/pps0` でデバイスが認識しているかを確認します。

```
ls /dev/pps0
```

実行例
```
pi@raspberrypi:~ $ ls /dev/pps0
/dev/pps0
pi@raspberrypi:~ $ 
```

ここで `ls: cannot access '/dev/pps0': No such file or directory` となった場合はOSでの設定ができていないので、　`4.3.PPSを有効にする` から設定を確認しましょう。

問題なければ `ppstest /dev/pps0`を実行します。

```
sudo 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 1663610127.994295210, sequence: 4636 - clear  0.000000000, sequence: 0
source 0 - assert 1663610128.994297397, sequence: 4637 - clear  0.000000000, sequence: 0
source 0 - assert 1663610129.994291099, sequence: 4638 - clear  0.000000000, sequence: 0
source 0 - assert 1663610130.994289180, sequence: 4639 - clear  0.000000000, sequence: 0
source 0 - assert 1663610131.994286639, sequence: 4640 - clear  0.000000000, sequence: 0
```
上記のように `source 0 - assert 1663610127.994295210, sequence: 4636 - clear  0.000000000, sequence: 0` と一定間隔で出てこれば問題ないです。

表示されない場合、`sudo`つけて実行しているかや、配線確認をしてみてください。

## 5.4 gpsdの設定
ここまで問題なければ、gpsdの設定を行います。
設定ファイルは　　`/etc/default/gpsd`にありますので、これを書き換えます。
`DEVICES=""` には　`/dev/ttyAMA0` と `/dev/pps0`を
`GPSD_OPTIONS=""`　には　`-n`を入れてクライアントからのアクセスがなくても更新するようにします。
https://gpsd.gitlab.io/gpsd/gpsd-time-service-howto.html

また、設定後にgpsdを再起動します。

```
sudo sed -i 's@DEVICES=""@DEVICES="/dev/ttyAMA0 /dev/pps0"@g' /etc/default/gpsd
sudo sed -i 's@GPSD_OPTIONS=""@GPSD_OPTIONS="-n"@g' /etc/default/gpsd
sudo systemctl restart gpsd.service
sudo systemctl restart gpsd.socket 
```

ここまで設定完了したら、再度gpsmonを起動して動作確認をします。
設定ファイルで`/dev/ttyAMA0` `/dev/pps0` を指定しているため、 `gpsmon`を叩くだけでステータス表示がされます。

```
gpsmon -n
```

実行例
```
pi@raspberrypi:~ $ gpsmon -n
tcp://localhost:2947          NMEA0183>
┌──────────────────────────────────────────────────────────────────────────────┐or":14}
│Time: 2022-09-19T18:48:14.000Z   Lat: xx xx.xxxxxx' N   Lon: xxx xx.xxxxxx' E │ver":"MTK-3301","subtype":"AXN_5.1.2_3333_17113000-0013","activated":"2022-09-19T18:48:0
└───────────────────────────────── Cooked TPV ─────────────────────────────────┘mincycle":0.10},{"class":"DEVICE","path":"/dev/pps0","driver":"PPS","activated":"2022-09
┌──────────────────────────────────────────────────────────────────────────────┐
│ GLGSV GNRMC GPZDA GPGRS GPGST GPGGA GNGSA GPGSV                              │false,"timing":false,"split24":false,"pps":true}
└───────────────────────────────── Sentences ──────────────────────────────────┘
┌───────────────────────┌─────────────────────────┌────────────────────────────┐
│ SVID  PRN  Az El SN HU│Time:     184814.000     │Time:      184815.000       │
│GP  1    1 228 65 30  Y│Latitude:    xxxx.xxxx N │Latitude:  xxxx.xxxx        │
│GP  8    8  72 57 23  Y│Longitude:  xxxxx.xxxx E │Longitude: xxxxx.xxxx       │
│GP 10   10  40 16 18  Y│Speed:    0.56           │Altitude:  xx.x             │
│GP 14   14 310 33 18  Y│Course:   338.30         │Quality:   1   Sats:  8     │
│GP 21   21  44 83 20  Y│Status:   A        FAA:A │HDOP:      x.xx             │
│GP 27   27  88 21 19  Y│MagVar:                  │Geoid:     xx.x             │
│GP 30   30 270 28 21  Y└───────── RMC ───────────└─────────── GGA ────────────┘
│GL 14   78 314 42 25  Y┌─────────────────────────┌────────────────────────────┐
│GP  3    3 170 15 18  N│Mode: A3 Sats: 1 8 10 +  │UTC: 184814.000RMS: 5.7     │
│GP  7    7 234 25  0  N│DOP H=1.29 V=0.86 P=1.55 │MAJ: 15        MIN: 8.4     │
│GP 16   16 139  2  0  N│TOFF:  0.264741719       │ORI: 170.5     LAT: 15      │
│GP 17   17 279 10  0  N│PPS: -0.006733994        │LON: 8.6       ALT: 18      │
└───v──── GSV ──────────└────── GSA + PPS ────────└─────────── GST ────────────┘
```

`GSA + PPS`のところの PPS:に数字が入るようになりました。
ここまで表示されていれば問題はないです。
`quit` もしくは `Ctrl+c`で抜けます

# 6.Chronyのインストールと設定
NTPサーバとしてChronyを使います。一般的なntpdという選択肢もありますが、この後RTCを搭載した際にハードウェアクロックとの同期がサポートされてたりと、機能的にChronyが良いため、Chronyをデーモンとして使用します。

## 6.1.Chronyのインストール

Chronyをインストールし設定します。

必要なパッケージ `chrony` をaptで入れましょう

```
sudo apt update && sudo apt -y install chrony
```

## 6.2.Chronyの設定
`/etc/chrony/chrony.conf` を編集し、PPSを使ったNTPサーバになるよう設定する。

デフォルトの `pool 2.debian.pool.ntp.org iburst` については
`pool ntp.nict.jp iburst minpoll 6 maxpoll 8`に変更し、PPSとの誤差を計測する

`sourcedir /run/chrony-dhcp`についてもコメントアウトする

`refclock PPS /dev/pps0 lock NMEA refid GPS`を追加する

`leapsecmode slew`を追加し、うるう秒においてslewモードで合わせる
`maxslewrate 1000`を追加し、1秒のずれを17時間34分かけて同期する。
`smoothtime 400 0.001 leaponly`を追加し閏秒の時でもスムーズに時刻同期する。

ここまで設定したら、 `systemctl restart chrony.service` でサービス再起動する

```
sudo sed -i 's@pool 2.debian.pool.ntp.org iburst@pool ntp.nict.jp iburst minpoll 6 maxpoll 8@g' /etc/chrony/chrony.conf
sudo sed -i 's@sourcedir /run/chrony-dhcp@#sourcedir /run/chrony-dhcp@g' /etc/chrony/chrony.conf
echo refclock PPS /dev/pps0 lock NMEA refid GPS | sudo tee -a /etc/chrony/chrony.conf
echo leapsecmode slew | sudo tee -a /etc/chrony/chrony.conf
echo maxslewrate 1000 | sudo tee -a /etc/chrony/chrony.conf
echo smoothtime 400 0.001 leaponly | sudo tee -a /etc/chrony/chrony.conf
sudo systemctl restart chrony.service
```

ここまで実行したら、`chronyc sources -v`にて同期状態をチェックしましょう
```
chronyc sources -v
```

実行例1
```
pi@raspberrypi:~ $ chronyc sources -v

  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current best, '+' = combined, '-' = not combined,
| /             'x' = may be in error, '~' = too variable, '?' = unusable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                \     |          |  zzzz = estimated error.
||                                 |    |           \
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
#? GPS                           0   4     0     -     +0ns[   +0ns] +/-    0ns
^+ ntp-b3.nict.go.jp             1   6     7     1   -155us[ -487us] +/-   12ms
^* ntp-b2.nict.go.jp             1   6     7     1    +80us[ -252us] +/-   13ms
^+ ntp-a2.nict.go.jp             1   6     7     2    +96us[ -236us] +/-   13ms
^- ntp-a3.nict.go.jp             1   6     7     2   -119us[ -452us] +/-   13ms
pi@raspberrypi:~ $ 
```

`ntp-b2.nict.go.jp` の左に `*`が付き、このソースをもとに同期を始める動作になるのですが、3分ぐらい経つと下記のようになります。

実行例2
```
pi@raspberrypi:~ $ chronyc sources -v

  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current best, '+' = combined, '-' = not combined,
| /             'x' = may be in error, '~' = too variable, '?' = unusable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                \     |          |  zzzz = estimated error.
||                                 |    |           \
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
#* GPS                           0   4    37     9  +1105ns[ -303ns] +/-  317ns
^- ntp-b3.nict.go.jp             1   6    37    11   -381us[ -382us] +/-   12ms
^- ntp-b2.nict.go.jp             1   6    37    11    -11us[  -13us] +/-   12ms
^- ntp-a2.nict.go.jp             1   6    37    11   -198us[ -199us] +/-   13ms
^- ntp-a3.nict.go.jp             1   6    37    11   -136us[ -137us] +/-   12ms
pi@raspberrypi:~ $ 
```
今度はGPSの隣に `*` が付きましたので、無事GPSの1PPS信号をもとに同期しています。
外部のNTPサーバとの補正や比較が必要なければ
`pool ntp.nict.jp iburst minpoll 6 maxpoll 8` をコメントアウトしてしまっても良いですが、この後紹介するRTCクロックを搭載後に行うのが良いかと思います。

ここまででGPSを使ったNTPサーバの構築は終わりです。

# 7.RTCモジュールの取り付け

```
pi@gps:~ $ pinout
Description        : Raspberry Pi 4B rev 1.5
Revision           : b03115
SoC                : BCM2711
RAM                : 2GB
Storage            : MicroSD
USB ports          : 4 (of which 2 USB3)
Ethernet ports     : 1 (1000Mbps max. speed)
Wi-fi              : True
Bluetooth          : True
Camera ports (CSI) : 1
Display ports (DSI): 1

,--------------------------------.
| oooooooooooooooooooo J8   +======
| 1ooooooooooooooooooo  J14 |   Net
|  Wi                    12 +======
|  Fi  Pi Model 4B  V1.5 oo      |
| |D     ,---. +---+          +====
| |S     |SoC| |RAM|          |USB3
| |I     `---' +---+          +====
| |0                C|           |
| oo1 J2            S|        +====
|                   I| |A|    |USB2
| pwr   |hd|   |hd| 0| |u|    +====
`-| |---|m0|---|m1|----|x|-------'

J8:
   3V3  (1) (2)  5V    
 GPIO2  (3) (4)  5V    
 GPIO3  (5) (6)  GND   
 GPIO4  (7) (8)  GPIO14
   GND  (9) (10) GPIO15
GPIO17 (11) (12) GPIO18
GPIO27 (13) (14) GND   
GPIO22 (15) (16) GPIO23
   3V3 (17) (18) GPIO24
GPIO10 (19) (20) GND   
 GPIO9 (21) (22) GPIO25
GPIO11 (23) (24) GPIO8 
   GND (25) (26) GPIO7 
 GPIO0 (27) (28) GPIO1 
 GPIO5 (29) (30) GND   
 GPIO6 (31) (32) GPIO12
GPIO13 (33) (34) GND   
GPIO19 (35) (36) GPIO16
GPIO26 (37) (38) GPIO20
   GND (39) (40) GPIO21

J2:
GLOBAL ENABLE (1)
          GND (2)
          RUN (3)

J14:
TR01 TAP (1) (2) TR00 TAP
TR03 TAP (3) (4) TR02 TAP

For further information, please refer to https://pinout.xyz/
pi@gps:~ $ 

```

pinoutコマンドを叩くとピン配列が出てきます。

今回のRTCモジュールには

水晶発信機の32.768kHzをそのまま出力する
- 32K

水晶発信機の32.768kHzを矩形波に直した
- SQW

I2C通信の
- SCL
- SDA

動作用の
- VCC　（3.3V入力）
- GND

の6ピンがありますが、 32KとSQWは使わなくて良いため、

- SCL
- SDA
- VCC
- GND

という４つのピンを、ラズパイの対応するピンと配線する必要があります。

ラズパイでI2Cが使えるのは
GPIO02,GPIO03となっている3番(I2C SDA)、5番(I2C SCL)
この辺りで電源として使える 3.3vPowerの1番、Groundの9番
ちょうど1直線に配線できそうです。

なので
- SCLを5番ピン
- SDAを3番ピン
- VCCを1番ピン
- GNDを9番ピン

に配線します。

`shutdown -h now` で電源を落とし、電源USBも抜いた上で、RTCモジュールとRaspberryPiを配線します。

![RTC配線.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54205/73133bf8-3f14-1af7-b071-d4e2256cb2e3.png)

# 8.Raspberry Pi OSでRTCを使うためのの設定変更

## 8.1.I2C有効にし、RTCを使えるようにする

I2Cを有効にするには　`/etc/modules` に `i2c-dev`を追記する必要がある。
また、今回のRTCはDS3231を使っているため、これを有効にするために `/boot/firmware/config.txt` に `dtoverlay=i2c-rtc,ds3231`
を追記する必要がある。

ここまで終えたら再起動をする。

```
echo i2c-dev| sudo tee -a /etc/modules
echo dtoverlay=i2c-rtc,ds3231 | sudo tee -a /boot/firmware/config.txt
sudo shutdown -r now
```

再起動後、問題なくI2Cのモジュールがロードされてるかを確認するため
`ls /dev/i2c*` を実行し、表示が出るか確認する。

実行例
```
pi@raspberrypi:~ $ ls /dev/i2c*
/dev/i2c-1
pi@raspberrypi:~ $ 
```

このように何かが表示されていれば問題ない。

## 8.2.i2c-toolsをインストール

`/dev/i2c-1`が表示されていても、これが何のデバイスかがこのままでは確認できないため、きちんとRTCが認識しているかを確認するため
`apt install i2c-tools` を行い、 `i2cdetect -y 1`でデバイス確認をします。

```
sudo apt update && sudo apt -y install i2c-tools
```

```
i2cdetect -y 1
```

実行例
```
pi@raspberrypi:~ $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         
pi@raspberrypi:~ $ 
```
57については、このRTCボードについているAT24C02 EEPROMのものなので、問題なし。
68がUUになっていればRTCが利用可能である。

万が一ここがUUではなく、数字で68となっている場合、ロードされていないため、`8.1.I2C有効にし、RTCを使えるようにする`の内容を確認する必要がある。

# 9.RTCを利用する

ここまででRTCが利用できる状態になりましたので、実際に確認や設定をします。

まず `hwclock -r` で読み出せるか確認します。

```
sudo hwclock -r
```

実行例
```
pi@raspberrypi:~ $ sudo hwclock -r
2022-09-20 12:15:26.475239+09:00
pi@raspberrypi:~ $ 
```

現在の時刻もしくは、2000年1月1日ぐらいの適当な時間のどちらかが表示されているかと思います。

本来この状態ではRTCには何も時刻が書き込まれていないはずなので、初期データの2000年1月1日ぐらいの適当な時刻が出るのですが、
GPS時刻の配信にChronyをインストールした際 `/etc/chrony/chrony.conf` に `rtcsync` が記載されているため、11分ごとにhwclockに現在時刻を書き込み同期させています。

なので、現在時刻が表示されてても問題ないです。

そこで簡単な実験をします。

`hwclock --set --date '-54min'`を行いRTCの時刻を適当な時刻へ変更後、　`while true; do echo; hwclock; date; sleep 1m; done`を実行し、様子を見ます。11分おきに　ChronyはRTCと同期をとるので、どこかのタイミングでRTCが書き変わるはずです。

```
sudo hwclock --set --date "-54min"
while true; do echo; sudo hwclock; date; sleep 1m; done
```

実行例

```
pi@raspberrypi:~ $ sudo hwclock --set --date "-54min"
pi@raspberrypi:~ $ while true; do echo; sudo hwclock; date; sleep 1m; done

2022-09-20 11:34:48.878274+09:00
Tue 20 Sep 12:28:49 JST 2022

2022-09-20 11:35:49.100144+09:00
Tue 20 Sep 12:29:50 JST 2022

2022-09-20 12:30:50.930984+09:00
Tue 20 Sep 12:30:51 JST 2022
^C
pi@raspberrypi:~ $ 
```

今回は3分ほどで同期されましたが、あくまで11分間隔で行なっているため、12分経っても同期されない場合、chronyの動作や設定に問題があります。

最後に　`timedatectl`を実行し　`System clock synchronized: yes`や　`NTP service: active`を確認する

```
timedatectl
```

実行例

```
pi@raspberrypi:~ $ timedatectl
               Local time: Tue 2022-09-20 12:37:11 JST
           Universal time: Tue 2022-09-20 03:37:11 UTC
                 RTC time: Tue 2022-09-20 03:37:11
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
pi@raspberrypi:~ $ 
```

問題なくRTCタイムが表示されていたり、`System clock synchronized: yes` `NTP service: active` が確認できればOKです。

# 10.おわりに

非常に長い文章となりましたが、RaspberryPi でのGPS　NTPやRTC利用の参考になればと。

参考資料

https://qiita.com/yunano/items/7883cf295f91f4ef716b