Forum: Mikrocontroller und Digitale Elektronik ESp32 Multithreading


You were forwarded to this site from EmbDev.net. Back to EmbDev.net
von Thorsten M. (cortex_user)


Lesenswert?

Moin,

auch wenn alles mit einem 1s Timer Int läuft, mich reizt jetzt die 
Auslagerung der Datenerfassung eines ADC115 auf den anderen Core. Ich 
habe mir das angeschhaut wie man mit xcreate... Tasks zeugt aber 
versteht folgendes nicht:

1. Wann wird eine task aufgerufen?
2. wie wird sie verlassen?
3. wie oft wird sie aufgerufen?

In Beispielen stehen da ständig Endlos Schleifen drin. Wozu das? Ohne 
stürzt der ESp32 ab.

Ich muss 1x die Sekunde daten in Arrays einschreiben. Das dauert fast 
150ms.  Das soll nicht mehr das Hauptprogramm auf Core1 machen sondern 
der andere Kern. Core 1 greift nur atomar lesend auf Variablen zu, d.h. 
Core 0 kann da reinschhreiben.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thorsten M. schrieb:
> Wann wird eine task aufgerufen?

Die Task-Funktion wird aufgerufen sobald man den Task erzeugt hat.

Thorsten M. schrieb:
> wie wird sie verlassen?

Nie, bei FreeRTOS sollten Tasks nicht zurück kehren sondern in einer 
Endlosschleife laufen.

Thorsten M. schrieb:
> wie oft wird sie aufgerufen?

Genau so oft wie du xTaskCreate aufrufst, also typischerweise 1x.

Thorsten M. schrieb:
> In Beispielen stehen da ständig Endlos Schleifen drin. Wozu das? Ohne
> stürzt der ESp32 ab.

Weil man unter FreeRTOS Threads nicht beenden kann. Ist auch meistens 
nicht nötig. Du lässt den Task halt endlos laufen.

: Bearbeitet durch User
von Thorsten M. (cortex_user)


Lesenswert?

Ok .. ich will aber keine delay 1000 da reinschreiben muessen. Die Task 
wird ja sicherlich vom scheduler unterbrochen. Sonst saesse der Core ja 
fest. Wie kriege ich es hin, dass die Task nur alle 1s Daten holt?

von Harry L. (mysth)


Lesenswert?

Niklas G. schrieb:
> Weil man unter FreeRTOS Threads nicht beenden kann.

Natürlich kann man Tasks auch wieder beenden, und das ist auch durchaus 
nichts Ungewöhnliches.

Seite 53:
https://www.freertos.org/fr-content-src/uploads/2018/07/FreeRTOS_Reference_Manual_V10.0.0.pdf

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thorsten M. schrieb:
> Ok .. ich will aber keine delay 1000 da reinschreiben muessen.

Warum nicht?

Thorsten M. schrieb:
> Wie kriege ich es hin, dass die Task nur alle 1s Daten holt?

Mit Delay, oder präziser mit dem Timer API:

https://www.freertos.org/RTOS-software-timer.html

Die Timer Callbacks laufen aber alle in einem Thread.

PS:
Wenn du deinen Task nicht permanent benötigst, und die Datenerfassung 
ein-und ausschalten möchtest, kannst du den Task (in der Endlosschleife) 
zwischenzeitlich schlafen legen und bei Bedarf aufwecken. Das geht u.a. 
mit dem Notification API:

https://www.freertos.org/RTOS-task-notifications.html

Das reduziert die Leistungsaufnahme.

von Thorsten M. (cortex_user)


Lesenswert?

Also quasi jede Sekunde die Task wrzeugen und mit vdeleteTask wieder 
verlassen? Und das alles von Core 1 aus? Die spielt dann ja von allein 
denke ich

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Harry L. schrieb:
> Natürlich kann man Tasks auch wieder beenden, und das ist auch durchaus
> nichts Ungewöhnliches.

Ja richtig, habe was verwechselt. Nur zurückkehren darf die 
Task-Funktion nicht, weil der vPortTaskWrapper vom ESP32 danach einen 
abort() hat.

von Harry L. (mysth)


Lesenswert?

Thorsten M. schrieb:
> Also quasi jede Sekunde die Task wrzeugen und mit vdeleteTask wieder
> verlassen?

Nein!

