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:
Wann wird eine task aufgerufen?
wie wird sie verlassen?
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.
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?
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:
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.
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.
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%?
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.
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.
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.
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!
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.
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?
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.
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.
Ich bräuchte hier noch mal Hilfe. Ich hab vermutlich irgendwo ein Problem mit einer Race Condition, und ich vermute es liegt am Timing. Ich hab mir von ChatGPT ein non-blocking delayMicroseconds() basteln lassen, hab aber keine Ahnung ob es funktioniert. Hauptproblem ist, dass diesselbe Funktion auf verschiedenen Cores aus verschiedenen Tasks aufgerufen wird, daher ist für jede Instanz ein eigener Timer notwendig. Momentan wird bei jedem Aufruf ein neuer Timer erstellt, das erzeugt unnötigen Overhead. Versuche den Timer außerhalb der Funktion anzulegen scheitern an den parallelen Instanzen. Vielleicht kann sich das mal jemand mit wirklich Ahnnung angucken?
Momentan wird bei jedem Aufruf ein neuer Timer erstellt, das erzeugt unnötigen Overhead. Versuche den Timer außerhalb der Funktion anzulegen scheitern an den parallelen Instanzen.
Wenn es anders nicht geht, ist der Overhead offenbar nicht unnötig, sondern notwendig.
Hat das Betriebssystem keine fertige Lösung für diese Aufgabe? Ich kann mir nicht vorstellen, daß jeder Anwendungsprogrammierer dieses Rad für sich neu erfinden muss. In der Doku von vTaskDelay() steht nichts von solchen Einschränkungen.
Ich hab vermutlich irgendwo ein
Problem mit einer Race Condition
Hat denn dein aufzuweckender Task auch die höchste Priorität? Sonst wird der Scheduler vermutlich nicht sofort zu diesem wechseln, und dann stimmt die Zeit nicht. Die normale Granularität des Schedulers ist bei den ESP32 IIRC auf 10ms eingestellt.
Ich hab verschiedene Tests mit Debugausgaben über Serial.print gemacht, die Funktion scheint im so darstellbaren Millisekundenbereich ordentlich zu timen. Allerdings sagt das nichts über den Mikrosekundenbereich aus.
Mein kleinstes delay ist 1ms. Mal funktioniert es und mal nicht (der Task, nicht das delay), hab die Vermutung das hier der Overhead ausbremst.
Ich hab vermutlich irgendwo ein
Problem mit einer Race Condition
So ganz klar ist mir jetzt nicht, was genau da im Einzelnen laufen soll.
Aber wenn es nur darum geht, dass die Datenerfassungs-Tasks jede Sekunde laufen sollen, dann nimm doch einfach die Funktion xTaskDelayUntil().
Den Heckmeck mit den Timern brauchst Du dann gar nicht.
Die Task-Prioritäten musst Du allerdings auch so beachten. Die Funktion xTaskDelayUntil() setzt den Task nur in den Zustand Ready. Der Scheduler läßt den nur laufen, wenn er (mit) die höchste Priorität aller Ready Tasks hat.
In der FreeRTOS Config bestimmt übrigens der Parameter configTICK_RATE_HZ die Tick-Rate. Oft ist die auf 100Hz eingestellt.
Ich glaub ich hab das Problem gefunden. Ich hab eine globale Variable mit Namen timer. Die Funktion hat einen esp_timer_handle_t timer. Ich benenne um...
Was soll das "non-blocking" im Kontext von FreeRtos denn sein? Die Zeitscheiben bleiben ja trotzdem 10ms lang. Warum nicht eine simple Schleife, die auf das Verstreichen der benötigten Mikrosekunden "busy" wartet?
Wie viele Mikrosekunden sind es denn? Was soll die CPU in den paar Mikrosekunden denn alles schaffen? Ist es nicht möglich, die Aufgabe in Hardware laufen zu lassen (PWM, DMA, ...)?
Ich finde ja "während der delay() Pause" ist korrektes deutsch, und über Dein Denglisch in so manchen KiCad T̶h̶r̶e̶a̶d̶s̶ Themen wollen wir nicht streiten :P
Ja, davon hat ChatGPT auch keine Ahnung, es schwafelt nur beeindruckend.
ChatGPT ist zumindest auf das Problem eingegangen nachdem ich erklärt habe warum vTaskDelay() nicht brauchbar ist. Und schlägt nun vor den Overhead (~100µs) zu reduzieren mit einem Lazy-Init Timer in einer Klasse, und einem Makro Wrapper der für jede Instanz automatisch eine neue Funktion deklariert so dass man delay_us() wie bisher aufrufen kann. Gefällt mir aber nicht so, da das dann zur Compile Time passiert. Dann lieber die Tick-Rate erhöhen.
Die Funktion selbst war ja auch letztendlich nicht das Problem, der Fehler mit der vermeintlichen Race Condition lag beim Anwender (Namenskollision global/statisch timer)
In der Zeit soll ein anderer Task was machen dürfen.
Wenn du während des Wartens zu einem anderen Task schalten lässt, wie soll FreeRtos dann. nach Ablauf der Wartezeit zu dem Wartetask zurückschalten? Dazu braucht es ein Ereignis, entweder einen Tick des Schedulers (nur alle 10ms), oder einen Interrupt, oder die Kooperation des anderen Tasks.
Die Timer-Interruptlösung hat dir ChatGPT aufgedröselt.
Für die Schedulerlösung müsstest du wohl tatsächlich die Tickrate erhöhen.
Kooperativ könnte noch funktionieren, je nachdem wie der "andere Task" strukturiert ist, also ob der "andere Task" häufig und regelmäßig genug deinen Wartetask über eine Semaphore oder so "anpingen" kann, und dieser dann prüft, ob die Wartezeit abgelaufen ist, und falls nicht die Kontrolle wieder "kurz" an den "anderen Task" abgibt.