PR 記事には広告が含まれています
Translate

ESP32がWiFi試行時ブラウンアウトリセットを何回かしたら一旦Deepsleepするプログラム

スポンサーリンク

ブラウンアウトリセットが何回か連続したら、WiFi接続をあきらめて、しばらくDeepsleepで寝るというプログラムを書いてみました。バッテリ動作時のテストに使えます。

スポンサーリンク

ブラウンアウトリセット

電池2,3本で動作するESP32-C3ボード」は電源電圧が低下した状態でWiFi接続すると、ESP32が大電流を消費し、低電圧状態になりリセットしてしまいます。これをブラウンアウトリセットと言います。

このため起動時のリセット要因として、ブラウンアウトリセットを検出したら、WiFiの接続をあきらめるか、長時間待ってバッテリー回復を待つかする必要があります。

そこで、起動時にリセット要因をチェックして、10回連続でブラウンアウトリセットを検出したら、1時間DeepSleepする。そうでなければ、WiFiに接続し、接続できたら5秒間Deepsleepする。という動作テスト用のプログラムを書いてみました。

ESP32-C3でしか試していなのでESP32-C3特有なのかもしれませんが、WiFi.beginにより低電圧でリセットすると、リセットしたのにのかかわらずWiFiの回路が暴走したままで大きな電流が流れている状態で再起動します。
起動時にWiFi.disconnect(true)を実行しても大電流は止まりません。
このWiFi回路の暴走を停止させるために、起動時にブラウンアウトリセットを検出したら1秒間Deepsleepし、WiFi回路への電源供給を強制的に止めています。そしてなぜか、Deepsleepから復帰後はWiFi.beginに必要な電流が少ないためなのか、低電圧でリセットせずに正常にWiFi.beginが終了する場合が多いです。

テストプログラム

#include <WiFi.h>
#define WIFI_BEGIN_TIMEOUT 10  //[s]
#define SLEEP_TIME 5*1000*1000 //[us] 5sec
#define SSID "SSID"
#define PASSWORD "PASSWORD"

#define WIFI_LED_PIN 7  //Tring connect WiFi
#define BOR_LED_PIN 10  //Brounot reset counter overflow

#include <Preferences.h>
Preferences prefs;
#define BROWNOUT_RST_MAX 10
#define BROWNOUT_SLEEP_TIME 60*60*1000*1000 //[us] 1hour

RTC_DATA_ATTR bool brownoutResetFlag = false;
#define BROWNOUTDETECT_SLEEP_TIME 1*1000*1000 //[us] 1sec

void setup() {
  WiFi.disconnect(true);  //WiFi OFF
  pinMode(WIFI_LED_PIN, OUTPUT);
  digitalWrite(WIFI_LED_PIN, LOW); //OFF
  pinMode(BOR_LED_PIN, OUTPUT);
  digitalWrite(BOR_LED_PIN, LOW);  //OFF

  Serial.begin(115200);
  Serial.println("");
  Serial.println("start");
  resetReason();  //Show RESET reason

  //Brownout detection
  prefs.begin("brownout", false);
  uint8_t count = prefs.getUChar("count", 0); // Read 1Byte(default:0)
  Serial.printf("ReadValue: %u\n", count);
  esp_reset_reason_t reason = esp_reset_reason();
  if( ESP_RST_BROWNOUT == reason )
  {
    //Brownout reset is detected
    brownoutResetFlag = true;
    prefs.end();
    esp_deep_sleep(BROWNOUTDETECT_SLEEP_TIME);  //All peripherals are disabled
  }
  
  if( ESP_RST_DEEPSLEEP == reason && brownoutResetFlag == true )
  {
    brownoutResetFlag = false;
    count++;
    if( BROWNOUT_RST_MAX < count )
    {
      prefs.end();

      //Brownout count is overflow
      for( int i=0 ; i<20 ; i++){
        digitalWrite(BOR_LED_PIN, HIGH);
        delay(250);
        digitalWrite(BOR_LED_PIN, LOW);
        delay(250);
      }

      //Long deepsleep
      esp_deep_sleep(BROWNOUT_SLEEP_TIME);

    }else{
      prefs.putUChar("count", count);
      Serial.printf("WriteValue: %u\n", count);
    }
  }else{
    if( 0 != count )
    {
      //Clear the counter
      count = 0;
      prefs.putUChar("count", count);
      Serial.printf("WriteValue: %u\n", count);
    }
  }
  prefs.end();

  //WiFi connect
  digitalWrite(WIFI_LED_PIN, HIGH);  //ON
  WiFi.mode(WIFI_MODE_STA);
  Serial.println("tring Wifi connect");
  WiFi.begin(SSID,PASSWORD);
  for (int i = 0; i < WIFI_BEGIN_TIMEOUT; i++) {
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println(" connected");
      break;
    }
    Serial.print("o");
    delay(1000);
  }
  if (WiFi.status() != WL_CONNECTED) {
    ESP.restart();
  }

  for(int i=0 ; i<3 ; i++){
  digitalWrite(WIFI_LED_PIN, LOW);  //OFF
  delay(100);
  digitalWrite(WIFI_LED_PIN, HIGH);  //ON
  delay(100);
  }

  //DeepSleep
  digitalWrite(WIFI_LED_PIN, LOW);  //OFF
  Serial.print("DeepSleep\n");
  esp_deep_sleep(SLEEP_TIME);

}

