Forum: Mikrocontroller und Digitale Elektronik ESP32 woher kommen alle 5 Minuten DMA Probleme?


von Dirk E. (dirk_1980)


Lesenswert?

Hallo.
Ich habe einen ESP32-S3 am laufen und ca. alle 5 Minuten habe ich ein 
Problem mit vermutlich einem DMA.

Zum Projekt: SPI Display, Kamera, SD und I2S sind parallel am laufen.
WLAN & BT sind aus, denke ich wenigstens weil ich das alles deaktiviert 
habe und kein Init davon mache. Aber was der ganze FREERTOS kram da noch 
verstalltet kann ich nicht erkennen.
Der Code ist basiert auf dem ofizellen CAM Treiber und einem WEB Player 
mit Display. Also eigentlich funktionieren Funktionen.

Von der SD Karte werden MP3 Daten abgespielt und auf dem Display der 
Titel oder Menue angezeigt. Im Hintergrund wird das Kammerabild 
eingeblendet.
Über eine Taste kann man zwischen Kamera, Mix und Menu umschalten.

So ca. alle 5 Minuten gibt es ein grossen Knall und das Bild & Ton sind 
kurz gestört. Ist mir beim Bild zuerst aufgefallen.

Was ich bis jetzt sehen kann ist das plötzlich Daten im Kammera DMA 
Speicher fehlen oder einfach nur komplett anders sind wie normal 
(Standbild mit XOR vergleich zum vorherigen Bild).
Bei dem I2S Daten kann ich das nicht sehen, der Speicher dafür wird aber 
gefüllt. Ob die SPI zum Display auch probleme hat kann ich leider auch 
nicht erkennen. Dafür müsste ich auch diesen Bus auswerten und ob man 
das dann dadrin findet ist offen.

Es ist schon recht komisch, das ganze passiert recht genau alle 5min 
+-20sec.

Kennt jemand so ein Problem?
Was kann das sein?

von Andras H. (kyrk)


Lesenswert?

Überlauf einer Register? Kommt es denn genau alle 5 Minunten? Oder 
irgendwie 4,2? Könnte auch ein Watchdog sein der nicht bedient ist.

DMA und Cache? Wie ist der Cachecoherenz sichergestellt?

Debuggen? Gibt es für den ESP32 richtige debuggers mit breakpoints und 
so? Wenn ja dann ran an das Gerät und gucken was da so läuft.

von Dirk E. (dirk_1980)


Lesenswert?

Im Debugger sieht man nichts.
Alles scheint richtig zu sein, ausser den Daten.
Schade da du diese Frage stellst benutzt Du anschined nicht diesen 
Prozessor.

Alles was WD heist ist auf anderen Werten, außerdem würde der sich auch 
anders melden.

Tja ein Überlauf könnte zwar sein aber da müsste man erst mal was 
finden, in dem von mir zusammen gebauten Code ist jedenfalls nichts 
dergleichen drin.
Und der Systemtimer ist da noch lange nicht übergelaufen.

DMA & Interrupts sind im IRAM gelegt damit mir kein Code laden rein 
funken kann.

Kann mir jemand sagen auf welchem Kern diese Funktionen laufen?

von Dirk E. (dirk_1980)


Lesenswert?

portENTER_CRITICAL ist der Feind!

Ich habe damit Zugriffe auf Ansammlungen von Globalen Variablen von 
einem Task durch einen 2. Task verhindert.
Nachdem ich das nun einfach mal ausgeklammert habe läuft alles 
anscheined sauber (45min).
Weitere Tests über mehrere Stunden muss ich noch machen.

Warum das überhaupt so kritisch ist könnte ich versuchen abzuklären, ist 
mir aber nicht wichtig genug.
Unter einem AVR oder unter einem STM32 hatte ich jedenfalls noch nie so 
ein Problem gehabt, obwohl ich bei Projekten darauf portENTER_CRITICAL 
sehr viel öfter benutze.

von Monk (roehrmond)


Lesenswert?

Gebe dir mal alle 100ms den freien Heap aus.

