Actually, I'm not sure if this is a firmware of hardware issue.
I have two units of my board (custom board with ESP32). Unfortunately I don't have both with me: one is miles away so I cannot run both in the same conditions.
My board works fine, the other crashes very often in a specific circumstance.
The errors he gets are quite different, here some of them:
CORRUPT HEAP: Bad head at 0x3fff7f40. Expected 0xabba1234 got 0x3ffe4364
assert failed: multi_heap_free multi_heap_poisoning.c:259 (head != NULL)
assert failed: xQueueGenericSend queue.c:821 (!( ( pvItemToQueue == ((void *)0) ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ))
assert failed: spinlock_acquire spinlock.h:122 (result == core_id || result == SPINLOCK_FREE)
abort() was called at PC 0x40218473 on core 1
Despite they are different, the "good" news is they happen in two specific case: when I turn on or off the HTTP server.
I'm not able to produce a minimal code that exibhits the issue and the whole firmware it way too big to be published here (and I can't anyway). What I've observed is:
- my board almost work in any case
- his board crashes almost every time it trigger the on/off of the webserver
- how often this happens changes when I change other part of the firmware (the code below is unchanged from several months)
Point 3. led me to think about a memory corruption issue, but if it was the case I should see the same behavior on my board, shouldn't I?
Here the relevant code, hoping I'm doing something wrong here:
void Network::goProvisioning()
{
if (webapp.IsRunning()) webapp.End();
if (sntp_enabled) sntp_stop();
WiFi.mode(WIFI_OFF);
while (static_cast<int8_t>(WiFi.status()) > WL_IDLE_STATUS)
{
yield();
delay(500);
}
_provisioning.Begin(Ssid().c_str(), PASSWORD);
}
void WebApp::Begin()
{
MDNS.begin(APP_NAME);
MDNS.addService("http", "tcp", 80);
_server.serveStatic("/", LittleFS, "/www")
.setDefaultFile("index.html")
.setTemplateProcessor(std::bind(&WebApp::processor, this, std::placeholders::_1));
_server.onNotFound([](AsyncWebServerRequest *request)
{
request->send(404);
});
_server.begin();
_isRunning = true;
Serial.println(F("[WEB] HTTP server started"));
}
void WebApp::End()
{
_server.end();
Serial.println(F("[WEB] HTTP server stopped"));
_isRunning = false;
}
void ESP32WiFiProvisioning::End()
{
_requestEnd = false;
_server.end();
MDNS.end();
_state = ProvisioningStates::Idle;
}
void ESP32WiFiProvisioning::Begin(const char *ssid, const char *password)
{
if (onProvisionCallback) onProvisionCallback();
strncpy(_ssid, ssid, sizeof(_ssid));
strncpy(_password, password, sizeof(_password));
WiFi.mode(WIFI_STA);
WiFi.disconnect();
startScan();
}
void ESP32WiFiProvisioning::startAP()
{
WiFi.mode(WIFI_AP);
while (WiFi.getMode() != WIFI_AP)
{
delay(500);
yield();
}
WiFi.softAPConfig(apIP, apIP, netMsk);
WiFi.softAP(_ssid, _password);
WiFi.softAPsetHostname(APP_NAME);
Serial.printf("[WP] Start DNS: %s\n",_dns.start(53, "*", WiFi.softAPIP()) ? "success" : "failed");
Serial.println("[WP] AP IP address: " + WiFi.softAPIP().toString());
Serial.print("[WP] AP SSID: ");
Serial.println(_ssid);
Serial.print("[WP] AP password: ");
Serial.println(_password);
_server.on("/api/close", HTTP_POST, [this](AsyncWebServerRequest *request)
{
_requestEnd = true;
request->redirect(F("/exit-provisioning.html"));
});
_server.serveStatic("/", LittleFS, "/www")
.setDefaultFile("wifi.html")
.setTemplateProcessor(std::bind(&ESP32WiFiProvisioning::processor, this, std::placeholders::_1));
_server.on("/", HTTP_POST, [this](AsyncWebServerRequest *request)
{
this->handleConfigureRequest(request);
request->redirect(F("/exit-provisioning.html"));
});
_server.onNotFound([](AsyncWebServerRequest *request)
{
request->send(404);
});
_server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER);
_server.begin();
_state = ProvisioningStates::Run;
Serial.println("[WP] HTTP server started");
}
void ESP32WiFiProvisioning::Stop()
{
_dns.stop();
WiFi.mode(WIFI_OFF);
}
int ESP32WiFiProvisioning::convertRRSItoLevel(int rssi)
{
// Convert RSSI to 0 - 4 Step level
int numlevels = 4;
int MIN_RSSI = -100;
int MAX_RSSI = -55;
if (rssi < MIN_RSSI) return 0;
else if (rssi >= MAX_RSSI) return numlevels;
else
{
int inputRange = MAX_RSSI - MIN_RSSI;
int res = std::ceil((rssi - MIN_RSSI) * numlevels / inputRange);
if (res == 0) return 1;
return res;
}
}
void ESP32WiFiProvisioning::startScan()
{
#ifdef DEBUG
Serial.println("[WP] Starting Network Scan...");
#endif
WiFi.scanNetworks(true);
_scanCount = WIFI_SCAN_RUNNING;
_state = ProvisioningStates::Scan;
}
void ESP32WiFiProvisioning::loopScan()
{
_scanCount = WiFi.scanComplete();
switch (_scanCount)
{
case WIFI_SCAN_RUNNING:
case WIFI_SCAN_FAILED:
delay(50);
break;
case 0:
Serial.println("[WP] No networks found");
break;
default:
Serial.printf("[WP] Found %d networks\n", _scanCount);
}
}
void ESP32WiFiProvisioning::Fsm()
{
_dns.processNextRequest();
switch (_state)
{
case ProvisioningStates::Scan:
{
if (_scanCount < 0) loopScan();
else
{
storeAvailableNetworks(_scanCount);
startAP();
}
}
break;
default:
break;
}
}
Most of the time when I get the crash with one of the errors above the last printed debug string is:
[WEB] HTTP server stopped"
Of course I cannot be 100% sure if is something else that happens before a new debug string is printed.
I asked him to change its power supply, but the errors are still there.
I'm not able to reproduce the issue here and it's hard to do lot of trials with different debug printf given the distances.
I'm aware you don't have the cristall ball but I'm just looking for some advice to put me on the right path:
- it could be a firmware issue even if it triggers on one board only?
- may it depend by the specific routers/wifi networks?
- can an hardware issue triggers differently when changing other part of code?
- can I enable in some way a verbose debug of ESP32? Perhaps it tells me more information
Of course if I cannot solve in this way I have to ask him to give me back its item and test on my desk with the working item aside.