NanoPi NEOにRTCモジュールを付ける

NanoPi NEOをNTPサーバにしているのだが、このシングルボードコンピューターはRTCが「なんちゃって」なので電源を切る(再起動する)と時刻情報が失われてしまう。一応システム起動時にネットワーク経由で時間合わせをするようにしているがせめて日時くらいは自分で持っててよと思う。それと、時刻のズレ方が盛大。1日で1秒2秒程度のズレならまぁかわいいものだが、NanoPi NEOでは使い方によっては酷ければ見ている内にどんどんズレてしまうほど。これは全く信用ならないのでRTCモジュールが欲しいと思ってたけど面倒と思う気持ちが勝って長らく放置してた。

例によってAliExpressで購入。2020年6月30日の購入時は商品価格が131円で送料無料だったけど、その後送料が50円前後発生している模様。なお、この製品およびリンク先がDS3231の本物チップを搭載したRTCモジュールであること、本物を販売するショップであることを保証するものではありません。

RTCモジュールの取り付けとLinuxの設定 1
届いたRTCモジュールが上。下は大きさ比較用のmicroSDカード。基板としては小さいけどRTCモジュールとしては大きいかしら?

RTCモジュールの取り付けとLinuxの設定 2
電池を付ける側。この面は電池ホルダーだけ。このモジュールは電池による時刻のバックアップができる(半分はそれが目的で買ってる)が、電池自体は付属していない。大きさ的には100均ショップなどでも入手できるCR2032のボタン電池が合う。

RTCモジュールの取り付けとLinuxの設定 3
反対の面。メインのチップはDS3231SNと書かれている。これが偽チップでなければ-40℃〜85℃対応なTCXOのちょっと良いやつ。DS3231SだとTCXOだけど寒い側非対応の0℃〜70℃。誤差は0℃〜40℃で±2ppm,他±3.5ppm。 DS3231MやDS3231MZだと「DS3231はTCXOである」ことを期待して購入した筈がTCXOではなくmicroelectromechanical system(MEMS)というやつで温度は-40℃〜85℃対応だけど±5ppm (±0.432秒/日)らしいので注意。

DS3231の下の(ATMTC086) 24C32N はEEPROM。DS3231のアドレスは0x68固定とのことだがアドレスはEEPROMのアドレスは初期値が0x57で0x50から0x57の間で変更可能のよう。アドレス変更は基板上のA0,A1,A2で。

RTCモジュールの取り付けとLinuxの設定 4
このモジュールはLIR2032という充電可能な電池を想定して作られているので充電非対応のCR2032を使うのは電池破裂等の危険があるので普通にNGというか絶対ダメ。ただし、基板上の抵抗を1つ外すことで非充電にしてCR2032ボタン電池を使うことができるようになる。画像の赤い下向け矢印のところにある抵抗で、1つ前の画像では抵抗が付いているが、この画像では既に抵抗を取り除いている。外し方としては超先細のラジオペンチなどで抵抗を挟んで砕くというのでも良いけど普通ははんだこてで温めてはんだを吸い取りながら抵抗を外すかな。今回は一応温めて丁寧に取り除いた。
このモジュールにはプルアップ抵抗が付いている。Raspberry Piではプルアップ抵抗が要らない(邪魔)ので外すらしいが、NanoPi NEOでは必要なようなのでRasbberryPi用の記事をそのまま信じてプルアップ用抵抗まで外してしまわないこと。(画像中の黄色い右向け矢印)

RTCモジュールの取り付けとLinuxの設定 5
抵抗を取り除いたので充電非対応のCR2032を取り付けた。なお、この電池ホルダーは電池を外すのが難しいタイプなので迂闊に電池を入れてしまうと苦労することも。抵抗を外す前に電池を入れない方が良さそう。

RTCモジュールの取り付けとLinuxの設定 6
NanoPi NEOとRTCモジュールの接続は簡単。赤丸の付いたピンとRTCモジュールの同じ名前のピンにつなぐだけ。
micro USB端子に近い側から1ピン空けてSDA, CSLと1ピン空けてGND、この3ピンの他に一番右上の外列2つのVCC 5V出力2つのどちらか空いてる方ををRTCモジュールとつなぐ。VCCとGNDは既に別なモジュール等が使っていたら別のピンでも良いけど、VCCは3.3Vはダメで5Vにつなぐ。
今回はNanoPi NEOと接続なのでRTCモジュールの32K(32768Hz出力)とSQW(1Hz出力)のピンは使わない。

