0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Raspberry Pi + CONTEC CPI-RASで、ネットワーク接続時はNTP、オフライン時はRTCを使う構成にした

0
Posted at

Raspberry Pi に CONTEC CPI-RAS を接続して使っている環境で、時刻同期を次のようにしたかった。

  • ネットワークにつながっているときは NTP の時刻を使う
  • ネットワークにつながっていないときは RTC の時刻を使う
  • ネットワークにつながって正しい時刻が取れたら RTC も更新する

最終的には RTC + systemd-timesyncd + systemd service で整理した。

この記事では、CPI-RAS の RTC を Linux から使えるようにするところから、起動時の自動登録NTP 同期後の RTC 更新検証方法までまとめる。


環境

  • Raspberry Pi
  • Raspberry Pi OS
  • CONTEC CPI-RAS
  • RTC ドライバ: CPI-RAS_106
  • RTC は I2C バス上の 0x32 に見えている
  • カーネル側では rtc-rv8803 ドライバを利用

やりたいこと

今回やりたかったのは、次の動き。

  1. 起動時、RTC があれば RTC の時刻で立ち上がる
  2. ネットワークにつながれば NTP で時刻を同期する
  3. NTP で正しい時刻が取れたら RTC にも書き戻す

つまり、普段は NTP 優先、オフライン時は RTC が保険という構成。


まず確認したこと

最初は RTC が OS から見えていない状態だった。

ls -l /dev/rtc*
sudo hwclock -r
timedatectl

この状態で、

  • /dev/rtc* が無い
  • hwclock -r が失敗する
  • timedatectlRTC time:n/a

なら、まだ RTC は Linux に登録されていない。


I2C 上で RTC が見えているか確認する

まずは I2C バス上で RTC チップが見えているか確認する。

ls /sys/class/i2c-dev/
i2cdetect -y 1

今回の環境では、0x32 にデバイスが見えていた。

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- 2c -- -- --
30: -- -- 32 -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

この時点ではまだ「I2C 上に何かいる」だけで、RTC として OS から使える状態ではない


RTC ドライバを準備する

まずは配布物を Raspberry Pi 側へ転送して展開する。

scp <CPI-RAS_106.tgz> <user>@<host>:<path>

SSH でログインし、展開してインストールする。

tar xvfz CPI-RAS_106.tgz
cd ~/CPI-RAS_106/rtcDrv
sudo apt install raspberrypi-kernel-headers
sudo make drivers_install

ハマりどころ

最初、古い CPI-RAS_105 のドライバを使っていたところ、カーネルバージョンとモジュールの vermagic がずれていて Exec format error が出た。

そのため、今のカーネルに合った CPI-RAS_106 を使うのが重要だった。

確認コマンド:

uname -r
modinfo rtc-rv8803 | egrep 'filename|vermagic'

uname -rvermagic が一致していない場合は、モジュール不整合を疑った方がよい。


RTC ドライバをロードする

まずはドライバをロードする。

sudo modprobe rtc-rv8803
lsmod | grep rtc_rv8803

ここで rtc_rv8803 が表示されれば、ドライバはロードできている。


RTC を Linux に登録する

ドライバがロードできる状態になったら、RTC を I2C デバイスとして登録する。

sudo sh -c 'echo rx8900 0x32 > /sys/bus/i2c/devices/i2c-1/new_device'

今回の環境では new_device のパスが

/sys/bus/i2c/devices/i2c-1/new_device

だった。
/sys/class/i2c-adapter/i2c-1/new_device ではなかった。


RTC が認識できたか確認する

登録後に以下を確認する。

ls -l /dev/rtc*
sudo hwclock -r
timedatectl
dmesg | tail -n 50

/dev/rtc0 ができている

lrwxrwxrwx 1 root root      4 ... /dev/rtc -> rtc0
crw------- 1 root root 252, 0 ... /dev/rtc0

これは Linux が RTC デバイスとして認識した という意味。

hwclock -r で読める

sudo hwclock -r
2026-03-18 13:07:12.405441+09:00

これは RTC チップ内の時刻を読み出せている という意味。

timedatectlRTC time: が出る

timedatectl
               Local time: Wed 2026-03-18 13:07:22 JST
           Universal time: Wed 2026-03-18 04:07:22 UTC
                 RTC time: Wed 2026-03-18 04:07:22
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

RTC time: n/a ではなく値が表示されていれば、systemd からも RTC が見えている。

dmesgregistered as rtc0 が出る

rtc-rv8803 1-0032: registered as rtc0
rtc-rv8803 1-0032: setting system clock to 2026-03-18T04:08:05 UTC
i2c i2c-1: new_device: Instantiated device rx8900 at 0x32

このログが出ていれば、

  • I2C バス 1
  • アドレス 0x32
  • rx8900 として登録
  • rtc0 として認識
  • その RTC の時刻でシステムクロックを初期化

という流れが成立している。


構成した内容

1. 起動時に RTC を自動登録する

RTC 登録スクリプト

sudo tee /usr/local/sbin/register-cpi-rtc.sh > /dev/null <<'EOF'
#!/bin/bash
set -e

BUS_PATH="/sys/bus/i2c/devices/i2c-1"
DEV_PATH="/sys/bus/i2c/devices/1-0032"

# 既に登録済みなら何もしない
if [ -e "$DEV_PATH" ]; then
  exit 0
fi

modprobe rtc-rv8803
echo rx8900 0x32 > "$BUS_PATH/new_device"
EOF

