Ich programmiere den ESP8266 mit Arduino. Das Program funktioniert
einwandfrei solange der ESP über Wifi verbunden ist.
Wenn der Accesspoint aber ausgeschaltet ist, läuft im Hintergrund der
Wifi-Connect weiter und versucht sich zu verbinden, während das Program
über die GUI benutzt werden kann.
Treten dann Interrupts auf, chrashed das System nach kurzer Zeit.
Unten habe ich mal den Exception decoder output angegeben.
Mir ist aufgefallen, das immer die Funktion
1
millis()
auf dem Stack ist. Diese Funktion benutze ich auch im Interrupt
(ansonsten setzt der Interrupt nur ein paar Variablen). Das ist laut
Arduino docu erlaubt wenn man beachtet das millis() währen des
Interrupts nicht weiter zählt.
Die Funktion millis)() ruft system_get_time() auf die nicht auf dem
Stack liegt und ist ansonsten unauffällig.
Gibt es ähnliche Chrash Erfahrungen während updateWifi()? Gibt es
Erfahrungen mit millis() in Interrupt Routinen?
0x4020cd18: esp_yield at
/home/user/.arduino15/packages/esp8266/hardware/esp8266/2.4.2/cores/esp8
266/core_esp8266_main.cpp line 91
Wie du siehst ist yield auf dem Stack... D.h. die Wifi library wurde
durch yield aufgerufen.
Habe gerade mit einer vollständig leeren Interrupt Routine (es handelt
sich um einen external GPIO interrupt) getestet. Sobald ich anfange
Interrupts auszulösen crashed updateWifi() nach ein paar Interrupts...
Wenn ich den exception Stack richtig interpretiere wurde der erste
Interrupt-Handler bei Zeile 130 von einem zweiten Interrupt Handler
unterbrochen. Der zweite Interrupt Handler wurde bei Zeile 136 von dem
Wifi Stack unterbrochen. Der nur als binary vorliegende Wifi-Stack hat
noch zwei weitere Funktionen aufgerufen. Dann kam mein leerer Interrupt
greenKey() und das System ist mit illegal instruction gecrashed...
Alles davor auf dem Stack zeigt, dass der Processor tief im Wifi Stack
vergraben ist der durch den call nach updateWifi() aufgerufen wurde.
Hallo,
da Dein Programm ja unbekannt ist: ich habe hier nur ein ESP8266-Projekt
in Betrieb, daß einen externen Interrupt nutzt. Der kommt von einem
RFM12-modul wenn ein gültiges Byte empfangen wurde. Die ISR ist relativ
lang weil alle 30 Byte komplett eingelesen werden müssen.
WiFi reconnects habe ich hier dank vielen WLANs öfter, gecrasht ist das
bisher noch nie, allerdings habe ich den AP auch nie längere Zeit
offline.
Müßte ich mal testen, kann mir im Moment aber eigentlich kein wirkliches
Problem vorstellen.
Gruß aus Berlin
Michael
Hallo,
mir ist gerade bewusst geworden, daß Du ja offenbar direkt auf der
Espressif-Ebene unterwegs bist. Das habe ich mir bisher fast immer
geschenkt und bin in der "Arduino"-Ebene geblieben. Werde Dir also wohl
nicht helfen können.
Dein Problem wäre wohl vermutlich im Espressif-Forum besser aufgehoben.
Gruß aus Berlin
Michael
Christian K. schrieb:> Ich hoffe mir kann irgend jemand einen Programmierfehler> nachweisen,> denn ansonsten ist wohl die WiFi Library das Problem?
Wenn du für den ESP die Version 2.4.2 hat, kann es sein!
Bei mir hat WiFi des öfteren sich getrennt und der AutoReconnect nicht
funktioniert. Bei der Version 2.3.0 hingegen gab es solch ein problem
nicht.
Downgrade mal über den Boardverwalter den "esp8266 by ESP8266 Community"
Hallo,
muß ich mir mal in Ruhe anschauen, ESP8266WiFiMulti.h habe ich bisher
noch nicht benutzt.
Ich habe mal ein Beispiel von mir unverändert anghängt.
Ist ein WiFi-Client mit einer Glimmanzeige als Thermometer.
Steuerung per MQTT und Ausgabe per PWM.
Das Konstrukt mit dem Ticker stammt aus dem Netz, Grund war eine
Ungereimtheit mit dem WiFi-Status: die Lib meldet WL_CONNECTED was
prinzipiell auch stimmt. Der AsyncMQTT hat dann sofort mit dem Borker
verbunden. Wollte er zumindest... Der ESP hatte noch keine gültige IP
vom DHCP bekommen und die MQTT-Anmeldung lief ins Leere.
Der ESP war denn sauner im WLAN, der MQTT aber nicht und auch nie wieder
einen Event zum Verbinden ausgelöst.
Ist jetzt mehr als Erklärung gedacht, Deine Geschichte kann ich mir erst
morgen im Detail wirklich mal anschauen.
Gruß aus Berlin
Michael
Hast mal zum Testen den Watchdog aus gemacht?
Soweit ich weiß sollte yield eigentlich den Watchdog triggern, oder du
machst zum spaß mal ein delay(10) rein (was aber eigentlich das selbe
tun sollte)
Christian K. schrieb:> einen Programmierfehler nachweisen
AddAP wird für Wifimulti typischerweise nur einmal für jeden AP in
setup() aufgerufen, damit wird der AP dem Programm bekanntgemacht. Der
zyklische Aufruf über loop() -> updatewifi() -> wifi_idle dürfte den
Speicher zumüllen.
MWS schrieb:> AddAP wird für Wifimulti typischerweise nur einmal für jeden AP in> setup() aufgerufen, damit wird der AP dem Programm bekanntgemacht. Der> zyklische Aufruf über loop() -> updatewifi() -> wifi_idle dürfte den> Speicher zumüllen.
Danke für den Hinweis! Aber leider macht er ja auch nur einmal. Der
State WIFI_IDLE ist ja nur einmal inital aktiv, danach wird er nicht
mehr angesprungen. Der State wechselt sofort auf
wifiState=WIFI_CONNECTING; und nie mehr zurück auf WIFI_IDLE
läuft bis jetzt stabil, ich habe mir 2 AP mit ESp8266 und ESP32 gebaut
weil ich mein lokales WLAN nicht dauern ein- und ausschalten will.
Verbindet mit einem AP, bei Verlust mit einem anderen.
Aus der loop() ist es nicht blockierend solange der ESP selbst nicht
blockiert.
Ausnahme ist ein delay(5);
Der ESP32 als AP macht hier auch etwas Eigenleben, er braucht "ewig" und
die DHCP IP auszuliefern.
WiFiReturns() habe ich einem Netzfund entliehen.
Deine Tasteninterrupts mußt Du mal selbst einbauen, ich sehe kein
Problem, wo die den Ablauf stören sollten.
Vielleicht hilft es erstmal etwas weiter als Anregung.
Noch als Nachtrag: die Event-Handler
WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;
scheinen nicht mehr durchgereicht zu werden wenn WiFiMulti eingebunden
ist
autoReconnect() klappt wohl auch nicht mehr so richtig (da hatte doch in
der 2.3.0 schonmal jemand drüber geklagt???).
Gruß aus Berlin
Michael
Marc Horby schrieb:> Wenn du für den ESP die Version 2.4.2 hat, kann es sein!> Bei mir hat WiFi des öfteren sich getrennt und der AutoReconnect nicht> funktioniert. Bei der Version 2.3.0 hingegen gab es solch ein problem> nicht.>> Downgrade mal über den Boardverwalter den "esp8266 by ESP8266 Community"
Hi Marc,
habe gerade auf die V2.3.0 downgegraded, stürzt genauso ab wie mit der
V2.4.2...
Es folgt der Workaround/Lösung für das Probem.
Das Problem ist: Der ESP8266 crashed, wenn während Wifi nach einer
Verbindung zum AP sucht (evtl. länger weil der AP ausgeschaltet ist)
externe GPIO Interrupts auftreten. Wenn Wifi verbunden ist funktionieren
die Interrupts einwandfrei.
Wie man an dem Exception Stack sieht, tritt der crash immer in der
Function WifiMulti.run(), tief im Wifi Stack auf.
Die Lösung/Workaround ist, GPIO interrupts zu disablen wenn die Funktion
run() aufgerufen wird.
1
noInterrupts();
2
wifiMulti.run();
3
interrupts();
geht natürlich nicht, weil der Wifi Stack auch Interrupts braucht.
Wie es dann letztendlich geht steht unten im Code Beispiel. Mit diesem
Code ist mir bisher kein Crash mehr gelungen.
1
#include<ESP8266WiFi.h>
2
#include<ESP8266WiFiMulti.h>
3
4
#define DEBUG
5
#ifndef DEBUG // disable Serial output
6
#define Serial NoDebug
7
staticclass{
8
public:
9
voidbegin(...){}
10
voidprint(...){}
11
voidprintln(...){}
12
voidprintf(...){}
13
voidflush(...){}
14
}Serial;
15
#endif
16
17
ESP8266WiFiMultiwifiMulti;// Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
18
19
#define PIN_D0 16 // WAKE
20
#define PIN_D1 5 // User purpose
21
#define PIN_D2 4 // User purpose
22
#define PIN_D3 0 // FLASH mode at boot time
23
#define PIN_D4 2 // TXD1 (Note: low on boot means go to FLASH mode)
24
#define PIN_D5 14 // HSCLK
25
#define PIN_D6 12 // HMISO
26
#define PIN_D7 13 // HMOSI RXD2
27
#define PIN_D8 15 // HCS TXD0
28
#define PIN_D9 3 // RXD0
29
#define PIN_D10 1 // TXD0
30
31
#define PIN_MOSI 8 // SD1
32
#define PIN_MISO 7 // SD0
33
#define PIN_SCLK 6 // CLK
34
#define PIN_HWCS 0 // D3
35
36
#define PIN_D11 9 // SD2
37
#define PIN_D12 10 // SD4
38
39
// Input-Output Definitions
40
staticconstbytegreenKeyInput=PIN_D2;
41
staticconstbyteredKeyInput=PIN_D1;
42
staticconstbyteblueKeyInput=PIN_D0;
43
staticconstbyteLEDPin=PIN_D4;
44
45
// Wifi States
46
staticconstintWIFI_IDLE=0;
47
staticconstintWIFI_CONNECTING=1;
48
staticconstintWIFI_CONNECTED=2;
49
staticintwifiState=WIFI_IDLE;
50
51
voidsetup(){
52
// GPIO setupt
53
pinMode(greenKeyInput,INPUT);
54
pinMode(redKeyInput,INPUT);
55
pinMode(blueKeyInput,INPUT_PULLUP);
56
pinMode(LEDPin,OUTPUT);
57
digitalWrite(LEDPin,HIGH);
58
59
Serial.begin(230400);// Start the Serial communication to send messages to the computer
Hallo,
ich kann Dir das so bestätigen
Christian K. schrieb:> Wie man an dem Exception Stack sieht, tritt der crash immer in der> Function WifiMulti.run(), tief im Wifi Stack auf.
Das kann ich Dir so bestätigen. Ich habe in meinen obigen Source mal die
Interrupts für die beiden Tasten eingehängt und kann den Crash erzeugen.
Ich bin da also Deinen Beispiel gefolgt:
1
#include <ESP8266WiFi.h>
2
#include <ESP8266WiFiMulti.h>
3
4
ESP8266WiFiMulti wifiMulti;
5
6
// WiFi
7
#define WIFI_WAIT 10 // 2,5s Verbindungsversuch, dann ab nach loop()
Gut zu wissen falls ich das doch mal in der Kombination benutze.
Ich habe auch den Aufruf in setup() für mich nochmal geändert, weil ich
beim Eintritt in loop() für andere Initialisierungen gern weiß, ob es
ein WLAN gibt.
PS: Deinen Pin-defines und den static const byte greenKeyInput = PIN_D2;
konnte ich nicht sorichtig folgen, das ist in der IDE doch ohnehin
zugeordnet. Hat es einen Grund, daß Du SPI auf andere Pins gelegt hast
und nicht die Standard-HW-Pins 12,13,14,15 genutzt hast?
Gruß aus Berlin
Michael
Schön zu hören, ist also ein generelles Problem beim ESP8266. Danke fürs
ausprobieren.
Die Pin Definition habe ich nur in der Source Code kopiert, weil mein
Board nicht die GPIO Beschriftung hat sondern die D0...D10 Beschriftung
und mein Schaltplan die GPIO. Das war für mich einfacher, kann man auch
rauslöschen.
Die Flash SPI Pins sind sicher auch nicht wichtig:
1
#define PIN_MOSI 8 // SD1
2
#define PIN_MISO 7 // SD0
3
#define PIN_SCLK 6 // CLK
4
#define PIN_HWCS 0 // D3
Es sind die User-SPI Pins die auf 12,13,14,15 gemapped sind.
Hallo,
Christian K. schrieb:> Die Pin Definition habe ich nur in der Source Code kopiert, weil mein> Board nicht die GPIO Beschriftung hat sondern die D0...D10 Beschriftung> und mein Schaltplan die GPIO. Das war für mich einfacher, kann man auch> rauslöschen.
das Problem kenne ich nur zu gut...
Ich benutze normalerweise immer die GPIO-Nummern im Source und habe ein
schönes ausgedrucktes farbiges einlamniertes Bild des jeweilgen Moduls
zum verdrahten daneben liegen. :-)
Bei den ESP32 Modulen geht es ohne sowas sowieso nicht richtig, ich habe
sicher 5 Versionen hier, die zwar versuchen sich an das DevKit zu
halten, aber sie versuchen es eben manchmal nur.
Gruß aus Berlin
Michael
Michael U. schrieb:> Hallo,>> ich kann Dir das so bestätigen
Ich nicht. Habe gerade deinen Code 1:1 übernommen. WLAN ist nicht
verbunden (da meine SSID anders ist) und wenn ich den Taster an D2
Drücke ist alles i.O. Nur etwas modifiziert:
1
voidgreenKey()
2
{
3
//digitalWrite(LED_PIN, HIGH);
4
Serial.println("Switch on D2 pressed");
5
}
Läuft so wie erwartet
PlatformIO 3.6.1, ESP8266 1.7.3 (Core 2.4.1)
Hallo,
ich habe gerade etwas gegooglet, es gibt das Problem auch im
Zusammenspiel ESPWebserver und externem Interrupt.
Man findet nur wenig, soviele Leute nutzen externe Interrupts wohl
nicht.
Timmo H. schrieb:> Ich nicht. Habe gerade deinen Code 1:1 übernommen. WLAN ist nicht> verbunden (da meine SSID anders ist) und wenn ich den Taster an D2> Drücke ist alles i.O. Nur etwas modifiziert:
ähhh, welchen Code jetzt? Ist da etwas unübersichtlich der Thread.
Gruß aus Berlin
Michael
Hallo,
der crasht ja auch nicht mehr.
Es gibt noch ganz wenige Meldungen im Netz zu Problemen mit externem
Interrupt und z.B. dem ESP8266Webserver.
Scheint wirklich eine race condition zu sein, die ganz unter nicht
sauber behandelt wird.
Gruß aus Berlin
Michael
Dann suche ich auch nicht weiter, brauche wenn dann schon etwas was sich
immer reproduzieren lässt. Läuft jetzt seit 30 Minuten problemlos. Kann
auch den Taster drücken wie ein verrückter Affe.
Ich meine warum ein Minimalbeispiel, wenn es sich dennoch nicht
reproduzieren lässt?
Hallo,
sorry, das hatte sich mit der Änderung überschnitten und mein Text ist
dadurch etwas unstimmig geworden...
Kommentiere in WiFiCheck()
1
// ETS_GPIO_INTR_DISABLE();
2
wifiMulti.run();
3
// ETS_GPIO_INTR_ENABLE();
das Abschalten der GPIO-Interrupts aus, dann sollte er wieder crashen.
Man muß ihn wohl währende des Aufrufs von wifiMulti.run(); im richtigen
Moment erwischen, es passiert nicht immer.
Zum Testen könnten man den Code vermutlich noch stark kürzen, ich (und
der TO) wollte ja was stabil spielendes...
Gruß aus Berlin
Michael
Michael U. schrieb:> Hallo,>> sorry, das hatte sich mit der Änderung überschnitten und mein Text ist> dadurch etwas unstimmig geworden...>> Kommentiere in WiFiCheck()// ETS_GPIO_INTR_DISABLE();> wifiMulti.run();> // ETS_GPIO_INTR_ENABLE();>
Negativ. Bekomme keinen Absturz provoziert
EDIT... Ahh doch. Aber ist wie erwartet ein wdt reset
Hallo,
Timmo H. schrieb:> EDIT... Ahh doch. Aber ist wie erwartet ein wdt reset
warum erwartest Du da einen wdt reset?
Der Programmablauf liefert dazu keinerlei Anlaß.
Gruß aus Berlin
Michael
Okay tritt auch mit ESP.wdtDisable(); Müsste man sich ggf. mal den
ESP8266WiFiMulti::run(void) code genauer ansehen
Michael U. schrieb:> Hallo,>> Timmo H. schrieb:>> EDIT... Ahh doch. Aber ist wie erwartet ein wdt reset>> warum erwartest Du da einen wdt reset?> Der Programmablauf liefert dazu keinerlei Anlaß.>> Gruß aus Berlin> Michael
Ich kannte anfangs den Code nicht (da verheimlicht) und ein
while(irgendwas) blubb(); triggert den wtd nicht, ein delay hingen
schon. (lag of info)
wdt schlägt immer zu wenn nicht regelmässig zurückgesetzt, also auch
nach einem Crash.
Darum tritt er auch hier auf. Die Ursache ist aber der Crash und nicht
das Program
Hallo,
auch hier Zustimmung.
@ Timmo H.: ESP.wdtDisable(); stoppt nur den Sofware-Watchdog.
Der Hardware-Watchdog schlägt in jedem Fall nach rund 6s zu wenn der
nicht von den internen ESp-Routinen zurückgesetzt wird.
PS und völlig OT: 1979 ging hier in der Ex-DDR eine Honeywell-Anlage in
Betrieb, da gab es auch einen Watchdog, den man beim Laden der Software
vom tape abschalten mußte.
Es wurde hier vor Ort eine Übersetzung der Kurzanleitung in Auftrag
gegeben.
Punkt a:
...
Punkt m: kill the watchdog
usw.
Was kam dann vom Übersetzer zurück?
Punkt m: töte den Wachhund ???
Gruß aus berlin
Michael
Ich habe das ganze Dilemma mit external Interrupts mal dokumentiert
(siehe Anhang).
Hilft hoffentlich jemand, zumindest ich verstehe damit in einem Jahr
noch warum der Code so aussieht :-)
Hallo,
schön gemachte Doku, Danke.
Darf man fragen welche Art Projekt das ist, was Du da verfolgst?
Mir fällt im Moment nichts ein, wo ich eine wechselnde Verbindung zu
verschiedenen AP brauche und parallel auch noch mit Hardware-Interrupts
relativ kurzer Dauer konfrontiert wäre.
Ist nur Neugier...
Gruß aus Berlin
Michael
Es handelt sich um eine Stop-Uhr, die elektronisch (per Lichtschranken)
gestartet und gestoppt werden soll.
Die echte Uhr läuft auf dem ESP8266 und schickt die Start- und Stop-Zeit
zu der LED-Anzeige via WiFi. Der AP ist im LED-Display (raspberry)
Die externen Interrupts müssen die Signale von den Lichtschranken
zuverlässig erfassen.
Da die Genauigkeit 1/100 Sekunde (10ms) betragen soll müssen die Signale
als Interrupt erfasst werden (polling ist zu ungenau).
Aber die Interrupt-Rate ist gering, daher funktionieren für mein Project
alle die Workarounds die ich im Dokument beschrieben habe.
Hallo,
ok, trotzdem eine Frage: warum WiFiMulti und kein normaler Connect?
Wechseln denn die AP, daß Du die Listenverwaltung da brauchst?
Ich hatte mich mit meinem Bekannten übder das Problem unterhalte. Der
hat z.B. einen Dimmer mit ESP8266 und MQTT laufen. Der Dimmer macht
Phasenanschnitt mit den 5Hz als Hardware-Interrupt. Der hängt natürlich
immer im gleichen WLAN. Bei reconnects ist da noch nie was abgestürzt.
Hätte er bemerkt, wenn plötzlich seine Wohnzimmerlampe ausgegangen wäre,
weil der ESP als default natülich das Licht ausmacht.
Bei mir habe ich jetzt mal meine Abfragen incl. Deiner IRQ-Sperre in den
Streamplayer mit ES32 reingebuat. Reconnect klappt zumindest
zuverlässig, meine WLAN-Umgebung sordt da leider manchmal dafür. Gibt
logischerweise einen Aussetzer, weil der Ram-Buffer auch auf einem ESP32
da knapp ist.
Er braucht meist weniger als 1 Sekunde für reconnect, Stream neu
aufrufen und MP3 syncronisieren, dann spielt er wieder.
Grund fpr WiFimulti ist eigenlich nur, daß ich den Player öfter mal mit
zu meinem Bekannten nehme wenn wir an der Software rumbasteln. Da
brauche ich dann nicht die WLAN-Daten anpassen, weil er mit in der
AP-Liste steht.
Christian K. schrieb:> Da die Genauigkeit 1/100 Sekunde (10ms) betragen soll müssen die Signale> als Interrupt erfasst werden (polling ist zu ungenau).
müßte ich glatt mal mit rumspielen wie sich Ticker.h z.B. mit 2ms
Aufruffolge benimmt..
Eigentlich braucht Du an der Stelle doch nur einen gültigen timestamp?
Also eine Variable im Ticker hochzählen und beim ext. Trigger den Wert
in eine andere kopieren. Die außen auswerten und wieder auf 0 setzen.
Gruß aus Berlin
Michael
Ich habe jetzt die Nase voll von den externen Interrupts. Heute war die
Uhr das erste mal im Einsatz, drei Abstürze auf den Tag verteilt, obwohl
WiFi connected war.
Ich habe jetzt gerade die SW auf ticker() umgestellt. Hoffe das ist
stabiler.
So zweiter Einsatz-Tag der Stopp-Uhr ist vorbei, es sind keine Abstürze
mehr aufgetreten.
Mein Fazit: ESP8266 Wifi Stack verträgt sich nicht mit (externen)
Interrupts. In Klammern, weil auf einer anderen Seite habe ich auch über
Probleme mit Timer Interrupts und Wifi beim ESP8266 gelesen...
Hallo,
Christian K. schrieb:> So zweiter Einsatz-Tag der Stopp-Uhr ist vorbei, es sind keine Abstürze> mehr aufgetreten.
Danke für die Info und schön wenn es jetzt klappt.
Deine Schlußfolgerung nehme eher zur Kenntnis, ich muß mal schauen, was
mein Bekannter da z.B. bei seinem Dimmer gemacht hat.
Das ein ESP8266 immer für Überraschungen gut ist, bestätige ich Dir aber
auf jeden Fall. Dazu kommt die Einbindung in die ArduinoIDE, die auch
nicht absolut fehlerfrei ist.
Mit dem ESP32 kann man das Überraschungspotenzial zur Zeit aber noch
beachtlich vergrößern. ;-)
Gruß aus Berlin
Michael
Ich kann das in einem einfachen Szenario jetzt auch nicht nachstellen.
Im einfachen Szenario habe ich eine UDP Verbindung und schicke alle
100ms ein Paket raus. Gleichzeitig läuft ein mit 10kHz gepulster externe
Interrupts und nichts crashed (natürlich nur solange WiFi verbunden
ist).
In der echten SW habe ich allerdings zwei UDP Verbindungen auf
verschiedene Ports parallel und asynchron laufen, das kann ich jetzt
nicht so einfach mit einer vereinfachten SW nachstellen