Raspberry Pi に RTC(DS1307) を導入した

Raspberry Pi に DS1307 を導入した

[【RaspberryPi】RTC DS1307 導入方法まとめ]( https://qiita.com/gcyagi/items/34e569dcd9f4ace88415 )

を読みながら作業したら問題なかったんだけど、上記の記事との差異や、追加情報を。

# ハードウェアとOS

ラズパイは：

* Raspberry Pi 3 Model B+
* Linux raspberrypi 4.19.50-v7+ #896 SMP Thu Jun 20 16:11:44 BST 2019 armv7l GNU/Linux

で。RTC は 「Raspberry Pi RTC Expansion Module v1.1Maxim DS1307チップ」というのを入手した。1000円前後。
別途ボタン電池 CR1220 必要。こちらは 150円前後。

# 起動

ハードウェアをつなげないと設定できないので、電池を入れてラズパイにさしてから起動する。

さし方は
[DS1307 RTC Module with BAT for Raspberry Pi SKU: EP-0059 ― How to Connect:]( https://wiki.52pi.com/index.php/DS1307_RTC_Module_with_BAT_for_Raspberry_Pi_SKU:_EP-0059#How_to_Connect: )
の写真が参考になる。

ちなみに、RTC をラズパイにさした状態だと手元のケースだとふたが閉まらなくなる。どうしたものか。

# I2C の有効化

```shell-session
$ sudo raspi-config
```

として、

`5 Interfacing Options` → `P5 I2C` を選ぶと
`Would you like the ARM I2C interface to be enabled?` と聞かれるので `<はい>` を選ぶ。

# 必要なツールのインストール

上記の記事だと `i2c-tools` も入れるようになっていたが、私の手元だとインストール済みだった。
というわけで、

```shell-session
$ sudo apt-get install ntpdate
```

と、`ntpdate` を入れる。これはあとで、起動スクリプトで使う。

# RTCモジュールを起動時に読み込むようにする

`/etc/modules` というファイルがあり、そこにモジュール名を書いておくと起動時に読み込んでくれるらしい。

上記の記事だと `i2c-dev` も書き込むようになっていたが、手元の環境ではすでに `i2c-dev`は `/etc/modules` に書いてあったので、 `rtc-ds1307` だけを書き込むことにした。

```bash
$ sudo echo rtc-ds1307 >> /etc/modules
-bash: /etc/modules: 許可がありません
```

が、失敗。仕方ないので root で実行。

```shell-session
$ su
# echo rtc-ds1307 >> /etc/modules
# exit
```

# RTC の I2C のアドレス番号を確認する

こんな感じ：

```shell-session
$ sudo 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: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --    
```

私の場合は 0x68 だった。

ちなみに `-y` は「Disable  interactive mode.」。`1` はi2c bus の番号らしい。

# デバイスアダプタ(?)の登録

続いて、 `/sys/class/i2c-adapter/i2c-1/new_device` に RTC を登録する。この、 `new_device` というファイルは、 `ls -l` すると

```shell-session
--w------- 1 root root 4096  8月 15 11:53 new_device
```

となっていて、普通のファイルではないことがわかる。このファイルにデバイス名とアドレス番号を

```shell-session
$ su
# modprobe rtc-ds1307
# echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
```

という具合に書き込む。
`modprobe` は、Linux カーネルにモジュールを追加するらしい。
`modprobe` にわたす引数と `new_device` に書き込むデバイス名が合っていないので不安になるけどこれでいいらしい。

うまくできると、 `i2cdetect` の出力が `68` から `UU` に変わる。`UU` は「ここはドライバが使っているよ」という意味。

```shell-session
$ sudo 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: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --   
```


# RTC 以外の時計を無効にする

RTC 以外の時計があると競合して(というより、RTC が負けて)RTCが機能しないので止める必要がある。
特に `fake-hwclock` は バッテリバックアップされた RTC がない環境専用なので全く必要ない。
ntp はあとで電源 on 時に参照するようになっているのでここは一旦 off にする。

こんな具合。ここは前掲の記事と全く同じ。

```shell-session
$ sudo apt-get install chkconfig
$ sudo chkconfig ntp off
$ sudo apt-get remove fake-hwclock
$ sudo dpkg --purge fake-hwclock
```

# 起動時に RTC の内容をシステムクロックに取り込む

起動スクリプト `rc.local` で、以下の変更を加える：

* npt サーバー `ntp.nict.jp` から時刻を読み取ろうとしてみる
* 読み取れたら、その結果を RTC に書き込む
* 読み取れなかったら、RTC の時刻をシステム時間とする

というわけで、`vim` などを使って `rc.local` を以下のように書き換える

変更前：

```bash
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

exit 0
```

変更後：


```bash
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device

ntpdate -v ntp.nict.jp

if  [ $? = 0 ]; then
  hwclock -w # システムクロック => RTC
else
  hwclock -s # システムクロック <= RTC
fi

exit 0
```

# 起動時にネットワーク接続を待たないようにする

このままだと、起動時にネットワーク接続を待ってしまうんだと思う。

そこで、

```shell-session
$ sudo raspi-config
```

として、起動オプションを変更する。

`3 Boot Options` → `B2 Wait for Network at Boot` を選ぶと
「`Would you like boot to wait until a network connection is established?`」と聞かれるので「`<いいえ>`」を選ぶ。

# RTC を正しい時刻にする

ntp が使える環境で再起動すると、先程の `rc.local` にあるスクリプトのおかげで時刻が正しくなる。というわけで、再起動。

そして

```shell-session
$ sudo hwclock --get
2019-08-15 13:58:39.252902+09:00
```

とすると、RTC が正しい時刻になっていることがわかる。

# ネットワークのない環境での動作確認

まだやっていない。