脳汁portal

アメリカ在住(だった)新米エンジニアがその日学んだIT知識を書き綴るブログ

low voltage detected, date/time is not reliable.

エラー文

RaspberryPiでRTCから時刻合わせをしようとすると以下のようなエラーが出ることがある。

Jan 01 23:11:11 raspberrypi kernel: [  131.098038] rtc-pcf8563 1-0051: low voltage detected, date/time is not reliable. 

ちなみに使ったRTCはこちら
リアルタイムクロック(RTC)モジュール: 半導体 秋月電子通商 電子部品 ネット通販
f:id:portaltan:20170113194609j:plain
エラーの意味としては『電圧低下が検知されたよ。だから今の時刻データは信頼できないよ。』って感じの警告だ。

調査

アプリケーションノートを読んでみると、RTCへの電源供給の電圧が一定以下になった場合、VLflag(Voltage Low Flag)が立つらしい。
f:id:portaltan:20170113100032p:plain

対応

ちなみにこのVLフラグは秒数を管理しているメモリ区域で管理されている
f:id:portaltan:20170113100209p:plain

なので上記のエラー文を出したくなければ、VLフラグを0クリアしてやればエラーは出なくなる。

RubyのThreadのステータスに関して

class Thread (Ruby 2.4.0)
instance method Thread#status (Ruby 2.4.0)
instance method Thread#alive? (Ruby 2.4.0)

Rubyのスレッドに関して各ケースのステータスまとめ

各項目がとる値

  • thread object(thread.inspect)
    • run
    • sleep
    • aborting
    • dead
  • thread.status
    • run
    • sleep
    • false
    • nil
  • thread.alive?
    • true
    • false

調査

通常時(スレッドが生きているとき)

ソース
t1 = Thread.start{
  loop do
    sleep 1
  end
}

loop do
  p t1 # run, sleep, aborting, dead
  puts t1.status || t1.status.class # run, sleep, false, nil
  puts t1.alive? # true, false
  puts "--------------------------------"
  sleep 1
end
実行結果
#<Thread:0x55e80d30 sleep>
run
true
--------------------------------
#<Thread:0x55e80d30 sleep>
run
true
--------------------------------
#<Thread:0x55e80d30 sleep>
run
true
--------------------------------
各ステータス
  • thread object : (run), sleep
  • thread.status : run, (sleep)
  • thread.alive? : true

正常終了時

ソース
t1 = Thread.start{
  2.times{|n|
    sleep 1
    puts n+1
  }
}

loop do
  p t1
  puts t1.status || t1.status.class # run, sleep, aborting, false, nil
  puts t1.alive? # true, false
  puts "--------------------------------"
  sleep 1
end
実行結果
#<Thread:0x566a0c48 run>
sleep
true
--------------------------------
1
#<Thread:0x566a0c48 sleep>
sleep
true
--------------------------------
2
#<Thread:0x566a0c48 dead>
FalseClass
false
--------------------------------
#<Thread:0x566a0c48 dead>
FalseClass
false
--------------------------------
#<Thread:0x566a0c48 dead>
FalseClass
false
--------------------------------
各ステータス
  • thread object : dead
  • thread.status : false
  • thread.alive? : false

異常終了時

ソース
t1 = Thread.start{
  2.times{|n|
    sleep 1
    puts n+1
  }
  raise
}

loop do
  p t1
  puts t1.status || t1.status.class # run, sleep, aborting, false, nil
  puts t1.alive? # true, false
  puts "--------------------------------"
  sleep 1
end
実行結果
#<Thread:0x558e8bf0 run>
sleep
true
--------------------------------
#<Thread:0x558e8bf0 run>
sleep
1
true
--------------------------------
#<Thread:0x558e8bf0 run>
2
sleep
false
--------------------------------
#<Thread:0x558e8bf0 dead>
NilClass
false
--------------------------------
#<Thread:0x558e8bf0 dead>
NilClass
false
各ステータス
  • thread object : dead
  • thread.status : nil
  • thread.alive? : false

まとめると

  • thread.statusはスレッドが生きている間はrunかsleepで、正常終了するとfalseになり、異常終了するとnilになる
  • thread.alive?はスレッドが生きている間はtrueで、終了すると正常・異常に関わらずfalseになる
  • thread情報を直接見ると、スレッドが生きている場合はrunかsleepで、終了処理中はabortingになり、完全に終了するとdeadになる

raspberryPiでRTCを使おうとしたときにargument Errorになる

前提条件として、raspberryPiにはRTCがついていないため、シャットダウンしてしまうと時間を保持しておくことが出来ない。