void loop() {
}

//Show RESET reason
void resetReason() {
  esp_reset_reason_t reason = esp_reset_reason();
  switch (reason) {
    case ESP_RST_UNKNOWN: Serial.println("ESP_RST_UNKNOWN : Reset reason can not be determined"); break;
    case ESP_RST_POWERON: Serial.println("ESP_RST_POWERON : Reset due to power-on event"); break;
    case ESP_RST_EXT: Serial.println("ESP_RST_EXT : Reset by external pin (not applicable for ESP32)"); break;
    case ESP_RST_SW: Serial.println("ESP_RST_SW : Software reset via esp_restart"); break;
    case ESP_RST_PANIC: Serial.println("ESP_RST_PANIC : Software reset due to exception/panic"); break;
    case ESP_RST_INT_WDT: Serial.println("ESP_RST_INT_WDT : Reset (software or hardware) due to interrupt watchdog"); break;
    case ESP_RST_TASK_WDT: Serial.println("ESP_RST_TASK_WDT : Reset due to task watchdog"); break;
    case ESP_RST_WDT: Serial.println("ESP_RST_WDT : Reset due to other watchdogs"); break;
    case ESP_RST_DEEPSLEEP: Serial.println("ESP_RST_DEEPSLEEP : Reset after exiting deep sleep mode"); break;
    case ESP_RST_BROWNOUT: Serial.println("ESP_RST_BROWNOUT : Brownout reset (software or hardware)"); break;
    case ESP_RST_SDIO: Serial.println("ESP_RST_SDIO : Reset over SDIO"); break;
    default: break;
  }
}

4行目 #define SSID にご自身のアクセスポイントのSSIDを設定し、5行目 #define PASSWORD にパスワードを設定してください。

WiFi.begin()でBrownoutResetが発生した場合、リセットはしてもWiFiの回路が暴走したままなので、一旦DeepSleepさせてWiFiの回路を停止させます(40行目)。RTCメモリのbrownoutResetFlag をtrueにしておきます。

DeepSleepから復帰してbrownoutResetFlagがtrueだったら(43行目)、FlashメモリにBrownoutResetの回数を設定します。この回数がBROWNOUT_RST_MAXの回数に達したら、WiFiの起動を諦めてDeepSleepに入ります。

その他の復帰条件だった場合、FlashメモリにBrownoutResetの回数を0に設定します(71行目)。

動作回路

テストプログラムの動作回路

GPIOの7ピンに1kΩ程度(470Ωから4.7kΩくらい)の抵抗と赤色のLEDを接続します。10ピンにも同様に1kΩ程度(100Ωから2.2kΩくらい)の抵抗と青色のLEDを接続します。

VINとGNDに電源や電池などを接続します。電源の配線は太いものを使ってください。

USBを接続するとUSBから電源が供給されてしまうので、テストすることができません。プログラムを書き込んで動作チェックがお済みになったら、USBは外してください。

動作

電源を入れます。青いLEDが点灯している間は、WiFiへの接続を試行している状態です。数秒間点灯しWiFiに接続できたら消灯します。その後5秒間Deepsleepします。

このため正常に動作していれば、数秒間青色LEDが点灯し、5秒間消灯するという動作を繰り返します。

しかし電源電圧が低いとWiFi接続の試行時にブラウンアウトリセットしてしまい、青色LEDがすぐに消灯します。このため、青色LEDが点滅しているように見えます。

10回連続してブラウンアウトリセットが起こるとWiFi接続の試行をあきらめ、赤いLEDが10秒間点灯します。10秒後は1時間のDeepsleepに入ります。

ご自身の環境で上記のプログラムを実行し、赤色LEDが点灯してしまうのであれば電圧不足か、配線の太さが細すぎると判断できます。

テストプログラムを使うことで、ご自身の環境において、どの電圧までWiFiが試行できるか、またどの電圧まで動作を継続することができるかテストすることができます。

電池2,3本で動作するESP32-C3ボード」をお使いになる際のテストにご利用ください。

この記事で利用している「電池2,3本で動作するESP32-C3ボード」はkohacraftのshopで販売しています。