Raspberry pi 4B ( 以下、raspi4 )をスケジュールにしたがってオン/オフするための回路とプログラムを作ってみた。
機能は以下のとおり。
- raspi4の電源をオンにしたり、シャットダウンして電源をオフにする。スイッチでも可能 (電源コントロール機能)
- 曜日、時刻、オンにしておく分数の指定によって稼働スケジュールを設定し、それにしたがって電源オン、シャットダウン、電源オフを行う(プログラマブルタイマー機能)。
- スケジュールの基準となる現在時刻を設定して記憶する(RTC搭載)。
- raspi4コアの温度が上がったら冷却用のファンを回す(gpio-fan機能)。
自分が寝ている時間帯に、勝手に起動してcronに設定した仕事をこなし、仕事が終わったらシャットダウンして電源もオフにするという機能を実現したくて、Pro MicroのATmega32U4とraspi4を接続した。
raspi4への電源は、Pch MOSFETをロードスイッチとして用いることで、タクトスイッチの押下やArduino (Pro Micro)のポート操作で行えるようにした。また、raspi4のOSが備えるオーバーレイを使ってデバイスツリーを拡張し、シャットダウンの開始 (gpio-shutdown) をArduinoのポート操作やタクトスイッチの押下で行えるようにし、raspi4からのパワーオフ通知( gpio-poweroff) をArduinoのポートで検出し、ロードスイッチをオフにする。
ついでに、gpio-fanオーバーレイを使ってコア温度が上がったら、DCファンを回すための回路も基板に載せた。
いろいろな話で長くなりそうなので、今回はおもにハードウェアについて。
今回使ったraspi4について
2021年の11月はじめに、Raspberry pi 4 Model B (4GBytes) を購入した。ちょうど品不足時期で「スターターキット」という販売形態しかなかった。たぶんオフィシャルケースは最初しか使わないが、USB Type-Cの5.1V出力のACアダプタや、MicroHDMIケーブルはすぐに利用したし今後も使うだろうから、高い買い物ということもなかった。
OSは、Raspbian OSイメージを含むフルバージョンNOOBS 書き込み済みのMicroSDがキットに付属していたので、そのまま利用している。この投稿を書いている時点のバージョンは Debian 10.11 (Linux raspberrypi 5.10.63-v7l+ ) になっている。今までRHEL系のCentOSばかり使ってきたので戸惑いもあったが、だんだんとなじんできた。
回路図
秋月電子のRaspberry Pi用ユニバーサル基板の上に以下の回路を載せた。
このユニバーサル基板には、2.1mm標準DCジャックをハンダ付けするためのパターンが描いてある。外部電源として、やはり秋月電子の+5V(4A)のACアダプタ (AD-A50P400) を接続している。
外部電源としては、USB Type-Cに接続する +5.1V(3A~4A) のものが使いたいのだけど、この基板にType-Cレセプタクルを載せられる場所が無さそうだったのであきらめた。3AくらいいけるType-Cレセプタクルを実装済のユニバーサル基板が欲しいところ。
このサイズのユニバーサル基板で使うとなると、Pro Microはちょっと大きい。当初、シャレでRP2040ブレイクアウトの Raspberry Pi Picoを使おうかと思っていたが、もっと大きいのでやめた。
おもな構成物について
構成するパーツや回路について。
マイコン (Pro Micro)
スケジュールの設定や記憶にマイコンがいるので、いつも使っているPro Micro (3.3V / 8MHz) を使った。raspi4のGPIOピンヘッダに接続するので、+5V動作のものより+3.3V動作の方が手間が減る。
Pro MicroのRAWピンには、DCジャック(ACアダプタ)からの+5Vをショットキーダイオード を介して接続している。このダイオードがないと、Pro MicroにUSBケーブルを接続している状態でDC5V inから電源ケーブルを抜いたとき、Pro MicroのUSBのVBUSが一次側電源(外部電源)として使われてしまってとてもまずい。Pro Microの電源周りは下図のようになっているから、500mA以上流れるとポリヒューズがトリップするだろう。
スケジュールの設定は、Arduino IDEのシリアルモニタ を使って対話的に行う。設定した内容はEEPROMに記憶するのでリセットしても電源切っても大丈夫。スケジュールは最大20個までとしたが、それほど設定することもないだろう。
スケジュールの設定時にはUSBケーブルを介してPCに仮想COMポートが見えている必要があるが、運用時にはシリアル接続は不要。ATMega32U4のパワーダウンスリープ機能により、raspiに電源を供給していない状態での消費電流は、ProMicroのパワーインジケータLEDといくつかのポート状態を維持するための 2mA以下になる。
RTC (RX8900) と電気二重層コンデンサ
スケジュール通りに動かすためには時計が必要になるので、RTC としてEPSONブランドのRX8900 (秋月のDIP化キット、AE-RX8900) を使った。RTCの電源としては、Pro MicroのオンボードLDOの出力(+3.3V、VCCピンから出てくる) を使っている。RX8900の消費電流は、Pro MicroのオンボードLEDが約1.3mA使うことを考えれば、まったく無視してかまわないレベル。
Pro MicroやRTCには基本的に常時通電するが、場所を変えたり構成を変えたりするときに電源オフにすることもある。そのような場合にいちいち時計を設定するのは面倒なので、1.0F の電気二重層コンデンサ(EDLC)をバックアップ電源として接続した。このコンデンサの耐圧は5.5Vなのだが、+3.3Vで充電するようにしておりフル充電時にほぼ+3.25Vとなる。このRTCは VBATが+1.6Vに低下するまで計時動作が可能とのこと。
RX8900のアプリケーションマニュアル から、VDD=0VになりVBATによる駆動に切り替わった際の消費電流は1.5uA (max) と見積もった。ここにコンデンサの自己放電分を加味して 10uA の定電流負荷になるとすると、電圧が1.6V低下するのに要する時間は、t = {C × (V0 – V1)} / I で求められるから、
1(F) × (3.2 – 1.6) ÷ 10(uA) = 1.6×105 (sec) ≒ 2666.7(min) ≒ 44時間27分
ということになる。今回使ったEDLCのスペックシートがなくて自己放電量を正確に把握できていないのだが、たとえそれが100uAだったとしても4.4時間は保持できるわけだから、今回の用途には十分過ぎるだろう。
定電流負荷時の放電時間の考え方については、コンデンサーメーカーのエルナー社のホームページを参考にした。
RX8900のVBATとEDLC間の抵抗は、おもに充電時の電流を制限するために入れた。3.3Vで100Ωだから、コンデンサが空っぽのときでも30mA強の電流しか流れ込まないはず。EDLCのESRも寄与するから実際にはもうちょっと電流は少ないだろう。その代わりフル充電までには10分間以上かかってしまうが、今回の用途では問題ない。
raspi電源制御
Raspi4の電源はGPIOピンヘッダの+5Vピンから与える。+5Vピンに電流を流すかどうかによって、raspi4の電源をオンにしたりオフにしたりする。raspiに備わっているType-Cの電源コネクタは使わない。raspi4Bの電源周りの回路図 ( https://datasheets.raspberrypi.com/rpi4/raspberry-pi-4-reduced-schematics.pdf ) を見ると、Type-CコネクタのVBUSは、そのまま+5Vとしてピンヘッダに接続されているし PMIC(Power Management IC) の MxL7704 のVINにもつながっている。
raspi電源をオン/オフするためのロードスイッチとして、Pch MOSFET の2SJ349 (Q3) を使った。このFETは低Vth でマイコンから扱いやすく、なおかつ低RDS(ON) なので一次側電源(外部電源~FETソース)と二次側電源 (FETドレイン~raspi+5V) の電位差が小さい。1A弱流れているときの実測で0.03~0.04V程度だった。2SJ349のデータシートの、RDS(ON) – ID グラフから読み取れるドレイン電流1A時の値も0.05Ω未満に見えるので、想定通り。
FETのゲートには+5Vをかける必要があるが、+3.3Vのマイコンと直結するわけにはいかないから、NPNトランジスタの 2N3904 (Q1) でゲート電圧をオン/オフしている。
Q1のベースには2系統の入力を用意した。一方はPro MicroのD4ポートで、もう一方はスライドスイッチ(SW1)を介して+3.3Vに接続している。SW1 (EVER-ONスイッチ)をオン側にすると、マイコンの状態に関わらずFETはオンになる。
2系統からの入力を手持ちの小電流スイッチングダイオードの1SS270Aを介してワイヤードORしたあと3.3kΩの抵抗を介して Q1のベースに接続している。このダイオードの VF が0.6V (@1mA) あたりだから、Q1のベース電流は0.8mA 程度ということになる。
EVER-ONスイッチは当初は不要と思っていたのだけど、FETをオンにした状態でマイコンをリセットすると、当然のようにraspiの電源が落ちてしまうので追加した。
rapi4とのインタフェース (DT Overlayの利用)
デバイスツリーオーバーレイ (Devicetree Overlay) とは、raspi用 のLinuxカーネルがもつ固有のデバイスツリーを、ブート時の設定(/boot/config.txt) にしたがって拡張したり変更したりする機能(と、解釈した)。今回の電源スケジューラボードでは、2つのオーバーレイファイルを有効にすることで、安全なシャットダウンとパワーオフを行えるようにした。
config.txtには、電源関係として以下の2行を追加した。
1 2 |
dtoverlay=gpio-shutdown,gpio_pin=20, active_low=1, gpio_pull=2 dtoverlay=gpio-poweroff,gpio_pin=26,active_low=1 |
これらの機能については次の文書を参考にした。 https://github.com/raspberrypi/firmware/blob/master/boot/overlays/README
gpio-shutdownオーバーレイ
このオーバーレイを有効にすると、指定のGPIOピンが指定の論理(アクティブLOWまたはHIGH)になったとき、キーボードのPowerキーが押されたときのようにシャットダウン処理を開始する。
上記のように、GPIO20、プルアップ有効、アクティブLOWとしたので、スケジューラボードのSHD-SWでGPIO20を所定の時間GNDに接地してやるか、ArduinoのポートからLOWを出力してシンクしてやれば、raspiはシャットダウンを開始してくれる。
gpio-poweroffオーバーレイと併用しない場合、gpio-shutdownを使ってシャットダウンした時点で電源コードを抜くなどするが、電源をそのままにしておいてGPIO3をLOWにしてやると、raspiは再度ブートしてくれる。
当初はGPIO3をスケジュールに沿ってオン/オフしてやればいいだろうと思っていたのだが、シャットダウン完了した時点での消費電流が実測で255mA もあった。これほど食うなら電源もオフにしようと思った。
gpio-poweroffオーバーレイ
このオーバーレイを有効にすると、シャットダウンが完了した時点で、指定のGPIOが指定の論理(LOWまたはHIGH)になり、電源断可能であることを通知してくれる。ただし、GPIO3を使った再ブートはできなくなる。
スケジューラボードでは、gpio-poweroffに指定したGPIO26がLOWになりシャットダウン完了状態になったことを検出すると、FETをオフにして電源断する。
raspiがシャットダウン完了状態になる要因としては以下を考えた。いずれの場合も、gpio-poweroffによる通知が有効だった。
- SHD-SWによる手動シャットダウン(gpio-shutdown)。
- Arduinoのポート操作(スケジューラ)によるシャットダウン (gpio-shutdown)。
- ターミナルからの入力やスクリプトでのshutdown -h の実行。
raspiのGPIO26は、Pro MicroのPCINT4 ( D8, PB4) に接続しており、Pin Change Interruptによってパワーダウンスリープから復帰してすぐに対応できるようにしている。
3V3の検出
raspiに電源を与えた直後は、gpio-poweroff通知を検出するGPIO26はLOWになっている。したがって、単純にGPIO26 == LOW を電源断のきっかけとすることはできない。
スケジューラボードでは、raspiのGPIOピンヘッダにでている3V3ピンから10kΩの抵抗を介してPro Microのポートピンに接続しておくことで、このピンがHIGHになったらraspiが稼働状態になったと判断する。そして、稼働状態になってしばらくたった時点で、GPIO26による電源断を許可するようにしている。
電源オン/オフのシーケンス
電源制御についてまとめると、以下のようになる。
GPIO20は、SHD-SW操作やポート出力によってraspiにシャットダウンを開始させるだけなので、電源制御とはあまり関係がない。
gpio-poweroffで使うGPIO26は、シャットダウン時には100msec間のLOW、100msec間のHIGHの後にLOWレベルになり、電源断許可の通知であることを明確に伝えてくれる。
たとえば、$ sudo reboot ( あるいは、shutdown -r now ) とかやった場合、100msecのHIGH期間が生じずにすぐにLOWになる。そして、約10秒後にシステムのリブートが完了するとHIGHに戻る。電源断を前提としたシャットダウンと、そうではないリスタートを区別して電源制御することができる。
gpio-poweroffについての追記(パラメータ追加)
kernelのupgradeをするたびにgpio-poweroffオーバーレイに変更が加わっているような気がする(ちゃんと見ていないだけなのだけど)。上に書いた電源断許可通知のについては、最初のLOW期間と次のHIGH期間の長さをパラメータで指定できるようになっている(2021年12月10日現在、5.10.63-v7l+ #1496 SMP)。
active_delay_ms によって最初のLOW期間の長さを、
inactive_delay_ms によって引き続くHIGH期間の長さを指定する。いずれもmsec単位で、省略値は100。
電源断許可通知を処理するArduinoスケッチではいずれも100msecを前提としているので、/boot/config.txt では以下のように明示的に指定するよう変更した。
1 |
dtoverlay=gpio-poweroff,gpio_pin=26, active_low=1, active_delay_ms=100, inactive_delay_ms=100 |
gpio-poweroffオーバーレイのdtsファイルは、rpi-5.10yブランチの以下を参照。
ユニバーサル基板と電源ライン
秋月のユニバーサル基板には、DCジャック用や電源レールのパタンが描いてあり、GPIOピンヘッダからDCジャックまで電源関係のラインはつながっている。
上図の赤色で示した部分が+5V、水色がGND、黄色が+3.3Vになっている(+3.3Vはraspi側から供給される)。
今回は、raspiに与える+5Vをオン/オフするのでこのままでは使えないから、左側の+5Vのパタンを裏表ともに途中でカットし、DCジャックに近い側を一次側電源ライン、ピンヘッダに近い方を二次側電源ラインとした。二次側電源ラインには、MOSFETのドレインを接続する。
低電圧警告と対策
最初MOSFETのドレインを二次側電源ラインの既存のパタンに接続するだけにして試していたところ、以下のようなログが出ることがあった。
1 2 3 4 |
... Nov 18 10:51:02 raspberrypi kernel: [ 628.717692] Under-voltage detected! (0x00050005) Nov 18 10:51:09 raspberrypi kernel: [ 634.967599] Voltage normalised (0x00000000) ... |
これは電源電圧が低下したのでコアの能力を絞りましたよ、ということのようである。二次側電圧が+4.8Vを下回ったあたりで低電圧警告がでてくるような感じ。
対策として、FETと電源ラインの配線をソース、ドレイン両方とも太い電線に変更したり2本にしたりしたところ、少なくとも目的の用途においては警告はでなくなった。配線面はとても見せられたものではなくなってしまったが。
使用状況は以下のとおり
- HDMIは4Kモニタに接続したりしなかったり
- USB3.0でUSBハードディスクに接続
- NICはGBit ハブに有線接続
- WiFiはオフ
- キーボード、マウスは未接続
現状、キーボードやMicroSDカードリーダーなどをUSBポートに接続してやると低電圧警告がでることがある。DC 5.25V / 3A出力のACアダプタとかあるといいですが。
組み立てについて
まず、raspi4のGPIOピンヘッダには、秋月電子の 連結ピンソケット 2×20(40P)ラズパイ用スタッキングコネクタ をはめた。
ただ、一段だけでは冷却ファンを収めるのが厄介そうだったので、ユニバーサル基板にも同様のコネクタをハンダ付けし、結果としてスタッキングコネクタ2段重ねとした。
ユニバーサル基板を固定するための脚としては、M2.5の真鍮製六角スペーサーの20mmと11mmを組み合わせるとちょうど良くて、raspiの基板面とユニバーサル基板の裏面との距離は32mmほどになった。ナットで締めなくても安定している。
裏側からM2.5×5mmのスペーサーで脚を固定することで、全体を支える脚にした。問題点は、全体を収める都合のいいシェルやケースが見つからないこと。
gpio-fan機能
raspi4にはSoCコアが指定の温度に達すると、指定のGPIOの論理を変える、gpio-fanオーバーレイが用意されている。これを利用して、冷却用のDCファンを回せるようにした。
/boot/config.txt に、以下のように書いてリブートするとこのデバイスツリーオーバーレイが有効になる。
1 |
dtoverlay=gpio-fan,gpiopin=21,temp=50000 |
この指定では、コア温度が50℃を超えた時点で gpio21 がHIGHになる。そして、指定温度から10℃下がると、今度はgpio21がLOWに戻る(低下温度はdtsファイルの定数になっている)。
GPIOピン自体から流す電流は規格上16mA以下とする必要があるので、ファンを直結するわけにはいかない。そのため、トランジスタのQ2 (2N3904)で受けてファンの電源をオン/オフするようにした。GPIOとQ2のベース間には1kΩの抵抗を入れたので、GPIO21から流れる電流は、最大でも3.3mAということになる。
ファンに与える+5Vは、このボード内の一次側電源を接続しているので、冷却ファンが回りだしたときの二次側(raspi側)への影響は少ないだろう。また、+5Vとファンの入力側の間には10Ωの抵抗を入れて過大な電流が流れないようにした。現在利用しているファンの場合実測で80~90mA流れている。
ファン自体はamazonで4つで1000円(送料込み)のものを使っていて、SoCのヒートシンクに強力両面テープで貼り付けた。貼り付ける都合でファンの上下が逆( ヒートシンクに吹き付ける方向 ) になってしまったが、今のところ問題はないようだ。もっとも、寒い季節になったのでなかなか回らないのだが。
きょうのまとめ
しばらく前に、2010年から自宅で使っていたIntel ATOM-D510ベースの小さなLinux boxが壊れてしまった。このホストには、BIOSに稼働時間を設定する仕組みが入っており、地球上のどこかで動いているサーバーから深夜または早朝にバックアップデータを吸い上げることを目的としていた。新しく買うのもつまらないので、初raspiを購入して早速工作してみた。
Raspberry Piというのは教育用に作られたコンピュータと言われているが、電源スイッチも時計も冷却ファンも、今回作ったような電源スケジューラも載ってないわけで、そういった補完機能を適切に考えて追加していくことが、楽しいコンピュータのお勉強ということだろうと思った。
次回は、Pro Microに載せたArduinoスケッチの話になる予定です。