RTCモジュールの取り付けとLinuxの設定 7
今回は以前に作ったアルミケース入りNTPサーバに取り付けた。これで半分がガラ空きだったNTPサーバのケースの中がなんとか埋まった感じ。

NanoPi NEOなどH3なSoCのシングルボードコンピュータでは以下のファイルを確認。(Armbianの場合)
/boot/dtb/overlay/README.sun8i-h3-overlays

### cir

Activates CIR (Infrared remote) receiver

CIR pin: PL11

### i2c0

Activates TWI/I2C bus 0

I2C0 pins (SCL, SDA): PA11, PA12

### i2c1

Activates TWI/I2C bus 1

I2C1 pins (SCL, SDA): PA18, PA19

### i2c2

Activates TWI/I2C bus 2

I2C2 pins (SCL, SDA): PE12, PE13

On most board this bus is wired to Camera (CSI) socket

README.sun8i-h3-overlays内でI2C0を検索して辺りを見ると i2c0 そのままの名前がある。
これを/boot/armbianEnv.txtのoverlays行に追加する。
PPS有効化のために既に書かれている内容に追記する形。(黄字部分)

overlays=uart1 pps-gpio i2c0

システムを再起動する。

$ sudo apt install i2c-tools  #i2c-toolsをインストール

$ sudo i2cdetect -y 0
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

     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 -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

0x68(黄字部分)の方がRTCで0x57の方がこのモジュールに載っているeeprom(使わない)

$ lsmod | grep rtc

この時点ではおそらく何も出ない。

$ sudo modprobe -c | grep ds3231
alias i2c:ds3231 rtc_ds1307
alias of:N*T*Cmaxim,ds3231 rtc_ds1307
alias of:N*T*Cmaxim,ds3231C* rtc_ds1307

DS3231専用は無くてDS1307用のAliasになってるみたい。

$ sudo modprobe i2c:ds3231
$ sudo lsmod | grep rtc
rtc_ds1307             28672  0

敢えてi2c:ds3231を指定したが、素直にrtc_ds1307で良いかと。


次にやりたいのはこのコマンドの送信。
echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-0/new_device
$ sudo echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-0/new_device
-bash: /sys/class/i2c-adapter/i2c-0/new_device: Permission denied
怒られた。もちろん、su - や sudo -s でrootになってからなら問題ない。
$ echo ds1307 0x68 | sudo tee /sys/class/i2c-adapter/i2c-0/new_device
これなら一般ユーザーからでもいける。
$ lsmod | grep rtc
rtc_ds1307             28672  0
もういちどlsmodしたところrtc_ds1307が出現している。
$ sudo i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --
0x68がUUになった。(動作中)
$ sudo hwclock -r -f /dev/rtc0
2020-07-15 14:48:15.696917+09:00
$ sudo hwclock -r -f /dev/rtc1
2020-07-15 14:48:28.614543+09:00
少なくとも2秒以内に2つのRTCの時刻を連続表示したが、13秒ほどズレている。
$ ls -l /dev | grep rtc
lrwxrwxrwx 1 root root           4 Feb 14  2019 rtc -> rtc0
crw------- 1 root root    252,   0 Feb 14  2019 rtc0
crw------- 1 root root    252,   1 Jul 15 13:50 rtc1

rtc1が出来ている。これが追加したRTCモジュール。しかし、/dev/rtcは/dev/rtc0にシンボリックリンクになっているのでこれをrtc1に向かせる。

$ sudo ln -f -s /dev/rtc1 /dev/rtc
既存の/dev/rtc0に向いてるのをrtc1に強制張り替え
$ ls -l /dev | grep rtc
lrwxrwxrwx 1 root root           9 Jul 15 14:08 rtc -> /dev/rtc1
crw------- 1 root root    252,   0 Feb 14  2019 rtc0
crw------- 1 root root    252,   1 Jul 15 13:50 rtc1
/etc/rc.local (exit 0の前あたりに挿入)
/usr/sbin/modprobe i2c:ds3231
echo 'ds1307 0x68' > /sys/class/i2c-adapter/i2c-0/new_device
ln -f -s /dev/rtc1 /dev/rtc   
hwclock -f /dev/rtc1 -s

追加したRTCモジュールが使えているのは確かなようだが、「なんちゃってRTC」からの切り替えがこれでできてるのかな? なんかイマイチ確信が持てない。