なので通常は起動時にntpでシステムの時刻をあわせるのだが、当然インターネット環境がない場合はその時間合わせをすること自体が出来ない。

そういう場合などのために個別にRTCを取り付けることが出来るのだが、以下のようにエラーが出てRTCへアクセスが出来ないことがたまにある。

hwclock: ioctl(RTC_RD_TIME) to /dev/rtcX to read the time failed: Invalid argument

調べていくと割とメジャーなつまづきポイントらしい。
Raspberry Pi • View topic - Wierd RTC(ds1307) problem

調べていくとfake_hwclockというものが悪さをしているらしく、上の方でraspberryPiにはRTC(hwclock)はついていないといったのだが、その代わりにのっているのがfake_hwclockらしい。

これは何かというと、普通ならば時刻データを保持できないのでネット環境がない場合は起動するたびに初期値の1970年1月1日0時0分0秒になってしまうのだが、
このfake_hwclockというシステムが有効化されていると、起動している時間を定期的(shutdown時にも?)にtxtとして保存しておき、次回起動時にこの時間を現在時刻として
使おうという機能である。

今回は本物のhwclockであるRTCとこのfake_hwclockが競合してしまったために上記のエラーが出たものと思われる。
解決方法としてはこいつを無効化してやればよい。

sudo update-rc.d fake-hwclock disable

これで競合することはなくなり、上記のエラーが出ることもなくなった。

raspberryPi3のIPを固定する方法(static ip)

raspberryPiは通常自動でIPをアサインしてくれますが、それでは困る場合などに固定IPアドレスにする方法です。
raspbianのversion upに伴い、raspberryPi2の時とは方法が変わっているようです。

ちなみにversionは8.0です

$ cat /etc/debian_version
8.0

/etc/network/interfacesの確認

$ cat /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto lo
iface lo inet loopback

iface eth0 inet manual

allow-hotplug wlan0
iface wlan0 inet manual
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

allow-hotplug wlan1
iface wlan1 inet manual
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

上のほうのコメントを見ると、staticIPにするにはdhcpcd.confを編集すればよいことがわかります。
とりあえず書かれている通りにmanを見ます

$ man dhcpcd.conf
     static value
             Configures a static value.  If you set ip_address then dhcpcd will not attempt to obtain a lease
             and just use the value for the address with an infinite lease time.

             Here is an example which configures a static address, routes and dns.
                   interface eth0
                   static ip_address=192.168.0.10/24
                   static routers=192.168.0.1
                   static domain_name_servers=192.168.0.1

             Here is an example for PPP which gives the destination a default route.  It uses the special desti-
             nation keyword to insert the destination address into the value.
                   interface ppp0
                   static ip_address=
                   destination routers

staticで検索すると上記のような記入例が出てくるので、自分のIPに変更して実際に書き込みます

/etc/dhcpcd.confの編集

$ vi /etc/dhcpcd.conf
### ファイル末尾に追加
interface eth0
static ip_address=192.168.0.10/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1

### wifi(wlan0)の場合は
interface wlan0
.
.
.

これで完了です。
後はraspberryPiを再起動して設定したIPでアクセスできることが確認できればOKです。

raspberryPi3へWiringPiGPIOを設定する手順

GPIO:General Purpose Input/Output

$ git clone git://git.drogon.net/wiringPi
  Cloning into 'wiringPi'...
  .
  .
  .
  Checking connectivity... done.

$ ls -l
  total 4
  drwxr-xr-x 10 pi pi 4096 Nov 29 15:10 wiringPi

$ cd wiringPi/

./build
  wiringPi Build script
  .
  .
  .
  All Done.
  .
  .
  .

$ gpio -v
  gpio version: 2.32
  Copyright (c) 2012-2015 Gordon Henderson
  This is free software with ABSOLUTELY NO WARRANTY.
  For details type: gpio -warranty
 
  Raspberry Pi Details:
    Type: Pi 3, Revision: 02, Memory: 1024MB, Maker: Embest
    * Device tree is enabled.
    * This Raspberry Pi supports user-level GPIO access.
      -> See the man-page for more details
      -> ie. export WIRINGPI_GPIOMEM=1

Rubyでシリアル通信する方法(serialport gem)

Rubyでシリアル通信する場合は、serialport gemを使うと簡単にできます。

install serial port

$ gem install serialport

How to Use

require 'serialport'

sp = SerialPort.new('/dev/ttyS0', 115200, 8, 1, 0) # device, rate, data, stop, parity

# 送信
sp.puts("foobar")

# 受信
sp.gets
sp.readline.chomp.strip # こっちだと空白とか余分な情報をそぎ落としてくれる