Ich würde auch den Stack kontrollieren. Wegen dem OS gibt es vermutlich 
für jeden Thread einen eigenen Stack, oder?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Dirk E. schrieb:
> portENTER_CRITICAL ist der Feind!

Vielleicht nimmst Du eher taskENTER_CRITICAL(). Siehe auch: 
Beitrag "Re: ESP32 Tasks portENTER_CRITICAL"

Laut https://www.freertos.org/taskENTER_CRITICAL_taskEXIT_CRITICAL.html 
scheint das auch das bessere Mittel zu sein.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Warum kein Mutex? Der ermöglicht es dem RTOS den wartenden Thread 
schlafen zu legen wenn gerade ein anderer Thread auf die Daten zugreift.

portENTER_CRITICAL ist auf ESP32 anscheinend ein Spinlock. D.h. ein 
Thread welcher gerade nicht zugreifen kann rotiert "sinnlos" in einer 
Endlosschleife, bis der andere Thread, welcher den Lock aquiriert hat, 
diesen wieder freigibt.

Bei Dual-Core (ESP32S3) wird so die Leistung eines Cores verschwendet, 
der auch andere Threads ausführen könnte.

Bei Singlecore wird der Timeslice des wartenden Threads verschwendet. 
Erst wenn der präemptive Scheduler (Round Robin) den wartenden Thread 
nach Ablaufen der Timeslice unterbricht und zum ersten Thread 
zurückwechselt kann dieser mit den Daten weiter arbeiten und den 
Spinlock wieder freigeben.

Da ist es natürlich kein Wunder dass es nicht gut läuft. Oder überseh 
ich was?

von Dirk E. (dirk_1980)


Lesenswert?

So ich habe nun etwas gelesen und mir einige meiner alten Projekte 
angesehen.

Das portENTER_CRITICAL in den alten Projekten ist auch falsch, da fällt 
es nur nicht auf weil da immer nur die SIO parallel per Interrupt läuft.

Jetzt mit der Kammera und den Interrupts dazu ist es halt einfacher zu 
treffen.

vTaskSuspendAll & xTaskResumeAll sind da wohl erstmal die bessere Wahl.
Auch wenn xTaskResumeAll die Interrupts kurz abschaltet.

Mutex ist auch eine gute Möglichkeit, macht aber hier und da es auch 
komplizierter wie es sein müsste.

Am besten man blockiert nichts!
Bis auf eine Stelle konnte ich das auch umbauen und dafür finde ich auch 
noch eine Lösung.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Dirk E. schrieb:
> vTaskSuspendAll & xTaskResumeAll sind da wohl erstmal die bessere Wahl.

Espressif sagt dazu:

> Given that scheduler suspension on ESP-IDF FreeRTOS will only suspend scheduling 
on a particular core, scheduler suspension is NOT a valid method ensuring mutual 
exclusion between tasks when accessing shared data. Users should use proper 
locking primitives such as mutexes or spinlocks if they require mutual exclusion.

Außerdem interferiert es mit Delay-Aufrufen auf der anderen CPU.

Dirk E. schrieb:
> Mutex ist auch eine gute Möglichkeit, macht aber hier und da es auch
> komplizierter wie es sein müsste.

Mutexe sind halt das Mittel der Wahl unter einem (RT)OS. Den Scheduler 
anzuhalten ist die ziemliche Holzhammermethode. Außerdem gibt es 
natürlich noch Atomics und beim ESP-IDF ist auch ein sehr hilfreicher 
thread-sicherer Ringbuffer mitgeliefert.

Ein korrekt(!) mithilfe von Mutex, Semaphore, Atomics implementierter 
Code funktioniert automatisch korrekt und effizient(!) auf Single- und 
Multicore-Prozessoren, weil man mithilfe dieser Primitive dem Scheduler 
genau mitteilt, welche Code-Abschnitte parallel ablaufen dürfen und 
welche nicht. Der Scheduler kann somit immer Threads finden, welche 
parallel laufen dürfen, und diese auf die Cores verteilen. Wenn man 
einfach den Scheduler abwürgt existiert diese Information nicht, und es 
skaliert nicht.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.