あと、さきほどlsmodした結果が要らないモジュールだらけだったので対応。
$ lsmod
Module                  Size  Used by
rtc_ds1307             28672  0
zstd                   16384  4
zram                   24576  2
zsmalloc               20480  1 zram
snd_soc_simple_card    20480  0
sun8i_codec_analog     24576  0
snd_soc_simple_card_utils    20480  1 snd_soc_simple_card
sun4i_i2s              24576  0
sun8i_adda_pr_regmap    16384  1 sun8i_codec_analog
sunxi_cedrus           32768  0
snd_soc_core          131072  4 sun4i_i2s,sun8i_codec_analog,snd_soc_simple_card_utils,snd_soc_simple_card
v4l2_mem2mem           20480  1 sunxi_cedrus
ac97_bus               16384  1 snd_soc_core
videobuf2_dma_contig    20480  1 sunxi_cedrus
snd_pcm_dmaengine      16384  1 snd_soc_core
videobuf2_memops       20480  1 videobuf2_dma_contig
videobuf2_v4l2         20480  2 sunxi_cedrus,v4l2_mem2mem
snd_pcm                69632  3 sun4i_i2s,snd_pcm_dmaengine,snd_soc_core
sun4i_gpadc_iio        16384  0
videobuf2_common       36864  3 sunxi_cedrus,v4l2_mem2mem,videobuf2_v4l2
industrialio           53248  1 sun4i_gpadc_iio
snd_timer              28672  1 snd_pcm
videodev              151552  4 sunxi_cedrus,videobuf2_common,v4l2_mem2mem,videobuf2_v4l2
snd                    49152  3 snd_timer,snd_soc_core,snd_pcm
sun8i_thermal          16384  0
soundcore              16384  1 snd
mc                     36864  5 sunxi_cedrus,videobuf2_common,videodev,v4l2_mem2mem,videobuf2_v4l2
sun4i_tcon             28672  0
sun8i_mixer            36864  0
sun8i_tcon_top         16384  1 sun4i_tcon
evdev                  20480  1
pps_gpio               16384  1
uio_pdrv_genirq        16384  0
uio                    16384  1 uio_pdrv_genirq
cpufreq_dt             20480  0
usb_f_acm              20480  1
u_serial               24576  3 usb_f_acm
g_serial               16384  0
libcomposite           45056  2 g_serial,usb_f_acm
ip_tables              24576  0
x_tables               24576  1 ip_tables
autofs4                36864  2
fixed                  20480  2
gpio_keys              20480  0
sndとかv4l2などが目立つかな。
/etc/modprobe.d/にはblacklist-nanopineo.confがあったので今回は新しくファイルは作らずにそのファイルに追記。
blacklist lima   #もともと入ってた

blacklist ac97_bus
blacklist mc
blacklist snd
blacklist snd_pcm
blacklist snd_pcm_dmaengine
blacklist snd_soc_core
blacklist snd_soc_simple_card
blacklist snd_soc_simple_card_utils
blacklist snd_timer
blacklist sun4i_i2s
blacklist sun8i_adda_pr_regmap
blacklist sun8i_codec_analog
blacklist sunxi_cedrus
blacklist v4l2_mem2mem
blacklist videobuf2_common
blacklist videobuf2_v4l2
blacklist videodev

起動中のシステムから手動で外すなら modprobe -r ac97_bus など。ただし、撥ねられるかも。

再起動するとこんな感じ
$ lsmod
Module                  Size  Used by
zstd                   16384  4
zram                   24576  2
zsmalloc               20480  1 zram
sun4i_gpadc_iio        16384  0
industrialio           53248  1 sun4i_gpadc_iio
sun8i_thermal          16384  0
sun4i_tcon             28672  0
sun8i_tcon_top         16384  1 sun4i_tcon
sun8i_mixer            36864  0
evdev                  20480  1
pps_gpio               16384  1
uio_pdrv_genirq        16384  0
uio                    16384  1 uio_pdrv_genirq
cpufreq_dt             20480  0
rtc_ds1307             28672  0
usb_f_acm              20480  1
u_serial               24576  3 usb_f_acm
g_serial               16384  0
libcomposite           45056  2 g_serial,usb_f_acm
ip_tables              24576  0
x_tables               24576  1 ip_tables
autofs4                36864  2
fixed                  20480  2
gpio_keys              20480  0

うん、だいぶスッキリ。

今回はNTPサーバにRTCモジュールを付けたけど目に見えるような効果あるかしら?ntpdで統計情報を録っているので暫く動かして何か変わるか様子を見る予定。

関連記事: