【JetPack6対応版】DS3231 RTCモジュールの設定と起動時時刻自動更新する方法
― JetPack5の方法でJetPack6で動かなかった理由と解決まで ―
対象機種:Jetson Orin Nano Developer Kit
開発環境:JetPack 6
JetPack5では問題なく動いていたRTC(リアルタイムクロック)が、
JetPack6にバージョンアップ後、
同じやり方でRTC(リアルタイムクロック)を設定しても動作しませんでした。
「配線は合っているのに認識しない」
「i2cdetectで何も出ない、RTCを認識していない?」
原因はハードではなく、i2Cバス番号の違いでした。
この記事では、
どこを確認すればよいのか、どう設定すれば動くのかを、
「解説 → コマンド → 実行結果」 の流れで解説していきます。
※記事内にアフィリエイトが含まれています。
DS3231が認識されているか確認する
Jetson Orin Nanoが、RTCモジュール「DS3231」を認識しているかを
確認することから始めます。
今回使用するRTCは「DS3231」です。
【重要ポイント!】
DS3231のI2Cアドレスは 【 0x68 】 です。
I2Cバスをスキャンして「68」と表示されれば
RTC「DS3231」が認識されています。
① PIO-40ピンヘッダ設定を確認する
SDA / SCL がどのI2Cに設定されているか確認します。
PIO-40ピンヘッダの設定内容を確認するには、
コマンドから確認できます。
【40ピンヘッダ設定を確認するコマンド】
sudo /opt/nvidia/jetson-io/jetson-io.py
コマンドを実行すると以下の結果が表示されました。
【実行結果】
=================== Jetson Expansion Header Tool ===================
| |
| |
| 3.3V ( 1) .. ( 2) 5V |
| i2c8 ( 3) .. ( 4) 5V |
| i2c8 ( 5) .. ( 6) GND |
| unused ( 7) .. ( 8) uarta |
| GND ( 9) .. ( 10) uarta |
| unused ( 11) .. ( 12) unused |
| unused ( 13) .. ( 14) GND |
| unused ( 15) .. ( 16) unused |
| 3.3V ( 17) .. ( 18) unused |
| unused ( 19) .. ( 20) GND |
| unused ( 21) .. ( 22) unused |
| unused ( 23) .. ( 24) unused |
| GND ( 25) .. ( 26) unused |
| i2c2 ( 27) .. ( 28) i2c2 |
| unused ( 29) .. ( 30) GND |
| unused ( 31) .. ( 32) unused |
| unused ( 33) .. ( 34) GND |
| unused ( 35) .. ( 36) unused |
| unused ( 37) .. ( 38) unused |
| GND ( 39) .. ( 40) unused |
| |
| |
Jetson 40pin Header:
Configure for compatible hardware
Configure header pins manually
Back
実行結果の赤文字部分を見ます。
( 3) i2c8
( 5) i2c8
3番ピン(SDA)
5番ピン(SCL)
3番ピン(SDA)、5番ピン(SCL)は、「 i2c8 」に設定されています。
使うのは:i2cdetect -y 8 になります。
⚠ ここが重要
設定表示されている番号を確認する必要があります。
i2c8(ピン表示) ≠ i2c-8(Linuxデバイス)数字は一致しません。
② i2Cバスに接続されているデバイスを調べる
I2c-8 を試すとどうなる?
I2Cバス番号8をスキャンして、接続されているデバイスのアドレスを調べます。
【I2Cバス番号8を調べるコマンド】
sudo i2cdetect -y 8
【実行結果】
user@user-desktop:~$ sudo i2cdetect -y 8
[sudo] user のパスワード:
Error: Could not open file /dev/i2c-8′ or /dev/i2c/8′: No such file or directory
「Error:Could not open file」
「ファイルを開くことができませんでした」とエラーが出ています。
つまり、LinuxがI2Cデバイスにアクセスできなかったという結果です。
「 i2c8 」は、Linux上では別の番号になっています。
③ 実際に存在する i2Cバスを確認する
このLinuxに存在している「 i2C 」バスの一覧を表示するコマンドで調べてみます。
【i2Cバスの一覧を表示するコマンド】
sudo i2cdetect -l
【実行結果】
user@user-desktop:~$ sudo i2cdetect -l
i2c-0 i2c 3160000.i2c I2C adapter
i2c-1 i2c c240000.i2c I2C adapter
i2c-2 i2c 3180000.i2c I2C adapter
i2c-4 i2c Tegra BPMP I2C adapter I2C adapter
i2c-5 i2c 31b0000.i2c I2C adapter
i2c-7 i2c c250000.i2c I2C adapter
i2c-9 i2c NVIDIA SOC i2c adapter 0 I2C adapter
この中で注目するのが、
i2c-7 c250000.i2c
jetson-ioの表示にあった i2c8(c250000)と一致しています。
40ピンの i2c8 は Linuxでは「 i2c-7 」
である可能性が高いことになります。
④ i2c-7 をスキャンする
「i2c-7」 を調べてみます。
Quick Write ではなく Read モードでしか読めない場合もあるため確認します。
【i2Cバス番号8を調べるコマンド】
sudo i2cdetect -y 7
【Quick Write ではなく Read モードで確認コマンド】
sudo i2cdetect -r -y 7
【実行結果】
user@user-desktop:~$ sudo i2cdetect -r -y 7
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: — — — — — — — —
10: — — — — — — — — — — — — — — — —
20: — — — — — — — — — — — — — — — —
30: — — — — — — — — — — — — — — — —
40: — — — — — — — — — — — — — — — —
50: — — — — — — — 57 — — — — — — — —
60: — — — — — — — — 68 — — — — — — —
「68」が出ました!
DS3231(RTC本体)を認識しています!
0x57 → EEPROM(AT24C32)
0x68 → DS3231(RTC本体)
ここまでで、
✅ 配線 正常
✅ I2C通信 正常
✅ RTC 生きている
ことが確認できました。
DS3231をLinuxへ登録する
検出できただけでは、DS3231は使えないため、
使えるようにする為、DS3231をLinuxへデバイス登録していきます。
① RTCドライバを読み込む
RTCドライバを読み込んでいきます。
【RTCドライバ読込コマンド】
sudo modprobe rtc-ds1307
※ DS3231 は ds1307 ドライバで動きます。
② デバイス登録
RTCデバイスを登録していきます。
【RTCデバイスを登録コマンド】
echo ds3231 0x68 | sudo tee /sys/class/i2c-adapter/i2c-7/new_device
③ RTCデバイスを確認
Linuxに登録されているRTC(時計デバイス)を一覧表示します。
①ls :ファイルやディレクトリを表示するコマンド
②/dev:「ファイル」として扱われます。
※ /dev フォルダには、
USB・I2C・シリアル・RTCなどのデバイスファイルが入っている
④rtc*:* はワイルドカードでrtc で始まるファイルを全部表示する
【一覧表示するコマンド】
ls /dev/rtc*
【実行結果】
/dev/rtc
/dev/rtc0
/dev/rtc1
/dev/rtc2
Linuxが現在認識しているRTCデバイスが4つあります。
それぞれの意味
/dev/rtc:デフォルトのRTCを指しています(多くの場合 rtc0 へのリンク)。
/dev/rtc0:SoC内蔵のRTCである。
/dev/rtc1:電源管理用のRTCなど、別の内部時計。
/dev/rtc2:「新しいRTCデバイス(DS3231)」を認識して追加した。
どれがDS3231か確認する
追加された「/dev/rtc2」のデバイスを確認します。
① cat:ファイルの中身を表示するコマンド
② /sys/class/rtc/:ここが重要です。
/dev → ハードを操作する入口
/sys → ハードの情報を見る場所という役割があります。
/sys/class/rtc/ には、
今Linuxが認識しているRTCデバイスの情報が入っています。
③ rtc0, rtc1, rtc2
これはそれぞれ
/dev/rtc0:(rtc0 の中身は何か?)
/dev/rtc1:(rtc1 の中身は何か?)
/dev/rtc2:(rtc2 の中身は何か?)
を調べます。
【デバイスの中身を表示するコマンド】
cat /sys/class/rtc/rtc0/name
cat /sys/class/rtc/rtc1/name
cat /sys/class/rtc/rtc2/name
【実行結果】
nvvrs-pseq-rtc
tegra_rtc c2a0000.rtc
rtc-ds1307 7-0068
この結果の意味
nvvrs-pseq-rtc → 電源制御系の内部RTC
tegra_rtc → Jetson本体に内蔵されているRTC
rtc-ds1307 7-0068 → 外付けRTC(DS3231)
※ DS3231は ds1307ドライバで動作するため、この名前になります。
「新しく rtc が増えています」
最初は
/dev/rtc
/dev/rtc0
/dev/rtc1
しかなかったのに、
ドライバを読み込み、登録すると
「 /dev/rtc2 」が増えます。
新しいRTCデバイス(DS3231)を認識されたことが確認できました。
✔ rtc0, rtc1, rtc2 の中身を確認する
✔ どれがDS3231なのか特定する
✔ hwclockで正しい番号を指定するための準備
という重要な確認作業です。
④ 時刻確認
時刻を確認します。
(Xは増えた番号)
【時刻確認するコマンド】
sudo hwclock -r -f /dev/rtcX
【実行結果】
rtc-ds1307 7-0068
これがDS3231です。
今回の場合は /dev/rtc2 です。
⑤ 時刻の読み込み
RTCからシステム時間に、時刻を読んでみます。
【時刻読み込みコマンド】
sudo hwclock -r -f /dev/rtc2
【実行結果】
2000-01-01 11:34:38
これは正常です。
新品や電池が入っていない場合、初期値は2000年になります。
⑥ 時刻の書き込み
システム時刻をRTCに、時刻を書き込んでみます。
インターネット接続して時刻を合わせた後に実行します。
【時刻を書き込むコマンド】
sudo hwclock -w -f /dev/rtc2
RTCに書き込まれているかを確認します。
<手順>
シャットダウン
電源を完全に抜く
10秒待つ
再起動(ネット未接続)
RTCから時刻を読み込みます。
【時刻を読み込むコマンド】
sudo hwclock -r -f /dev/rtc2
【実行結果】
2000-01-01 11:34:38.609865+09:00
正しい時刻が表示されれば成功です。
^^^^^^^^^^^^^^^^^^
<起動時RTCモジュールから時刻をシステム時刻に書き込む設定>
⑩ 起動時に自動で時刻を反映させる(JetPack6対応)
JetPack6では rc.local は使いません。
systemdサービスを作成します。
① サービスファイル作成
sudo nano /etc/systemd/system/ds3231.service
内容:
[Unit]
Description=DS3231 RTC setup
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c “modprobe rtc-ds1307”
ExecStart=/bin/bash -c “echo ds3231 0x68 > /sys/class/i2c-adapter/i2c-7/new_device”
ExecStart=/sbin/hwclock -s -f /dev/rtc2
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
② サービス登録
sudo systemctl daemon-reload
sudo systemctl enable ds3231.service
③ 動作確認
sudo systemctl start ds3231.service
エラーがなければOKです。
最終テスト
シャットダウン
電源を完全に抜く
10秒待つ
起動(ネット未接続)
date
正しい時刻が表示されれば、完全成功です。
まとめ
JetPack6で一番の落とし穴は、
ピン表示の i2c8 と Linux上の i2c-7 が一致しないこと
ハードが壊れているわけではありません。
多くの場合、「番号の対応関係」が原因です。
組み込み開発では、
配線を疑う
バス番号を疑う
デバイス登録を確認する
この順番で考えると、必ず解決に近づきます。
同じように悩んでいる学生さんの助けになれば嬉しいです。

