Technical Information/Raspberry Pi
ラズベリーパイ用RTC+電源ボタンユニットの作成
2019/01/26
ラズベリーパイにRTCと電源ボタンをもつアドオンボードを作りました。シャットダウン後ラズベリーパイへの5V電源供給をカットして電源の電力消費を抑えます。シャットダウン処理後、緑色LEDの点滅が終了してから5V電源をカットする安心設計です。
回路図
部品構成
- ラズベリーパイ3 model B
- 自作基板
※C1,C3,C4,C5,CN2,D2,D3,R2,R4,R13,U1は実装しない
ソフトウェア構成
- ラズベリーパイ:Raspbian GNU/Linux 9.6 (stretch)
- AVRマイコン:AVR/GNU C Compiler (Atmel Studio 7)
機能
- 日時情報のバックアップ
- OSの起動時にインターネットに接続されている場合はntpによる時刻取得およびRTCの更新を行う
- OSの起動時にインターネットに接続されていない場合はRTCの保持している時刻をシステム時刻に設定する
- 電源ボタン押下(0.5秒以上の長押し)による自動シャットダウンおよび5V電源カット
- 電源ボタン押下による電源接続およびシステムの起動
導入方法
※ラズベリーパイをインターネットに繋いだ状態で作業してください
- 予めAVRマイコンにソフトウェアを書き込んでおき、アドオンボードに実装する。ソフトウェアの内容は以下のとおり:
/*
* test07.c
*
* Created: 2018/12/20 2:44:00
* Author : wdn
*/
// [PB0,PB1,PB2]
#define P_UP 0 // 最初に電源が投入された状態。 HV_FETがOFF [L ,L ,L ]
#define P_SET 1 // P_UPの状態でパワーSWが押され、ラズパイが起動中の状態 [H/L,L ,H ]
#define P_RUN 2 // ラズパイが起動を完了し、BCM17からHが出力中の状態 [L ,H ,H ]
// PB0 : パワーSW入力 SW押下時にH
// PB1 : 生存信号入力 BCM17へ接続 OS起動時H
// PB2 : MOSFET駆動信号 Hで 5V on
#include <avr/io.h>
#include <util/delay.h> // for _delay() func
#include <avr/interrupt.h> // for interrupt func
#include <avr/sleep.h> // for sleep func
volatile int Status;
ISR(PCINT0_vect)
{
char port;
port = ~PINB; // PORTB の内容を変数 port に格納
if (Status == P_UP){ // [外部電源投入直後 or シャットダウン後]
if((port & (1<<PORTB0)) == (1<<PORTB0)){ // 変化後のPORTB0 の状態がLの場合は
; // 何もしない
} else { // 変化後のPORTB0 の状態がHの場合は
_delay_ms(1); // チャタリング対策で1ms待つ
if((~PINB & (1<<PORTB0)) != (1<<PORTB0)){ // 1ms後のPORTB0 の状態がHの場合は
PORTB |= (1 << PORTB2); // PORTB2 の出力をHに設定
//Status = P_SET; // 状態を P_SET に変更
//_delay_ms(1000); // 3.3Vが起動するまで1秒待つ
Status = P_RUN; // 状態を P_RUN に変更
}
}
}
else if (Status == P_SET){ // [パワースイッチ押下後のセットアップ中]
if((port & (1<<PORTB1)) == (1<<PORTB1)){ // 変化後のPORTB1 の状態がLの場合は
; // 何もしない
} else { // 変化後のPORTB1 の状態がHの場合は
Status = P_RUN; // 状態を P_SET に変更
}
}
else if (Status == P_RUN){ // [OS起動後の動作状態にて]
if((port & (1<<PORTB1)) == (1<<PORTB1)){ // 変化後のPORTB1 の状態がLの場合は
_delay_ms(1); // チャタリング対策で1ms待つ
if((~PINB & (1<<PORTB1)) == (1<<PORTB1)){ // 1ms後のPORTB1 の状態がLの場合は
_delay_ms(10000); // SDカードアクセス終了まで約10秒間待機
PORTB &= ~(1 << PORTB2); // PORTB2 の出力をLに設定
Status = P_UP; // 状態を P_UPに設定
}
} else { // 変化後のPORTB1 の状態がHの場合は
; // 何もしない
}
}
PCIFR = (1 << PCIE0); // 割り込み発生中に発生したピン変化割り込み要求をクリア
}
int main(void)
{
CCP = 0xD8; // 書き込み保護レジスタのセット
CLKMSR = 0x00; // メインクロック = 内蔵8MHz発振器
CCP = 0xD8; // 書き込み保護レジスタのクリア
CLKPSR = 0x00; // クロック分周レジスタ設定 prescale = 1;
DDRB = (1 << PORTB2); // ポートB方向レジスタ:PORTB2のみ出力に
PORTB &= ~(1 << PORTB2); // PORTB2 の出力をLに設定
Status = P_UP; // 状態を初期化
_delay_ms(500); // 電源投入時のチャタリング対策
// ポート変化割り込みの許可
PCICR = (1 << PCIE0); // ピン変化割り込み制御レジスタをセット
PCMSK = (1<<PCINT0)|(1<<PCINT1); // PCINT0, PCINT1を有効化
set_sleep_mode(SLEEP_MODE_PWR_DOWN);// sleepモードを POWER DOWN に設定
sei(); // 全割り込み許可
/* Replace with your application code */
while (1)
{
sleep_mode();
}
return 0;
}
- PORTB0のチャタリング:電源ボタン押下時のチャタリング
- PORTB1のチャタリング:BCM17ピンの出力設定時一瞬Lレベルが出力される現象
- 状態P_SET は使用しない(理由は・・・お考えください)
なお、AVR/GNU C Compiler の Symbols にCPUクロックを定義しておく
F_CPU=8000000UL
- アドオンボードをラズベリーパイのGPIO端子に装着し、ラズベリーパイの電源コネクタ(Micro USBコネクタ)ではなく、今回作成したアドオンボード上のMicroUSBコネクタ(CN3)に5V電源供給用のUSBケーブルを接続する。その後電源ボタン(S1)を押してラズベリーパイを起動する。
- シャットダウンボタンのドライバをインストールする。
- シャットダウン時のみBCM17ピンをL出力させるために、オーバレイ機能を上書きする。まずは上書き動作のスクリプトを作成する。
pi@raspberrypi:~ $ sudo vi /lib/systemd/system-shutdown/gpio-poff
スクリプトの内容は以下:
#! /bin/sh
# file: /lib/systemd/system-shutdown/gpio-poff
# $1 will be either "halt", "poweroff", "reboot" or "kexec"
poff_pin="17"
case "$1" in
poweroff)
if [ "$poff_pin" = "" ]; then
/bin/echo "Skipping power off" && exit 0
else
/bin/echo "Power off pin $poff_pin"
fi
/bin/echo $poff_pin > /sys/class/gpio/export
/bin/echo out > /sys/class/gpio/gpio$poff_pin/direction
/bin/echo 0 > /sys/class/gpio/gpio$poff_pin/value
/bin/sleep 0.5
;;
esac
:
- 次に作成したスクリプトに実行可能属性を設定する
pi@raspberrypi:~ $ sudo chmod 755 /lib/systemd/system-shutdown/gpio-poff
- オーバレイ機能を上記のスクリプトで上書きする設定を、config.txtの最後に追記する。
pi@raspberrypi:~ $ sudo vi /boot/config.txt
追記する内容は以下の通り:
# Enable gpio-poff (user custom script)
dtoverlay=gpio-poff
- 続いて、電源ボタン押下によるシャットダウン制御のスクリプトを作成。ここでは /home/pi/script/shutdown.pyとする。
pi@raspberrypi:~ $ vi ./script/shutdown.py
スクリプトの内容は以下の通り:
#!/usr/bin/python
# coding:utf-8
import time
import RPi.GPIO as GPIO
import os
pinnumber=4
GPIO.setmode(GPIO.BCM)
#GPIO17pinを出力モードとし、Hレベルを出力する
GPIO.setup(17,GPIO.OUT)
GPIO.output(17,GPIO.HIGH)
# GPIO4pinを入力モードにする
# 外部プルアップのため、pull up設定をoffにする
GPIO.setup(pinnumber,GPIO.IN,pull_up_down=GPIO.PUD_OFF)
while True:
GPIO.wait_for_edge(pinnumber, GPIO.FALLING)
sw_counter = 0
while True:
sw_status = GPIO.input(pinnumber)
if sw_status == 0:
sw_counter = sw_counter + 1
if sw_counter >= 5:
print("Detect long-pressing the BCM4 button for 0.5 seconds.")
os.system("sudo shutdown -h now")
break
else:
print("Detect short-pressing the BCM4 button.")
break
time.sleep(0.1)
print(sw_counter)
- ファイルに実行可能属性を設定する
pi@raspberrypi:~/script $ sudo chmod 755 shutdown.py
- サービスファイルを作成
pi@raspberrypi:~/script $ sudo vi /usr/lib/systemd/system/shutdownbutton.service
ファイルの編集内容は以下のとおり:
[Unit]
Description=Shutdown Daemon
[Service]
ExecStart =/home/pi/script/shutdown.py
Restart=always
Type=simple
[Install]
WantedBy=multi-user.target
- サービスの有効化(これで再起動時に自動的にスクリプトが実行される)
pi@raspberrypi:~ $ sudo systemctl enable shutdownbutton.service
- デーモンを再起動
pi@raspberrypi:~ $ sudo systemctl daemon-reload
- 一旦リブート
pi@raspberrypi:~ $ sudo reboot
- サービスの状態を確認 (loaded & active であることを確認する)
pi@raspberrypi:~ $ systemctl status shutdownbutton.service
● shutdownbutton.service - Shutdown Daemon
Loaded: loaded (/usr/lib/systemd/system/shutdownbutton.service; enabled; vend
Active: active (running) since Sat 2018-10-27 16:32:00 JST; 3min 1s ago
Main PID: 973 (shutdown.py)
CGroup: /system.slice/shutdownbutton.service
mq973 /usr/bin/python /home/pi/script/shutdown.py
10月 27 16:32:00 raspberrypi systemd[1]: Started Shutdown Daemon.
- 動作確認
- ラズベリーパイの電源コネクタ(Micro USBコネクタ)ではなく、今回作成したアドオンボード上のMicroUSBコネクタ(CN3)に5V電源供給用のUSBケーブルを接続する。この状態ではラズベリーパイの電源が入らないことを確認。
- 電源ボタン(S1)を押すと赤色LEDが点灯しラズベリーパイに電源が投入され、システムが起動することを確認。
- 電源ボタン(S1)の0.5秒未満の短押しではシャットダウンが動作せず、0.5秒以上の長押しで即座にシャットダウン動作が開始され、シャットダウン終了後ラズベリーパイの緑色LEDの点滅が終了した後に赤色LEDが消灯することを確認。
- 再び電源ボタン(S1)を押し、システムを起動する。つづいてターミナルよりリブートを行う。
pi@raspberrypi:~ $ sudo reboot
ラズベリーパイの電源が切れることなく、システムがリブートされることを確認する。
- RTCのドライバをインストール
- i2cdetect コマンドにて、接続されているi2cデバイスののアドレスを確認
pi@raspberrypi:~ $ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- 32 -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
- ドライバが有るかどうか確認。 rx-8025が存在。
pi@raspberrypi:~ $ ls -l /lib/modules/$(uname -r)/kernel/drivers/rtc/
合計 436
-rw-r--r-- 1 root root 16552 9月 25 18:07 rtc-abx80x.ko
-rw-r--r-- 1 root root 10912 9月 25 18:07 rtc-bq32k.ko
-rw-r--r-- 1 root root 8436 9月 25 18:07 rtc-ds1302.ko
-rw-r--r-- 1 root root 13308 9月 25 18:07 rtc-ds1305.ko
-rw-r--r-- 1 root root 29676 9月 25 18:07 rtc-ds1307.ko
-rw-r--r-- 1 root root 11624 9月 25 18:07 rtc-ds1374.ko
-rw-r--r-- 1 root root 8324 9月 25 18:07 rtc-ds1390.ko
-rw-r--r-- 1 root root 8892 9月 25 18:07 rtc-ds1672.ko
-rw-r--r-- 1 root root 14576 9月 25 18:07 rtc-ds3232.ko
-rw-r--r-- 1 root root 7612 9月 25 18:07 rtc-em3027.ko
-rw-r--r-- 1 root root 9964 9月 25 18:07 rtc-fm3130.ko
-rw-r--r-- 1 root root 9300 9月 25 18:07 rtc-isl12022.ko
-rw-r--r-- 1 root root 17524 9月 25 18:07 rtc-isl1208.ko
-rw-r--r-- 1 root root 19760 9月 25 18:07 rtc-m41t80.ko
-rw-r--r-- 1 root root 8728 9月 25 18:07 rtc-m41t93.ko
-rw-r--r-- 1 root root 7876 9月 25 18:07 rtc-m41t94.ko
-rw-r--r-- 1 root root 7680 9月 25 18:07 rtc-max6900.ko
-rw-r--r-- 1 root root 6956 9月 25 18:07 rtc-max6902.ko
-rw-r--r-- 1 root root 10808 9月 25 18:07 rtc-pcf2123.ko
-rw-r--r-- 1 root root 13096 9月 25 18:07 rtc-pcf2127.ko
-rw-r--r-- 1 root root 8624 9月 25 18:07 rtc-pcf8523.ko
-rw-r--r-- 1 root root 14016 9月 25 18:07 rtc-pcf8563.ko
-rw-r--r-- 1 root root 8008 9月 25 18:07 rtc-pcf8583.ko
-rw-r--r-- 1 root root 7996 9月 25 18:07 rtc-r9701.ko
-rw-r--r-- 1 root root 8260 9月 25 18:07 rtc-rs5c348.ko
-rw-r--r-- 1 root root 15308 9月 25 18:07 rtc-rs5c372.ko
-rw-r--r-- 1 root root 18664 9月 25 18:07 rtc-rv3029c2.ko
-rw-r--r-- 1 root root 8468 9月 25 18:07 rtc-rx4581.ko
-rw-r--r-- 1 root root 12112 9月 25 18:07 rtc-rx8025.ko
-rw-r--r-- 1 root root 9884 9月 25 18:07 rtc-rx8581.ko
-rw-r--r-- 1 root root 11764 9月 25 18:07 rtc-s35390a.ko
-rw-r--r-- 1 root root 13880 9月 25 18:07 rtc-x1205.ko
- RX-8025をOSで管理できるように設定する
まず、modprobe コマンドで、対象のモジュール(i2c-devおよびrtc-rx8025)をロードする。つづいて、先程調べた RX-8025のi2cアドレスをOSが新しく管理するデバイスとして設定する。もう一度i2cdetect コマンドを実行し、RX-8025がOSに管理されていることを確認する。(UUが表示されればOK)
pi@raspberrypi:~ $ sudo su
root@raspberrypi:/home/pi# modprobe i2c-dev
root@raspberrypi:/home/pi# modprobe rtc-rx8025
root@raspberrypi:/home/pi# echo rx8025 0x32 > /sys/class/i2c-adapter/i2c-1/new_device
root@raspberrypi:/home/pi# exit
exit
pi@raspberrypi:~ $ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- UU -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
- 時刻の自動更新を行えるように、fake-hwclockを無効にする
pi@raspberrypi:~ $ sudo apt-get purge fake-hwclock
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下のパッケージは「削除」されます:
fake-hwclock*
アップグレード: 0 個、新規インストール: 0 個、削除: 1 個、保留: 0 個。
この操作後に 32.8 kB のディスク容量が解放されます。
続行しますか? [Y/n] Y
(データベースを読み込んでいます ... 現在 84579 個のファイルとディレクトリがインストールされて います。)
fake-hwclock (0.11+rpt1) を削除しています ...
man-db (2.7.6.1-2) のトリガを処理しています ...
(データベースを読み込んでいます ... 現在 84573 個のファイルとディレクトリがインストールされて います。)
fake-hwclock (0.11+rpt1) の設定ファイルを削除しています ...
systemd (232-25+deb9u6) のトリガを処理しています ...
pi@raspberrypi:~ $
- RTCに、現在のOSのシステムクロックの時刻を書き込む
pi@raspberrypi:~ $ sudo hwclock -w
- ブートごとにRTCの更新処理を行うスクリプトを作成する
pi@raspberrypi:~ $ sudo vi /etc/rc.local
編集内容は以下のとおり。exit 0 の前に、# RTC Settings から始まるスクリプトを追加する。
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
# RTC Settings
modprobe rtc-rx8025
echo rx8025 0x32 > /sys/class/i2c-adapter/i2c-1/new_device
sleep 1
/sbin/hwclock -s
sleep 15
/usr/sbin/ntpdate -b ntp.nict.jp && /sbin/hwclock -w
exit 0
- ブート時にRTCの初期化を行わないように/etc/default/hwclock を編集
pi@raspberrypi:~ $ sudo vi /etc/default/hwclock
変更内容は、 HWCLOCKACCESS=yes を HWCLOCKACCESS=no に変更するだけ。
# Defaults for the hwclock init script. See hwclock(5) and hwclock(8).
# This is used to specify that the hardware clock incapable of storing
# years outside the range of 1994-1999. Set to yes if the hardware is
# broken or no if working correctly.
#BADYEAR=no
# Set this to yes if it is possible to access the hardware clock,
# or no if it is not.
#HWCLOCKACCESS=yes
HWCLOCKACCESS=no
# Set this to any options you might need to give to hwclock, such
# as machine hardware clock type for Alphas.
#HWCLOCKPARS=
# Set this to the hardware clock device you want to use, it should
# probably match the CONFIG_RTC_HCTOSYS_DEVICE kernel config option.
#HCTOSYS_DEVICE=rtc0
- 以上で設定は完了したので、再起動してRTCの動作を確認する。たとえば、LANケーブルを抜いて再起動しても時刻を保持していることや、異なる時刻を設定したあとLANケーブルを接続して再起動し、正しい時刻に修正されることを確認する。
pi@raspberrypi:~ $ sudo shutdown -r now
補足説明
- ラズベリーパイへの5V電源の供給を制御するためにAVRマイコンを使用しています。電源OFFの場合は電源ボタンの押下にてラズベリーパイに5V電源を供給します。電源ONの場合はラズベリーパイのBCM17ピンのLレベル入力から10秒後(ラズベリーパイがシャットダウンし、緑LEDの点滅終了後)に5V電源入力を切断します。
- ラズベリーパイはOS起動後、電源ボタンに連動しているBCM4信号を監視し、0.5秒以上押されているとシステムをシャットダウンします。電源ボタンが0.5秒以上押された場合や、コンソールからシャットダウン操作が行われた場合に限り、シャットダウン後にBCM17ピンをL出力とし、AVRマイコンに5V電源の切断を要求します。(コンソールからのリブートでは電源は切断されません)
- RTCモジュールを実装せず、シャットダウン機能を備えた電源制御ユニットにすることも出来ます。
- 入手性を考慮し、RTCは秋月電子のRTCモジュールを使用できるようにしました。
- RTCモジュールは AE-RX-8025NB の他に AE-RTC-8565NB も使用できるように基板を作成していますが、動作確認はしていません。
- 自作基板B0031へは、RTCモジュール の他にRX-8025NBチップ単品 を実装することも出来ます。ただし、C1の追加実装が必要です。(これも動作確認はしていません・・・)
- その他、外部からシャットダウン制御を行うためのサービスコネクタ(CN2)や、外付けの電源ボタン用のコネクタ(CN4)を取り付けられます。
|