Einfach mit delay schlafen legen.
Der Sheduler kümmert sich um den Rest.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thorsten M. schrieb:
> Also quasi jede Sekunde die Task wrzeugen und mit vdeleteTask
> wieder
> verlassen? Und das alles von Core 1 aus? Die spielt dann ja von allein
> denke ich

Nein, den Task permanent laufen lassen. Entweder per Delay zwischendurch 
schlafen legen oder per Software Timer und xTaskNotify aufwecken. Tasks 
ständig zu erzeugen und wieder löschen macht wenig Sinn.

von Thorsten M. (cortex_user)


Lesenswert?

Ich muss mir das erstmal bildlich aufmalen. Der delay(1000) in der Tasks 
blockiert also den Core nicht? Die Datensammlung laeuft rund um die Uhr 
bei mir. Die Arrays liegenn im RTC Ram und werden nur gelesen von der 
loop im Arduino.

von Harry L. (mysth)


Lesenswert?

Thorsten M. schrieb:
> Der delay(1000) in der Tasks
> blockiert also den Core nicht?

Nein.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thorsten M. schrieb:
> Der delay(1000) in der Tasks blockiert also den Core nicht?

Nein, FreeRTOS führt dann andere Tasks aus, oder eben den Idle-Task. Ein 
schlafender Task verbraucht keine Rechenzeit (und keine Energie!). Das 
kannst du am PC ausprobieren: Starte in einem Programm so viele Threads 
wie CPU-Cores existieren (oder auch viel mehr), die alle nur Sleep 
aufrufen. Friert der PC ein? Geht die CPU-Last auf 100%?

von Thorsten M. (cortex_user)


Lesenswert?

Ok, ich bedanke mich erstmal. Viele Texte im Netz vergessen es, dass man 
erstmal das Ganze verstehen muss, bevor man sich mit den Details 
befasst.

Also das ginge auch:

Core 1 (der wo alles drauf läuft)):

Global:
3x arrays

loop () {

   if (Flags.1s)
     erzeuge task Datensammeln

}

task datensammeln() {

  Hole 1 Datum pro Durchlauf und schreibe es ein
  Bilde Mittelwerte
  zerstöre task;
}

alternativ wird die task nur einmal im setup erzeugt und dann

task datensammeln() {

  while (1) {
  Hole 1 Datum pro Durchlauf und schreibe es ein
  Bilde Mittelwerte
  delay(1000)
}
}

von Thorsten M. (cortex_user)


Lesenswert?

Niklas G. schrieb:
> Nein, FreeRTOS führt dann andere Tasks aus, oder eben den Idle-Task.

da liest man noch etwas von yield() und vdelay(), die benutzt werden 
sollen, da delay scheinbar doch blockiert.

https://www.esp32.com/viewtopic.php?t=8944#:~:text=This%20is%20vTaskDelay%20%28pdMS_TO_TICKS%20%2810%29%29%20a%20delay%20of,pdMS_TO_TICKS%20%28X%29%20which%20will%20do%20it%20for%20you.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Was erhoffst du dir davon den Task ständig zu zerstören und neu zu 
erstellen? Das ist eine Menge Overhead.

FreeRTOS verteilt die Tasks automatisch auf die beiden Cores. Es kann 
dir recht egal sein was genau auf Core 0 und 1 läuft.

von Thorsten M. (cortex_user)


Lesenswert?

Niklas G. schrieb:
> Was erhoffst du dir davon den Task ständig zu zerstören und neu zu
> erstellen? Das ist eine Menge Overhead.

Bei einer CPU, die 240 Mio Ops/s macht ist mir das völlig wumpe..... 
aber ich werde wohl die bessere Möglichkeit wählen. Ich nutze kein 
FreeRTOS, nur die beidden Funktionen daraus. Mein programm existiert 
schon und ist sehr gross.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thorsten M. schrieb:
> da delay scheinbar doch blockiert.

Ich denke du meinst vTaskDelay? Ja, das blockiert, im Sinne von dass der 
Scheduler diesen Task nicht mehr ausführt bis die Zeit abläuft. Der CPU 
Kern ist dann frei für andere Tasks.

Thorsten M. schrieb:
> Bei einer CPU, die 240 Mio Ops/s macht ist mir das völlig wumpe

Du machst dir ja schon Gedanken beide Cores zu benutzen, also scheinen 
einmal 240 Mio OPs nicht zu reichen...?

