Technical Information/Raspberry Pi

Edit  

ラズベリーパイ用RTC+電源ボタンユニットの作成

2019/01/26

ラズベリーパイにRTCと電源ボタンをもつアドオンボードを作りました。シャットダウン後ラズベリーパイへの5V電源供給をカットして電源の電力消費を抑えます。シャットダウン処理後、緑色LEDの点滅が終了してから5V電源をカットする安心設計です。

P1060379.JPG
 
Edit  

回路図

WS000217.PNG
 
Edit  

部品構成

  • ラズベリーパイ3 model B
  • 自作基板
    ReferenceValuePART
    B0031自作基板B0031
    BT1リチウムイオン2次電池MS621FE FL11E
    C210uF セラミックコンデンサGRM188R6YA106MA73
    CN1ピンソケット_2x9 2.54mmピッチFHU-2x42SG (同等品可)
    CN3USBコネクタ10118194-0001LF
    D1DAN202UM共通カソードDUAL DIODE
    D4ショットキーバリアダイオードRB751S-40
    Q1Pch MOSFETDMG3415U
    Q2,Q3Nch MOSFETBSS138
    R1680Ω チップ抵抗 1608サイズRK73B1JTTD681J (同等品可)
    R3,R10100KΩ チップ抵抗 1608サイズRK73B1JTTD104J (同等品可)
    R5,R910Ω チップ抵抗 1608サイズRK73B1JTTD100J (同等品可)
    R6,R8,R1110KΩ チップ抵抗 1608サイズRK73B1JTTD103J (同等品可)
    R7,R121KΩ チップ抵抗 1608サイズRK73B1JTTD102J (同等品可)
    S1タクトスイッチSKRPACE010
    U2リアルタイムクロックモジュールAE-RX-8025NB
    U3米粒AVRマイコン ATtiny10ATTINY10-TSHR
    ※C1,C3,C4,C5,CN2,D2,D3,R2,R4,R13,U1は実装しない

    P1060372.JPG P1060373.JPG

 
Edit  

ソフトウェア構成

  • ラズベリーパイ:Raspbian GNU/Linux 9.6 (stretch)
  • AVRマイコン:AVR/GNU C Compiler (Atmel Studio 7)
 
Edit  

機能

  • 日時情報のバックアップ
    • OSの起動時にインターネットに接続されている場合はntpによる時刻取得およびRTCの更新を行う
    • OSの起動時にインターネットに接続されていない場合はRTCの保持している時刻をシステム時刻に設定する
  • 電源ボタン押下(0.5秒以上の長押し)による自動シャットダウンおよび5V電源カット
  • 電源ボタン押下による電源接続およびシステムの起動
 
Edit  

導入方法

 ※ラズベリーパイをインターネットに繋いだ状態で作業してください

  1. 予め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
  2. アドオンボードをラズベリーパイのGPIO端子に装着し、ラズベリーパイの電源コネクタ(Micro USBコネクタ)ではなく、今回作成したアドオンボード上のMicroUSBコネクタ(CN3)に5V電源供給用のUSBケーブルを接続する。その後電源ボタン(S1)を押してラズベリーパイを起動する。

  3. シャットダウンボタンのドライバをインストールする。
    1. シャットダウン時のみ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
      :
    2. 次に作成したスクリプトに実行可能属性を設定する
      pi@raspberrypi:~ $ sudo chmod 755  /lib/systemd/system-shutdown/gpio-poff
    3. オーバレイ機能を上記のスクリプトで上書きする設定を、config.txtの最後に追記する。
      pi@raspberrypi:~ $ sudo vi /boot/config.txt
      追記する内容は以下の通り:
      # Enable gpio-poff (user custom script)
      dtoverlay=gpio-poff
    4. 続いて、電源ボタン押下によるシャットダウン制御のスクリプトを作成。ここでは /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)
    5. ファイルに実行可能属性を設定する
      pi@raspberrypi:~/script $ sudo chmod 755 shutdown.py
    6. サービスファイルを作成
      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
    7. サービスの有効化(これで再起動時に自動的にスクリプトが実行される)
      pi@raspberrypi:~ $ sudo systemctl enable shutdownbutton.service
    8. デーモンを再起動
      pi@raspberrypi:~ $ sudo systemctl daemon-reload
    9. 一旦リブート
      pi@raspberrypi:~ $ sudo reboot
    10. サービスの状態を確認 (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.
    11. 動作確認
      1. ラズベリーパイの電源コネクタ(Micro USBコネクタ)ではなく、今回作成したアドオンボード上のMicroUSBコネクタ(CN3)に5V電源供給用のUSBケーブルを接続する。この状態ではラズベリーパイの電源が入らないことを確認。
      2. 電源ボタン(S1)を押すと赤色LEDが点灯しラズベリーパイに電源が投入され、システムが起動することを確認。
      3. 電源ボタン(S1)の0.5秒未満の短押しではシャットダウンが動作せず、0.5秒以上の長押しで即座にシャットダウン動作が開始され、シャットダウン終了後ラズベリーパイの緑色LEDの点滅が終了した後に赤色LEDが消灯することを確認。
      4. 再び電源ボタン(S1)を押し、システムを起動する。つづいてターミナルよりリブートを行う。
        pi@raspberrypi:~ $ sudo reboot
        ラズベリーパイの電源が切れることなく、システムがリブートされることを確認する。

  4. RTCのドライバをインストール
    1. 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: -- -- -- -- -- -- -- --
    2. ドライバが有るかどうか確認。 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
    3. 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: -- -- -- -- -- -- -- --
    4. 時刻の自動更新を行えるように、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:~ $
    5. RTCに、現在のOSのシステムクロックの時刻を書き込む
      pi@raspberrypi:~ $ sudo hwclock -w
    6. ブートごとに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
    7. ブート時に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
    8. 以上で設定は完了したので、再起動してRTCの動作を確認する。たとえば、LANケーブルを抜いて再起動しても時刻を保持していることや、異なる時刻を設定したあとLANケーブルを接続して再起動し、正しい時刻に修正されることを確認する。
      pi@raspberrypi:~ $ sudo shutdown -r now
 
Edit  

補足説明

  • ラズベリーパイへの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)を取り付けられます。

トップ   リロード   一覧 単語検索