ブログ/こばさんの wakwak 山歩き

2017-02-19 ESP32 Deep Sleep のテスト (Hibernation mode)

ESP32 Deep Sleep のテスト (Hibernation mode)

| ESP32 Deep Sleep のテスト (Hibernation mode)を含むブックマーク

 ESP32 の Deep Sleep が 27μA までしか落とせない・・・って 嘆いていた ところ、keynee さんから貴重なコメント を賜りました。

 結果として無事に 4μA@3.3V な Hibernation mode に突入させることに成功しましたので、他の方への参考になるよう記事に残します。

#include "esp_deep_sleep.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/dport_reg.h"
#include "soc/i2s_reg.h"
#include "soc/sens_reg.h"
#include "soc/syscon_reg.h"

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200, SERIAL_8N1);
  Serial.println("Start");  

  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_OFF);
  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF);
  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_MAX, ESP_PD_OPTION_OFF); 
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(1000);
  Serial.println("good night!");

  SET_PERI_REG_BITS(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_DTEST_RTC, 0, RTC_CNTL_DTEST_RTC_S);
  CLEAR_PERI_REG_MASK(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_ENT_RTC);
  CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU);

  esp_deep_sleep_enable_timer_wakeup(10 * 1000 * 1000);  // wakeup(restart) after 10secs
  esp_deep_sleep_start();

  Serial.println("zzz");  // ここは実行されない
}

 keynee さん直伝の秘技

  SET_PERI_REG_BITS(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_DTEST_RTC, 0, RTC_CNTL_DTEST_RTC_S);
  CLEAR_PERI_REG_MASK(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_ENT_RTC);
  CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU);

の3連投をしたのちに esp_deep_sleep_start() させてやることで、見事に Hibernation mode に移行♪


4.0μA@3.3V3.8μA@3.0V
http://dl.ftrans.etr.jp/?07f969c2ac6043bdb700ca4d4e71a6a1e81781cd.jpghttp://dl.ftrans.etr.jp/?1bc2d1d65645481281eadd00608bb96d815487e3.jpg

 ほぼ全停止状態ではありますが RTC は生きてるので「指定時間後に再起動」だけは出来ます。

(上のサンプルだと10秒後に再起動)

 ESP8266 のときには、Deep Sleep から抜けて再起動させるときには、IO16 を RST ピンに繋いでおく必要がありましたが、ESP32 ではそーいう作法は必要なく、普通に再起動かかるようです。


 ESP8266 の Deep Sleep 10μA でも凄いのに、その半分以下の 4μA とは驚きですねー

keyneekeynee 2017/02/20 08:43 検証ご苦労様です。
bootloaderでbootloader_random_disableしてからアプリが起動されますので、スケッチの中ではbootloader_random_disableはおそらく無くていいと思いますよ。

こばさんこばさん 2017/02/20 11:08 おはようございます。
色々とありがとうございました。
4μAなら電池駆動の希望が見えてきますよね♪

>スケッチの中ではbootloader_random_disableはおそらく無くていいと思いますよ

秘技3連投のみでも大丈夫かも?ってことですね
仕事から帰宅したら続きを試してみようと思います!!

こばさんこばさん 2017/02/20 23:26 確認しましたら、bootloader_random_disable を削除しても消費電流は変わりませんでした。
何から何までありがとうございました。

ESP32 で Hibernation mode をしたくてこのページに訪問された方が混乱しないよう、記事の内容もまとめ直しました。

また宜しくお願い致します〜

keyneekeynee 2017/02/21 13:05 どうもです。
本家さんも同じ結論になったようですね。
/* Disable pull supply voltage to SAR ADC */
CLEAR_PERI_REG_MASK(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_ENT_RTC);
SET_PERI_REG_BITS(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_DTEST_RTC, 0, RTC_CNTL_DTEST_RTC_S);
だそうです。
近いうちにcommitされるはずですので、最新版では本処理は不要となります。

しかしながら、RTC_CNTL_CK8M_FORCE_PU のクリアの必要性は不明。

