Raspberry Pi: RTC の接続

Takami Torao RPi3 Model B+ Raspbian 11 #RaspberryPi
  • このエントリーをはてなブックマークに追加

概要

Raspberry Pi は RTC1 (real-time clock) を搭載しておらず、シャットダウン時に時刻を記録して次の起動時にはその時刻から開始するように動作する。ネットワークに接続していれば起動後すぐに NTP サーバと時刻同期を行って概ね正しい時刻で動作するが、オフライン環境や NTPd をオフにしている状態ではシステム時刻が実際の時刻よりどんどん遅れることになる。

Raspberry Pi に RTC モジュールを追加することで電源のオン/オフを行っても正しいシステム時刻を示すようにすることができる。この記事では実際に RTC モジュールを取り付けてシステムが RTC の時刻を使用するように設定する。

  • 1コンピュータ内蔵の時計や回路。電池などのバックアップによりコンピュータの電源を落とした状態でも時間を刻み続けることができる。ハードウェアクロック、CMOS に時刻を記録し続けるため CMOS クロックなどとも呼ばれる。

Table of Contents

  1. 概要
  2. RTC による時刻合わせ
    1. RTC の接続
    2. RTC の有効化
    3. システム時刻で RTC 時刻を更新
    4. 起動時にシステム時刻を RTC 時刻で更新
    5. fake-hwclock の削除

ここでは SEEED の DS1307 クロックの RTC を使用している。RTC 単体であれば 500 円程度で購入することができる。それ以外には電源制御モジュールのように RTC とセットになっている物を選んでも良い。

Fig 1. DS1307 クロックを使った Raspberry Pi 用の RTC。

この RTC モジュールはバックアップ電池に 3V CR1225 を使用する。CR1225 は国内の家電店では取り扱いがないため、ネットで購入するか BR1225 で代用するしかない点に注意 (応急処置的に高さが 0.5mm 低い 3V CR1220 も使えないことはない)。

RTC による時刻合わせ

先に raspi-config を使って RTC を取り付ける I²C インターフェースを有効化する。

pi@pirite:~ $ sudo raspi-config

Interface OptionsI2CYes

Fig 2. raspi-config で I²C インターフェースを有効化する。

まずは RTC 取り付け前の状態を確認してみよう。timedatectl を実行すると RTC time が n/a になっていて時刻制御に使用できる RTC が存在しないことが分かる。また i2cdetect -y 1 の実行結果は I²C インターフェース上で何のデバイスも検出していないことを示している。

pi@pirite:~ $ timedatectl
               Local time: Sun 2022-02-06 16:18:40 JST
           Universal time: Sun 2022-02-06 07:18:40 UTC
                 RTC time: n/a
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: no
              NTP service: n/a
          RTC in local TZ: no


pi@pirite:~ $ 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: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

RTC の接続

次に Raspberry Pi に RTC を設置しよう。取り付けで特に難しいことはなく、本体の電源を落として Fig 3 に示すように I²C インターフェースに差し込むだけで良い。

Fig 3. DS1307 を Raspberry Pi の I²C に接続。ケースの高さによっては干渉するかもしれない。

RTC の有効化

RTC モジュールの取り付けが完了したら次は Raspberry Pi を起動して RTC を有効にする。まずはシステムが対応している RTC のクロックを確認しよう。

pi@pirite:~ $ dtoverlay -h i2c-rtc
Name:   i2c-rtc
Info:   Adds support for a number of I2C Real Time Clock devices
Usage:  dtoverlay=i2c-rtc,<param>=<val>
Params: abx80x                  Select one of the ABx80x family:
                                  AB0801, AB0803, AB0804, AB0805,
                                  AB1801, AB1803, AB1804, AB1805
        bq32000                 Select the TI BQ32000 device
        ds1307                  Select the DS1307 device   ← 今回設置した RTC に搭載されているクロック
        ds1339                  Select the DS1339 device
        ds1340                  Select the DS1340 device
        ds3231                  Select the DS3231 device
        ...

