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ドライバを利用
やりたいこと
今回やりたかったのは、次の動き。
- 起動時、RTC があれば RTC の時刻で立ち上がる
- ネットワークにつながれば NTP で時刻を同期する
- NTP で正しい時刻が取れたら RTC にも書き戻す
つまり、普段は NTP 優先、オフライン時は RTC が保険という構成。
まず確認したこと
最初は RTC が OS から見えていない状態だった。
ls -l /dev/rtc*
sudo hwclock -r
timedatectl
この状態で、
-
/dev/rtc*が無い -
hwclock -rが失敗する -
timedatectlのRTC 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 -r と vermagic が一致していない場合は、モジュール不整合を疑った方がよい。
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 チップ内の時刻を読み出せている という意味。
timedatectl で RTC 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 が見えている。
dmesg に registered 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で読める -
timedatectlにRTC 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:が設定した時刻付近 -
dateやLocal 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 -rとdateがほぼ一致
検証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: yesNTPSynchronized=yes-
dateが正しい現在時刻 -
hwclock -rも正しい現在時刻に更新されている
まとめ
今回やったことを一言でいうと、
- RTC を OS に認識させる
- 起動時に RTC を自動登録する
- ネットワークがあれば NTP を使う
- NTP 同期後に RTC に書き戻す
という構成にした、という話になる。
補足
今回は Raspberry Pi + CONTEC CPI-RAS 環境で、RTC の認識や NTP 同期後の RTC 更新までを明示的に制御したかったため、modprobe や new_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も更新するらしいので、これだけでよい説もある。実機検証して問題なさそうだったらこっちの方が、余計なことしなくてシンプルでいいかも。