keyneekeynee 2017/02/22 19:10 esp-idf のmasterが更新されました。
これにより最新版では本問題は修正され、余計なことをしなくてもHibernation modeになります。
RTC_CNTL_CK8M_FORCE_PUビットのクリアも不要です。RTC_CNTL_CK8M_FORCE_PUビットのクリアは芳しくないのかもしれません。
修正版では以下の処理がesp_deep_sleep_startで追加されています。

// Shut down parts of RTC which may have been left enabled by the wireless drivers
CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG,
RTC_CNTL_CKGEN_I2C_PU | RTC_CNTL_PLL_I2C_PU |
RTC_CNTL_RFRX_PBUS_PU | RTC_CNTL_TXRF_I2C_PU);

SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_M, 0, SENS_FORCE_XPD_SAR_S);

こばさんこばさん 2017/02/22 19:37 こんばんは。まだ会社ですが、

https://github.com/espressif/esp-idf/blob/d3fde5188e3df788764edf7317b10034a7c724d1/components/esp32/deep_sleep.c

ですね。
帰宅したら実際に試してみます♪

こばさんこばさん 2017/02/23 00:59 こんばんは。帰宅して続きやってます。
esp-idf のほうは改善されたみたいですが、Arduino-esp32 のほうは、未だ更新されてませんでした。

ご本尊は libesp32.a みたいですが、まだリポジトリに反映されてないみたい。
反映されるまでは、上記のとおり手動でレジスタ操作する方法で回避ですな。

ずっとWiFiが死んだ1号機で試してましたが、今度は 「flash read err, 1000」が出るようになり本格的に死んでしまいました。
http://make.kosakalab.com/esp8266/esp32-flash_read_err_10002/ の方と同じ現象と思いますが、この方も改善できていないみたい。

手荒に扱ってるものの、書き込み中にリセットまではやってないのですけどねぇ・・・
とにかく壊れやすい気がしたので、本業でもないのに追加で10個ポチってしまいましたよ。

2017-02-16 ESP32 Deep Sleep のテスト

ESP32 Deep Sleep のテスト

| ESP32 Deep Sleep のテストを含むブックマーク

 ESP8266 に比べて Bluetooth など様々なペリフェラルに対応している ESP32 ですが、そーいう表面的なところのほか、実は Sleep と Wakeup の付近も極めて充実しています。

 RTC Slow Memory と呼ばれる遅いけど電気を食わないメモリ空間があって、そこにプログラムを配置しておくと Deep Sleep からの復帰時にリセットでなく、所定の処理を走らせることができたり・・・そんな風ぽい感じです。


 そーいう深いゾーンはおいおいとして、とりあえず Deep Sleep がちゃんと作動するのか試してみます。


#include "esp_deep_sleep.h"

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200, SERIAL_8N1);
  Serial.println("Start");  

  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_OFF);
  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF);
  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_MAX, ESP_PD_OPTION_OFF);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("good night!");
  delay(500);
  esp_deep_sleep_start();
  delay(500);
  Serial.println("now sleeping");  // ここは実行されない
}

 Deep Sleep 時の挙動を決める esp_deep_sleep_pd_config という関数があるものの、具体的にどう使うべきなのか資料が見つけられてないんですけど、引数に使える選択肢の全てを ESP_PD_OPTION_OFF にしてみましたが。


http://dl.ftrans.etr.jp/?2ad69e7acfb84bf692324cbd66a23c6d3b0b5e04.jpg


 手持ちテスターにて 27μA。

 2980円で買った安物テスターなので、μAオーダーの測定が正しく行えているのか疑問は残りますが、公式には 5μA まで落とせるらしいので頑張りが足りないですかねー


http://dl.ftrans.etr.jp/?0490bd90fcc8415a9ad151fac33f864f8ad3aef6.png


 テスターの計測が概ね合ってるとしたら「Deep-sleep mode ULP sensor-monitored pattern」という状態か?

 esp_deep_sleep_pd_config で RTC Memories も全て OFF にさせたつもりなんですが、何が足りないんでしょ

 一桁μA に出来た方おられたら、是非ともコメントくださーい!


(追記)

 TrueRMS なテスター を使って再測定してみました。