sudo chmod +x /usr/local/sbin/register-cpi-rtc.sh

systemd service

sudo tee /etc/systemd/system/register-cpi-rtc.service > /dev/null <<'EOF'
[Unit]
Description=Register CPI-RAS RTC on I2C bus
DefaultDependencies=no
After=systemd-modules-load.service
Before=sysinit.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/register-cpi-rtc.sh
RemainAfterExit=yes

[Install]
WantedBy=sysinit.target
EOF

2. NTP 同期後に RTC を更新する

RTC 更新スクリプト

sudo tee /usr/local/sbin/update-cpi-rtc-from-ntp.sh > /dev/null <<'EOF'
#!/bin/bash
set -e

[ -e /dev/rtc0 ] || exit 0

for i in $(seq 1 60); do
  if [ "$(timedatectl show -p NTPSynchronized --value)" = "yes" ]; then
    hwclock --systohc --utc
    exit 0
  fi
  sleep 1
done

exit 0
EOF

sudo chmod +x /usr/local/sbin/update-cpi-rtc-from-ntp.sh

systemd service

sudo tee /etc/systemd/system/update-cpi-rtc-from-ntp.service > /dev/null <<'EOF'
[Unit]
Description=Update CPI-RAS RTC after NTP synchronization
After=network-online.target systemd-timesyncd.service register-cpi-rtc.service
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/update-cpi-rtc-from-ntp.sh

[Install]
WantedBy=multi-user.target
EOF

3. service を有効化する

sudo systemctl daemon-reload
sudo systemctl enable register-cpi-rtc.service
sudo systemctl enable update-cpi-rtc-from-ntp.service
sudo timedatectl set-ntp true

動作確認

ls -l /dev/rtc*
sudo hwclock -r
timedatectl
systemctl status register-cpi-rtc.service
systemctl status update-cpi-rtc-from-ntp.service

ここで、

  • /dev/rtc0 がある
  • hwclock -r で読める
  • timedatectlRTC time: が出る
  • 2つの service が失敗していない

なら、土台は完成。


検証方法

検証は以下の 3 パターン。

  • RTC が使えているか
  • ネットワークなしで RTC 起動できるか
  • ネットワークありで NTP 優先になり、RTC へ書き戻されるか

検証1: RTC 単体で使えるか

まず NTP を無効化。

sudo timedatectl set-ntp false

RTC 時刻をわざと変更する。

sudo hwclock --set --date "2026-03-22 08:00:00"
sudo hwclock -r
timedatectl

再起動。

sudo reboot

起動後に確認。

timedatectl
sudo hwclock -r
date

成功条件

  • System clock synchronized: no
  • RTC time: が設定した時刻付近
  • dateLocal time も RTC に近い時刻

検証2: ネットワークなし起動で RTC が使われるか

NTP を有効化。

sudo timedatectl set-ntp true

RTC に分かりやすい時刻を設定。

sudo hwclock --set --date "2026-03-22 09:30:00"
sudo hwclock -r

LAN を抜く、または Wi-Fi を切って再起動。

sudo reboot

起動後に確認。

timedatectl
sudo hwclock -r
date
ip a

成功条件

  • System clock synchronized: no
  • Local time が RTC に近い
  • hwclock -rdate がほぼ一致

検証3: ネットワークありで NTP が優先されるか

ネットワーク接続状態で、RTC にわざとズレた時刻を入れる。

sudo hwclock --set --date "2026-03-22 01:00:00"
sudo hwclock -r
timedatectl

再起動。

sudo reboot

起動後に 30〜60 秒待って確認。

timedatectl
timedatectl show -p NTPSynchronized --value
sudo hwclock -r
date
journalctl -u update-cpi-rtc-from-ntp.service -b --no-pager

成功条件

  • System clock synchronized: yes
  • NTPSynchronized=yes
  • date が正しい現在時刻
  • hwclock -r も正しい現在時刻に更新されている

まとめ

今回やったことを一言でいうと、

  • RTC を OS に認識させる
  • 起動時に RTC を自動登録する
  • ネットワークがあれば NTP を使う
  • NTP 同期後に RTC に書き戻す

という構成にした、という話になる。


補足

今回は Raspberry Pi + CONTEC CPI-RAS 環境で、RTC の認識や NTP 同期後の RTC 更新までを明示的に制御したかったため、modprobenew_device、systemd service を使って構成した。

ただ、もっとシンプルに済む可能性もありそう。

/boot/firmware/config.txt に以下を設定する方法。

dtoverlay=i2c-rtc,rx8900

この方法で、起動時の RTC 認識まで自動化できる可能性がある。
環境によっては、今回のように echo rx8900 0x32 > /sys/bus/i2c/devices/i2c-1/new_device を明示的に実行しなくても、これだけで動くかもしれない。

つまり今回の記事の内容は、

  • 確実に動作を把握しながら組みたい場合
  • CPI-RAS 環境で挙動を明示的に制御したい場合
  • 「ネットワーク時はNTP、オフライン時はRTC、復帰後はRTC更新」を自分で確実に担保したい場合

には有効だと思う。

一方で、最初からここまで手厚く組まなくても、まずは

dtoverlay=i2c-rtc,rx8900

これで認識するなら、余計なことしなくてもこれでいいのかも。
systemd-timesyncdが11分おきにRTCも更新するらしいので、これだけでよい説もある。実機検証して問題なさそうだったらこっちの方が、余計なことしなくてシンプルでいいかも。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?