Arduino
Arduino copied to clipboard
WiFI Fails to connect in specific circumstance after deepsleep
Basic Infos
- [x ] This issue complies with the issue POLICY doc.
- [ x] I have read the documentation at readthedocs and the issue is not addressed there.
- [ x] I have tested that the issue is present in current master branch (aka latest git).
- [x ] I have searched the issue tracker for a similar issue.
- [ ] If there is a stack dump, I have decoded it.
- [x ] I have filled out all fields below.
Platform
- Hardware: LOLIN D1 Mini Pro 2.0.0 (ESP 12E)
- Core Version: 3.0.1
- Development Env: Arduino IDE
- Operating System: Windows
Settings in IDE
- Module: LOLIN(WEMOS) D1 Mini Pro
- Flash Mode: [qio|dio|other]
- Flash Size: 16 MB
- lwip Variant: v2 Lower Memory
- Reset Method: [ck|nodemcu]
- Flash Frequency: [40Mhz]
- CPU Frequency: 80Mhz
- Upload Using: SERIAL
- Upload Speed: 921600
Problem Description
The circumstance is as follows: If a sketch is coded to connect to WiFi and uses deepsleep and only connects to WiFi on some invocations of the sketch, after connecting once and then sleeping and waking for a session that does not connect, no future connections are possible until the board is powered off and on again.
I have a sketch that makes water level measurements with a battery powered device, but only wants to report the measurements occasionally, not on every wakeup. So the sketch does not use WiFi on sessions where only measurements are taken (to save battery life) and recorded locally on and SD card. After one successful session and then one session without using WiFi, no additional WiFi connections are successful.
To demonstrate this, I have made a slight modification to the supplied example provided with 3.0.1 called WiFIShutDown. I modified the sketch to bring up a WiFi connection only on about half of the sessions (using ESP.random()). After the first successful connection, no future connections succeed.
Note: If you replace the ESP.deepsleep() with a delay() and ESP.restart(), the problem goes away, so this has something to do with the WiFi internal state across deepsleep().
The code for this follows.
MCVE Sketch
// Demonstrate the use of WiFi.shutdown() and WiFi.resumeFromShutdown() // Released to public domain
// Modified to demonstrate bug in core 3.0.1 causing WiFi to fail continuously after one session with no WiFi requested.
// Current on WEMOS D1 mini (including: LDO, usbserial chip): // ~85mA during normal operations // ~30mA during wifi shutdown // ~5mA during deepsleep
#ifndef STASSID #define STASSID "SSID" #define STAPSK "PASSWORD" #endif
#ifndef RTC_USER_DATA_SLOT_WIFI_STATE #define RTC_USER_DATA_SLOT_WIFI_STATE 33u // Data stored in first 32 blocks overwritten by OTA updates #endif
#include <ESP8266WiFi.h> #include <include/WiFiState.h> // WiFiState structure details
WiFiState state; // Size of this is 152 bytes
const char* ssid = STASSID; const char* password = STAPSK;
void setup() { Serial.begin(74880); //Serial.setDebugOutput(true); // If you need debug output Serial.println("Trying to resume WiFi connection...");
// May be necessary after deepSleep. Otherwise you may get "error: pll_cal exceeds 2ms!!!" when trying to connect delay(1);
// --- // Here you can do whatever you need to do that doesn't need a WiFi connection. // ---
ESP.rtcUserMemoryRead(RTC_USER_DATA_SLOT_WIFI_STATE, reinterpret_cast<uint32_t *>(&state), sizeof(state)); unsigned long start = millis(); if (ESP.random() & 01) { // Modification to demonstrate bug where WiFi fails after first successful connection.
if (!WiFi.resumeFromShutdown(state)
|| (WiFi.waitForConnectResult(10000) != WL_CONNECTED)) {
Serial.println("Cannot resume WiFi connection, connecting via begin...");
WiFi.persistent(false);
if (!WiFi.mode(WIFI_STA)
|| !WiFi.begin(ssid, password)
|| (WiFi.waitForConnectResult(10000) != WL_CONNECTED)) {
WiFi.mode(WIFI_OFF);
Serial.println("Cannot connect!");
Serial.flush();
ESP.deepSleep(10e6, RF_DISABLED); // 10 seconds
return;
}
}
unsigned long duration = millis() - start;
Serial.printf("Duration: %f", duration * 0.001);
Serial.println();
// ---
// Here you can do whatever you need to do that needs a WiFi connection.
// ---
WiFi.shutdown(state);
} else { Serial.println("Skipped WiFi this loop"); } ESP.rtcUserMemoryWrite(RTC_USER_DATA_SLOT_WIFI_STATE, reinterpret_cast<uint32_t *>(&state), sizeof(state));
// --- // Here you can do whatever you need to do that doesn't need a WiFi connection anymore. // --- delay(2000); Serial.println("Done."); Serial.flush(); ESP.deepSleep(10e6, RF_DISABLED); // 10 seconds }
void loop() { // Nothing to do here. }
ESP.deepSleep(10e6, RF_DISABLED); That RF_DISABLED means exactly that...
There are 2 ways to wake the modem after you've hard-disabled it with that Deep Sleep option, but you're not attempting either one. I'll have to look later to find the one that works in the current wake-after-sleep cycle, but the second method is to put it back to sleep with one of the other wake options. After hard-sleeping the modem you WILL experience an RF_CAL as the modem parameters are wiped with that RF_DISABLED.
Tech-TX, thanks for taking the time to reply. I'm sorry that I don't quite understand your point.
The sketch that I provided is from the examples given in the IDE with core 3.0.1, with the exception that the sketch is modified so that it does not connect on every invocation to WiFi, only about half of the time. Are you saying that during an invocation when WiFi is NOT used, that deepsleep should be called with a different argument than when WiFi IS used? (Note that the original example works all the time, but WiFi is used in every invocation.) By the way, the equivalent script runs successfully with core 2.7.4. (I say equivalent because WiFi.shutdown() and WiFi.resumeFromShutdown() appear to take different arguments in 3.0.1 than in 2.7.4, so the sketch needs to be slightly different.)
https://github.com/esp8266/Arduino/issues/3072#issuecomment-741524721 That should wake the modem again after you disable it with that Deep Sleep option. Try it.
BTW, case and syntax are important. That option should be WAKE_RF_DISABLED or else it likely compiles to an option of zero...
Thanks. I changed RF_DISABLED to WAKE_RF_DEFAULT and it works. This seems to say, however, that the example published with the core should use WAKE_RF_DEFAULT instead of RF_DISABLED, correct? (The example does not have WAKE_) I noticed that the core 3.0.1 documentation also warns about WAKE_RF_DISABLED. So, perhaps, this boils down to fixing the WiFiShutDown example shipped with core 3.0.1.
@daledj Could you please try and comment on PR #7979?