ESP8266 Deep-Sleepの最長スリープ時間の問題

Arduino/ESP32D1Mini,Deep-Sleep,DeepSleep,deepSleepMax,ESP8266,uint32_t,uint64_t,ディープスリープ,最長時間

前回の記事で、Deep-Sleepのテストを行ったはいいけど失敗した件

まぁなんか色々調べてみたんですが

やっとまぁコレじゃないかって結論に。

あまりにもう゛・・案件だったのでまた今回もBing AIチャットにイメージを描いてもらいました。

esp8266_deepsleep_max01
イメージ作成:Bing
イメージ生成モデル:DALL-E
イメージ生成ツール:graphic_art
イメージの著作権はBingに帰属しますので、無断で改変や再配布をしないでください。

例の如く、クレジットを明記しろってBingAIチャットさんが言うので

画像のキャプションをよくご確認下さい。

ESP8266 長い時間のDeep-Sleepが出来ない訳

全ての元凶はこれ。

framework-arduinoespressif8266\cores\esp8266\Esp.cpp

EspClass::deepSleep(uint64_t time_us, RFMode mode = RF_DEFAULT)

void EspClass::deepSleep(uint64_t time_us, WakeMode mode)
{
    system_deep_sleep_set_option(static_cast<int>(mode));
    system_deep_sleep(time_us);
    esp_suspend();
}

そしてこれ。

framework-arduinoespressif8266\tools\sdk\include\user_interface.h

bool system_deep_sleep(uint64 time_in_us);

まるでさぁ

なぁ?

uint64_t が受け付けられるみたいじゃない?

uint64_tの最大値は 2^64 符号なしで 18446744073709551615

つまり秒だと 18446744073709.551615秒

584942年はスリープできる筈なんだけどさ?

前回スリープしようとした時間は14時間。

60 * 60 * 14 * 100 * 1000 = 50400000000マイクロ秒

どうよこれ。

18446744073709551615 us
     50400000000 us

余裕っぽく見えるよな・・・?

駄菓子菓子

実際にはESP8266は、uint32_tしか受け付けてくれまいっぽい。

uint32_tの最大値は符号なしで 4294967295

18446744073709551615 uint64_t MAX
         50400000000 14時間@マイクロ秒
          4294967295 uint32_t MAX

余裕で桁あふれジャン。

そのくせな?

インターフェースがuint64_t受け付けるものだから、コンパイラがエラーを吐かない。

そんなわけで、まるで正常にスリープしたかの様な動作で実際はスリープできてない現象となる。

まじかようんkかよ

本当にuint64_tがダメなのか?その理由。

なんか変なキャストが走って妙な時間に丸められてるんじゃないのかと思って、色々やってみたのだけどダメ。

まぁつまりは、ESP8266は32bitCPUで、64bitタイマーを持ってなくてスタックする仕組みも無いから無理って話なんだってさ。

ESP32なら64ビットタイマーがあるから動くんだって。

なんじゃそれ的な。

ESP8266 (ESP-12F) deep sleep and light sleep with Arduino

この記事が本当にそうか、結構検証しますたが、間違いは見つけられませんでした。

いやぁなんかさぁ・・・

あとこれ、記事中で紹介されているリンクも見ておくといいかも。

GitHub:Low-Power Demo:Test 10 – Deep Sleep Instant, wake with RF_DISABLED

このREADMEによると、、、

Since SDK 2.1 the maximum Deep Sleep time has changed. The old maximum was based on uint32_t(micros) or ~71.58 minutes (2^32-1 microseconds). The new maximum is calculated from the RTC clock, which drifts with temperature from 5 to 7 timer ticks per microsecond, and will return a different number each time you read system_rtc_clock_cali_proc().

SDK2.1以降、DeepSleepの最長時間は71分から変更され、新しいタイマーはクロックTickから計算される方式に変わったそうで、実際には3~4時間に延長になったとか。

それで引数がuint32_tからuint64_tに変更になったのか

という辺りで腑に落ちる。

結局、こういう事か。

uint32_tしか受け付けられない訳ではなく、延長されたからuint64_tになった。

だけどuint64_tほど長くはスリープできないよ。

なぜならクロックTickから計算してタイマー駆動しているからさ、HaHaHa!

というわけで

uint64_t deepSleepMax = ESP.deepSleepMax();

これで最大時間を計算できるのだそう。

だけどなんかさ

スリープ時間が延長されたのはいいけど

Tickと係数で時間を計算する様になって、より雑なタイマーになった感・・・?

まぁいいや

いいや

じゃあどうすんの、ESP8266のDeepSleepタイマーさ

ESP.deepSleepMax() で最大スリープ時間が取得できるらしいけど、温度やら込み具合やらのRTCドリフトで結構ズレるんだって。

だからREADMEではMAXより短い時間で設定しろと書いてあった。

実際にESP.deepSleepMax()で何度か値を取ってみたら以下の通り。

13033275385
13030129657
12806258682
12807307258
12857114618
12853444602
12876513274
12879134714

すごいな結構範囲が広い。

うん、、、ざっくりと見て

12800000000 ~ 13034000000 辺りになっている。

実測最小辺りの 12800000000 マイクロ秒だと大体213分、3時間半くらいか。

というわけでESP8266では、少なくとも手元のD1 Miniでは、3時間くらい毎にDeep-Sleepから目覚めさせる必要があるっぽいという事。

目覚めさせないと変な動作になって乙る。

幸いESPマイコンにはWifiが付いているので、NTPサーバーから時刻を取って来れば正確な時間のスケジューリングは可能だろうけれど

折角省電力で動かそうってのにWifiはちょっと。

とりあえずどのくらい時間がズレていくのか、要検証という感じかな。

そのズレ具合によって、補正するかNTPサーバーと同期する頻度を高めるか、ちょっと実証してみないとわからんちん。

ESP8266は安価で多機能で便利なんだけど、なんというか

「ちゃんと書いておいてくれよ」

的な。

尚、今回のBing AIチャットにイメージを描いてもらった時のオーダーは、このブログ記事の文章を張り付けて

「この下記の文章をブログ記事用として苦悩しながら書いている可愛らしい日本の萌えキャラを描いてほしい。」

と。

すごいなビズリーチBingAIチャット!

画像の著作権はBingにあるそうですので、くれぐれもクレジットには目を通して下さいませ。m(__)m