3.3V時3.0V時
http://dl.ftrans.etr.jp/?baff1c70959546f08422861cca1a0a23aa95390c.jpghttp://dl.ftrans.etr.jp/?1f04140bf2394c49aa3dad8471f7d154158b711a.jpg
2.7V時2.5V時2.2V時
http://dl.ftrans.etr.jp/?9f30b4e48d444e77a553a6490b0910e692408204.jpghttp://dl.ftrans.etr.jp/?b724a2d783944f9ea0498fc0ccf246c5fa07e5aa.jpghttp://dl.ftrans.etr.jp/?4c2bcb5a79e8471cba3a5046d461137d2fde7f86.jpg

 2980円のテスターで27μAを測定したときは約3Vでしたので、ほとんど誤差なかったみたいです。


(追記)2017/02/19

 keynee さんの貴重なコメントで、無事に Hibernation mode に移行させることに成功しました。

 消費電流は僅か 3.8〜4.0μA という次元です。


 サンプルソースも貼りましたので、こちら からどうぞ

keyneekeynee 2017/02/17 20:19 初めまして通りすがりの者です。
少々調べてみました。
bootloader_start.c のコミットID=3922ce47 あたりで挙動が変わったようです。
とりあえず、Deep-sleep mode の電流がどの程度か確認したいのであれば、bootloader_random_enable(); をコメントアウトして、bootloaderをmakeすれば 9μA 程度にはなります。
以下のURLが参考になりました。
https://www.esp32.com/viewtopic.php?t=1133
本家も解析しているようですので、時が来ればFixするでしょう。
それと、調査していてわかったのですが、RTC_CNTL_CLK_CONF_REG の bit26 (RTC_CNTL_CK8M_FORCE_PU)をクリアしてあげると、4μA 程度になりますが、これをすることによる弊害はわかりません。

こばさんこばさん 2017/02/18 00:19 こんばんは。
とても有益な情報に感謝します!!
とてつもなく深そうな部分ですねー

教えて頂いた bootloader_random_enable のソースを漁ってたら、対義ぽい感じの bootloader_random_disable ってものもあるみたいですね。


>RTC_CNTL_CLK_CONF_REG の bit26 (RTC_CNTL_CK8M_FORCE_PU)をクリア

ESP32 Datasheet に

> Hibernation mode: The internal 8MHz oscillator and ULP-coprocessor are disabled.
> The RTC recovery memory are power-down.
> Only one RTC timer on the slow clock and some RTC GPIOs are active.
> The RTC timer or the RTC GPIOs can wake up the chip from the Hibernation mode.

で記載のある、8MHzのオシレータ を停止させるレジスタぽい感じですかね
自力で復帰させる予定がなければ(リセットで復帰させるならば)、使っちゃって平気な気がしてきました。

自分も週末にチャレンジしてみようと思います。

keyneekeynee 2017/02/18 10:56 おはようございます。

bootloader_random_disable() で完全に初期状態に戻せてないようですね。
TEST回路が繋がったままでそこから電流リークしている?

bootloader_random.c の booloader_random_disable()関数に以下を追加すればよさげです。

SET_PERI_REG_BITS(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_DTEST_RTC, 0, RTC_CNTL_DTEST_RTC_S);
CLEAR_PERI_REG_MASK(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_ENT_RTC);

こばさんこばさん 2017/02/19 14:57 >TEST回路が繋がったままでそこから電流リークしている?

消費電流が電圧依存してるので、50kΩ相当?な内蔵プルダウンか何かが生きてるぽいですね。
そこら辺のレジスタを弄ったら無事に 3.8〜4μV になりました!

bootloader を弄る方法だと ESP-IDF の環境が要りますが、bootloader を弄らないで Arduino 環境から Hibernation mode に移行させることに成功しましたので、2/19 付けでまとめました。
http://d.hatena.ne.jp/wakwak_koba/20170219

>RTC_CNTL_CLK_CONF_REG の bit26 (RTC_CNTL_CK8M_FORCE_PU)をクリア

をやることによる消費電流への寄与は -5μA ほどみたいなんですが、それでも RTC は生きてるぽく、Hibernation からタイマー起動できました。