取り付けた RTC のクロックに対応していることを確認したら、/boot/config.txt を開いてそのクロックを指定する。

pi@pirite:~ $ sudo vim /boot/config.txt
# Enable RTC
dtoverlay=i2c-rtc,ds1307

Raspberry Pi を再起動して RTC が認識されていることを確認する。次の例は RTC time から時刻を参照できており、I²C バス上のアドレス 0x68 がシステムによって使用されていることを示している。

pi@pirite:~ $ timedatectl
               Local time: Tue 2022-02-08 22:19:44 JST
           Universal time: Tue 2022-02-08 13:19:44 UTC
                 RTC time: Tue 2022-02-08 13:19:42
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: no
              NTP service: n/a
          RTC in local TZ: no


pi@pirite:~ $ 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 時刻を更新

OS の管理するシステム時刻と、RTC のハードウェアクロックは別々に時刻を管理している。

有効化したばかりの RTC は間違った時刻を示していることがある。時刻はコマンドライン上で指定もできるが、システム時刻が正確ならシステム時刻で更新するのが確実なので、まずシステム時刻を NTP サーバと同期しよう。

以下のコマンドで ntpdactive (running) 状態になっていれば問い合わせ時刻を確認する。以下の例では 16:06 (現在 16:18 なので 12 分前) にプールに設定されている NTP サーバに要請していることがわかる。

pi@pirite02:~ $ sudo systemctl status ntp
● ntp.service - Network Time Service
     Loaded: loaded (/lib/systemd/system/ntp.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2022-02-11 16:06:47 JST; 1min 34s ago
       Docs: man:ntpd(8)
    Process: 4807 ExecStart=/usr/lib/ntp/ntp-systemd-wrapper (code=exited, status=0/SUCCESS)
   Main PID: 4813 (ntpd)
      Tasks: 2 (limit: 780)
        CPU: 181ms
     CGroup: /system.slice/ntp.service
             └─4813 /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 115:124

Feb 11 16:06:51 pirite ntpd[4813]: Soliciting pool server 2001:9a8:0:e:1337:0:123:1
Feb 11 16:06:51 pirite ntpd[4813]: Soliciting pool server 160.16.113.133
...
Feb 11 16:06:54 pirite ntpd[4813]: Soliciting pool server 194.0.5.123

あるいは意図的に ntpd を停止しているのであれば ntpdate を使って同期する。

pi@pirite:~ $ sudo apt install -y ntpdate
pi@pirite:~ $ ntpdate ntp.nict.jp

システム時刻が正しいことを確認したら、次のコマンドで RTC 時刻をシステム時刻で更新する。

pi@pirite:~ $ sudo hwclock --systohc

起動時にシステム時刻を RTC 時刻で更新

/etc/udev/rules.d/85-hwclock.rules に以下のようなファイルを作成する。

pi@pirite:~ $ sudo vim /etc/udev/rules.d/85-hwclock.rules
# On the Raspberry Pi the RTC isn't available when systemd tries,
# set the time from RTC now when it is available.
KERNEL=="rtc0", RUN+="/sbin/hwclock --rtc=$root/$name --hctosys"

この設定後に WiFi をオフにして Ethernet ケーブルと電源ケーブルを抜いた状態で暫く放置し、起動した後に確認すると、システム時刻、RTC 時刻、電波時計 (G-SHOCK) がすべて同じ時刻を示していた。

fake-hwclock の削除

RTC を構成した後も Raspberry Pi がデフォルトで使用している fake-hwclock を残しておくことができる。しかしこれを削除しておくことで (電池切れなどにより) RTC が機能していないときに 2016-11-03 のような明らかにおかしい時間となって気づきやすい。残しても削除してもどちらでも良いが、削除する場合は apt から行うことができる。

pi@pirite:~ $ sudo apt purge fake-hwclock