NanoPi NEOの時刻のズレを直したい

時計

5つ前のPPSの記事でやったようなことで普通のPCならPPSを時刻ソースとしてNTPサーバが一応正常に動く筈なんだけど、NanoPi NEOだと数分でNMEAとPPSの両方の同期が切れてしまう。
でも、ネットワーク上の他のNTPサーバとの同期は切れないんだよなぁ。そこが解せん。
何故かなと調べてたらRTCの時刻のズレ方がとんでもない凄さ。使用中なら20分で5分、アイドル状態放置でも8時間で45分ほどズレてしまう。RTCの時刻を表示する度にどんどんズレてくのでウワァって感じ。カーネルビルドのオプション指定間違えてるのだろうか?

# ppswatch -a /dev/pps0
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
timestamp: 1490575231, sequence: 37551, offset:  1276715
timestamp: 1490575232, sequence: 37552, offset:  1279569

眺めているとoffsetの値が急激に増大または減少する。さらには増大してるかと思ったら突然減少に反転、或いはその反対ということも起こる。これはおかしい?
RTCを狂わせてる原因は何かしら?

$ lsmod
Module                  Size  Used by
cfg80211              192770  0 
bluetooth             263753  0 
rfkill                 10928  2 bluetooth,cfg80211
evdev                   9979  0 
sun8i_ths               3134  0 
gpio_keys               8517  0 
cpufreq_dt              3522  0 
uio_pdrv_genirq         3354  0 
uio                     8012  1 uio_pdrv_genirq
thermal_sys            43232  2 cpufreq_dt,sun8i_ths
pps_gpio                2897  1 
g_serial                3737  0 
libcomposite           34692  1 g_serial
fuse                   70718  1 

どう見てもcfg80211やbluetoothなど幾つかは要らない。
そこで /etc/modprobe.d/fbdev-blacklist.conf に追記

1
2
3
blacklist bluetooth
blacklist cfg80211
blacklist evdev
# systemctl list-unit-files
UNIT FILE                                  STATE
中略
bluetooth.service                          enabled
中略
dbus-org.freedesktop.nm-dispatcher.service enabled
中略
fake-hwclock.service                       enabled
後略

こいつらも停めてしまうことにする。

# systemctl stop bluetooth.service
# systemctl disable  bluetooth.service
# systemctl stop dbus.service
# systemctl disable dbus.service
# systemctl stop fake-hwclock.service
# systemctl disable fake-hwclock.service

さて、一番アヤシイのはCPUのクロックがコロコロ変わること。これを固定させたい。
まずは状態を確認。

$ cpufreq-info
cpufrequtils 008: cpufreq-info (C) Dominik Brodowski 2004-2009
Report errors and bugs to cpufreq@vger.kernel.org, please.
analyzing CPU 0:
  driver: cpufreq-dt
  CPUs which run at the same hardware frequency: 0 1 2 3
  CPUs which need to have their frequency coordinated by software: 0 1 2 3
  maximum transition latency: 4.24 ms.
  hardware limits: 120 MHz - 1.01 GHz
  available frequency steps: 120 MHz, 240 MHz, 312 MHz, 480 MHz, 624 MHz, 816 MHz, 1.01 GHz
  available cpufreq governors: conservative, ondemand, userspace, powersave, performance, schedutil
  current policy: frequency should be within 816 MHz and 816 MHz.
                  The governor "performance" may decide which speed to use
                  within this range.
  current CPU frequency is 816 MHz (asserted by call to hardware).
  cpufreq stats: 120 MHz:0.00%, 240 MHz:0.00%, 312 MHz:0.00%, 480 MHz:0.01%, 624 MHz:0.00%, 816 MHz:97.42%, 1.01 GHz:2.58%  (2)

以下、CPUのコア数分の表示が行われる。

CPUのクロックは120 MHz, 240 MHz, 312 MHz, 480 MHz, 624 MHz, 816 MHz, 1.01 GHzが指定できると書かれているが、1.01GHzは数字を丸めたっぽい。

$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
120000 240000 312000 480000 624000 816000 1008000

指定可能な最大のクロックは1008000だ。←指定するときはこの数字でないと弾かれる(というか指定可能などれか近いのになる)

# cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
conservative ondemand userspace powersave performance schedutil

