はじめに
ちょっと前の記事 はじめてね AtomVM(4) ESP32でLチカ v0.7.0-alpha.1 版 でアルファ版の AtomVM をインストールしてみました。AtomVM でスリープモードが使えるのか試してみました。
ファイルの場所、コンパイル、ファームに焼き焼き、は前回同様です。
Sleep mode
さまざまなプロセッサで、プログラムが動作しないタイミングで電力消費を押さえるような機能があります。この機能、スリープに関する ESP32 の動作モードは、
- 通常の Active mode
- CPUが停止する Light sleep mode
- 何もかもが停止する Deep sleep mode
の3種類あるようです。おそらく黙ってプログラムを作ると Active mode でしょう。スリープ状態を AtomVM プログラムで引き起こせるのか試してみます。用いるのは Releases v0.7.0-alpha.0 です。
今回ESP32でやってまして、これESP32用の特別な関数が用意されてました。その当たりは ESP32-specific APIsにまとめられてます。さらにスリープ周りについては Restart and Sleep にあります。
Light Sleep mode
先に Light sleep をさせてみます。実はこちらの方が苦労してます。ドキュメントは Light Sleep にあります。
今回はタイマをセットして Light sleep して、時間が来たら起き上がるというのを繰り返すことで Lチカさせます。なお、他のプログラムと区別するのにチカチカと2回点滅してから寝るようにしてます。
defmodule Blinky do
@compile {:no_warn_undefined, [GPIO, :atomvm, :esp]}
@gpio_pin 2 # for GPIO of ESP32
def start() do
IO.puts("LED Blink starts")
GPIO.set_pin_mode(@gpio_pin, :output)
loop(@gpio_pin)
end
def loop(pin) do
Enum.each(0..1, fn _ -> blink_1(pin) end)
:esp.sleep_enable_timer_wakeup(1_000_000) # micro seconds
:esp.light_sleep()
loop(pin)
end
defp blink_1(pin) do
GPIO.digital_write(pin, :high)
Process.sleep(100)
GPIO.digital_write(pin, :low)
Process.sleep(100)
end
end
タイマを仕掛けてから眠るところは
:esp.sleep_enable_timer_wakeup(1_000_000) # micro seconds
:esp.light_sleep()
の部分です。:esp.sleep_enable_timer_wakeup/1 関数の引数がミリ秒でなくマイクロ秒なのになかなか気が付かずでした。ESP-IDF をちゃんと調べるとすぐに分かったものと思います。
今回はタイマでやりましたが、GPIO の入力でも起床できるようなので、例えばボタンが押されるまでスリープしてるとかも簡単に書けそうです。
Deep sleep mode
Light sleep よりしっかり寝るのが Deep sleep です。こちらは CPU だけじゃなくあらかた全部 off になってしまうので、sleep 中の電力消費が少ないというメリットがあります。その代わりメモリの内容も失われてしまう… すなわち BEAM 処理系としての動作状態が完全に失われるので、起きてくることが電源オンの状態と同じになります。
ドキュメントは Deep Sleep にあります。
defmodule Blinky do
@compile {:no_warn_undefined, [GPIO, :atomvm, :esp]}
@gpio_pin 2 # for GPIO of ESP32
def start() do
IO.puts("LED Blink starts")
GPIO.set_pin_mode(@gpio_pin, :output)
Enum.each(0..2, fn _ -> blink_1(@gpio_pin) end)
:esp.deep_sleep(1000)
end
defp blink_1(pin) do
GPIO.digital_write(pin, :high)
Process.sleep(100)
GPIO.digital_write(pin, :low)
Process.sleep(100)
end
end
この :esp.deep_sleep/1 関数で sleep します。次に起きてくるときは start/0 関数の先頭になるので、明示的に再帰でループを書かなくてもこれで start/0 関数が毎度実行されるという仕掛けになってます。こちらはチカチカチカと3回チカってから sleep するようにしました。
なおここで :esp.deep_sleep/1 関数の引数がミリ秒なことに注意して下さい。Light sleep と Deep sleep で単位が違ってます(なんでやねん)。
なお、何もかもオフになると書きましたが、RTC (Real Time Clock) に若干メモリがあって、そこにデータを保持できるようです。ただし
- RTC 保持用の電池(大概はボタン型の酸化銀電池)で RTC がバックアップされてる必要がある
- ESP32の電源を完全に切ってしまうと失われる
- おそらくアクセスは遅くて、容量はだいぶ小さい
ドキュメントは RTC Memory です。
まとめ
AtomVM v0.7.0-a.1 で ESP32 の2種類のスリープ機能が使えるのを確認しました。
Light sleep mode からの GPIO による復帰や、Deep sleep mode での RTC Memory の利用などもやってみたいと思います。