Thorsten M. schrieb:
> Ich nutze kein FreeRTOS, nur die beidden Funktionen daraus

Auf den ESP32 musst du FreeRTOS benutzen. Das läuft immer im 
Hintergrund. ESP-IDF startet das automatisch.

von Thorsten M. (cortex_user)


Lesenswert?

Niklas G. schrieb:
> Du machst dir ja schon Gedanken beide Cores zu benutzen, also scheinen
> einmal 240 Mio OPs nicht zu reichen...?

Kannst ja mal reinschauen wo für das alles gut ist, der Link ist noch 
ein paar Tage gültig, habe das im Gast wlan laufen. Der ESP32 Firebeetle 
steuert mittlerweile so viele Relais und Geräte... ist schon ein geiles 
Teilchen.

http://l11vzu256z3bfz2j.myfritz.net/abfrage?pass=myesp32

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Thorsten M. schrieb:
>  da delay scheinbar doch blockiert.

Welche eine rege Fantasie!
Einbildung, statt Doku lesen...

Tipp:
Man kann auch in den Quellcode schauen, wenn man wissen will was delay() 
tut.
https://github.com/espressif/arduino-esp32/blob/1a7962ece8a4c6ffa1d64c5a86ed8ee58dde10ba/cores/esp32/esp32-hal-misc.c#L176

Er liegt auch auf deinem Rechner.

Beitrag #7419465 wurde vom Autor gelöscht.
von Thorsten M. (cortex_user)


Angehängte Dateien:

Lesenswert?

So, alles ausprobiert, chatGPT schreibt auch den Code und das sogar 
richtig.
Das Teil ist einfach nur genial, wenn man alles nochmal überprüft...
vTaskDelay ist übrigens richtig!

von Mike R. (thesealion)


Lesenswert?

Thorsten M. schrieb:
> So, alles ausprobiert, chatGPT schreibt auch den Code und das sogar
> richtig.

Aber nur wenn der Kopierer auch weiß, dass er den Semaphore vorher auch 
noch erzeugen muss. Ansonsten gibt es Schiffbruch.

von Thorsten M. (cortex_user)


Lesenswert?

Mike R. schrieb:
> Aber nur wenn der Kopierer auch weiß, dass er den Semaphore vorher auch
> noch erzeugen muss. Ansonsten gibt es Schiffbruch.

Nein, das nicht aber ein Reset :-) Überdies ist der Reset die Antwort 
des ESP32 auf alles, ähnlich "42".

In meiner Awendung läuft tasking nicht, vermutlich weil ich die Hardware 
Timer benutze und ne Menge Interfaces. In einer Beispeilanwendung klappt 
alles prima. Wenn FReeRtOS dann auch nur diese API nutzen,. die zb für 
die Timer nur soft Timer vorsieht.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thorsten M. schrieb:
> Nein, das nicht aber ein Reset

Haha, bei Race Conditions passieren irgendwie unvorhersehbaren, gerne 
auch unbemerkte, Probleme. Irgendwann macht das Programm nicht 
reproduzierbar irgendwas komisches und keiner weiß warum. Ein reset wäre 
ja schön, da bemerkt man wenigstens dass was schief läuft. Aber woher 
soll der ESP32 wissen dass da eine Race Condition vorliegt?

Thorsten M. schrieb:
> In meiner Awendung läuft tasking nicht

Wie hast du das hinbekommen? Das ESP-IDF (welches ja Teil des Arduino 
ESP32 Framework ist) startet automatisch FreeRTOS und den Scheduler. 
Ohne das funktioniert weder das ESP-IDF, noch das Arduino Framework, 
noch die WiFi-Funktion.

Thorsten M. schrieb:
> die zb für die Timer nur soft Timer vorsieht.

Die Soft Timer funktionieren ebenfalls nur wenn FreeRTOS "richtig" 
läuft.

PS: Von mehreren Threads aus auf I²C zugreifen (und das per Semaphore 
absichern) finde ich übrigens nicht besonders clever, weil I²C ja 
ziemlich langsam ist und somit mehrere Threads für längere Zeit 
blockiert werden und nichts anderes tun können. Ich würde das eher von 
einem einzelnen Thread aus machen und diesen asynchron mit den anderen 
Threads kommunizieren lassen.

: Bearbeitet durch User
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.