使用可能なガバナーは6つ、これはcpufreq-infoまたはcpufreq-info -gで表示されるものと同じ。

システム起動中の指定変更にはcpufreq-setを使うということになっているが、システム起動時用の設定ファイルとしては/etc/default/cpufrequtilsが用意されているようだ。

1
2
3
4
ENABLE=true
MIN_SPEED=0
MAX_SPEED=0
GOVERNOR=performance

システムを再起動してみる。

現在の設定を確認する。

# cpufreq-info -p
120000 1008000 performance

表示上は最低クロックが12000最大クロックが1008000となっているが、ガバナーが指定された最大値固定のperformanceなので1008000以外にはならない(ことになっている)。

暫く使った後に本当にクロックが固定されているか確認する。

# cpufreq-info -s
120000:0, 240000:0, 312000:0, 480000:0, 624000:0, 816000:0, 1008000:33629  (1)

1008000以外の使用が0ということなので固定されていると見てよさそう。クロックの後の数字の単位は不明。

1
2
3
4
ENABLE=true
MIN_SPEED=0
MAX_SPEED=816000
GOVERNOR=performance

最大速度を中間の値(816000)で指定してみた。

$ cpufreq-info -s
120000:0, 240000:0, 312000:0, 480000:2, 624000:0, 816000:14583, 1008000:439  (2)

816000以外で動かない筈だが、システム起動中の固定設定になる前に1008000で動いた時間があるようだ。480000にも2というのがあるがこれは無視して良さそう。
もちろん、performanceガバナーが有効になった後は816000以外では動かないはずなのでこの後にcpufreq-info -sで表示すると816000以外では数値は増えない(筈)。

同様にMIN_SPEEDを指定してpowersaveガバナーを使用するとMIN_SPEEDのクロックで固定される。MIN_SPEEDが0なら選択可能な一番低いクロックで固定。

ondemandとconservativeガバナーを選択した場合はクロックの切り替わりの挙動が異なるようだが、どちらも負荷に応じてMIN_SPEEDからMAX_SPEEDの間でクロック可変となる。MIN_SPEEDとMAX_SPEEDを0指定にしていれば選択可能な一番低いクロックから選択可能な一番高いクロックの間で可変。

で、NanoPi NEOのCPU(っていうかH3の)のカタログスペック上の最大値って1.2GHz (1200000)じゃなかったっけ?
以前の記事の古いカーネルでは1.2GHzまで使えたけどカーネル4.10系では2017年3月30日時点では1GHzまでらしい。
もっともクロック最大でブン回すと熱が出るのでこの手のSBCだと寧ろ使用する機能に影響しない範囲で如何に低いクロックを設定するかに苦心するところだろうけど。

さて、CPUクロックを固定してみたが、RTCのズレ具合は改善しただろうか?

全然ダメ

殆ど全くというレベルで改善していない。何だろうCPU動くたびに仕事量に応じてズレてるとしか思えない。

そういえばtimedatectlにRTCをNTPに同期させてくれる機能ってのが付いてたような。

$ timedatectl status
      Local time: Tue 2017-03-30 13:04:38 JST
  Universal time: Tue 2017-03-30 04:04:38 UTC
        RTC time: Tue 2017-03-30 04:04:38
       Time zone: Asia/Tokyo (JST, +0900)
     NTP enabled: no
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a


# timedatectl set-ntp yes   ←RTCをNTPに同期させる


$ timedatectl status
      Local time: Tue 2017-03-30 13:04:58 JST
  Universal time: Tue 2017-03-30 04:04:58 UTC
        RTC time: Tue 2017-03-30 04:04:57
       Time zone: Asia/Tokyo (JST, +0900)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: no
      DST active: n/a

表示上はRTCの時刻のズレ方がメチャクチャというのは直った。でも、ぴったり合うというわけでもないみたい。
そして、相変わらずNTPのソースとしてのNMEAとPPSは同期してくれない、もしくは同期してもすぐに切れてそのまま。
やはり見かけじゃない部分でRTC自体がズレていて本来正しい方のNMEAとPPSの時刻を異常と思って同期を切ってると考えるのが正しいよねぇ。でも、他のNTPサーバとの同期は切れないのは何で?
こうなるとRTCモジュールを買ってみるしかない?でも負けたみたいで嫌だなぁ。
引き続き他の対策も考えたい。

関連記事: