Vandaag wil ik laten zien wat 'Performance Resources' in de ESP32 zit. Het is veel minder bekend dat onze ESP32-microcontroller geen enkele processor is, maar een multiprocessor met 2 kernen. In de ESP, 2 xtensa 32-bit LX6 CPUS-werk, die RAM en ROM delen. Dit onderscheidt zich van zijn voorganger, de ESP8266. De twee kernen hebben verschillende namen. CPU 0 wordt ook protocol cpu (pro_cpu) en CPU 1-applicatie CPU (app_cpu) genoemd. De CPU 0 bestuurt Wi-Fi, Bluetooth en andere interne randapparatuur zoals SPI, I2C, ADC, etc., terwijl CPU 1 beschikbaar is voor ons gebruikersprogramma. Schetsen die we in de hoofdlus schrijven en uploaden naar de ESP zal zonder uitzondering op de CPU 1 worden uitgevoerd, terwijl de app_cpu (CPU 0) standaard wordt weggelaten voor de toepassingscode. Het volgende diagram toont de standaardverdeling van taken op de CPU's:
Het is te zien dat 2 kernen bijna verdubbelen, de prestaties van ESP32 zijn niet direct beschikbaar voor gratis gebruik.
Het ESP-framework biedt echter ook functies met de ARDUINO IDE, die individuele taken op de ESP32-CPU's en dus op de CPU kan verdelen.
Taakhandle_t namedistaskle; |
om te verwijderen. Om een nieuwe taak te maken, gebruiken we de XTASKCREATEPINNEDTOCORE-functie met behulp van de volgende opties:
XTASKCREATEPINNEDTOCORE ( |
Ons doel is om aangepaste code uit te voeren als een taak op de CPU1. Daarom wordt onze code uitgevoerd als een taak op de CPU1 onafhankelijk van de CPU0, zoals weergegeven in de volgende afbeelding:
We voeren nu de volgende voorbeeldcode in onze IDE in en nodigen hem uit voor de ESP32:
Taakhandle_t Core0teekhnd ; Taakhandle_t Core1taskhnd ; leegte opgericht() { Serieel.Beginnen(9600); XTASKCREATEPINNEDTOCORE(Coretask0,"CPU_0",1000,NUL,1,&Core0teekhnd,0); XTASKCREATEPINNEDTOCORE(Coretask1,"CPU_1",1000,NUL,1,&Core0teekhnd,1); } leegte lus() { Serieel.afdrukken ("Applicatie CPU is op kern:"); Serieel.Println (XportgetcoreID()); vertraging (500); } leegte Coretask0( leegte * parameter ) { voor (;;) { Serieel.afdrukken("Coretask0 draait op kern:"); Serieel.Println(XportgetcoreID()); rendement(); vertraging (600); } } leegte Coretask1( leegte * parameter ) { voor (;;) { Serieel.afdrukken("Coretask1 werkt op kern:"); Serieel.Println(XportgetcoreID()); vertraging (700); } }
.
Met de ESP Interne functie XPORTGETCOREID () kunnen we het kernnummer doorgeven waarop ons codesectie draait. Dit kernnummer kan de waarde 0 of 1 accepteren. We gebruiken deze functie om seriële informatie te geven over welke kern de taak nu draait:
We zien nu de 3 taken die in de kwestie worden uitgevoerd. Een taak met de naam "Coretask 0" op CPU 0, een taak met de naam "Coretask1" op CPU 1, evenals onze hoofdslop-taak (LOOP) op Core 1.
Tot nu toe klinkt alles te leuk om waar te zijn. In feite hebben we met het gebruik van de CPU 0 een probleem dat we moeten opletten: zoals weergegeven op de bovenste foto, loopt de Kernel Protocol-taak op de CPU 0. Deze taak zorgt voor de WiFi en TCP / IP-stapel onder andere. Als deze langere tijd niet wordt uitgevoerd, omdat onze taak bijvoorbeeld te veel CPU-tijd vereist, kan het systeem onstabiel worden als geheel en een crash. We moeten dus ervoor zorgen dat onze eigen taak geen of slechts maximale zeer kleinschalige vertragingsverklaringen ontvangt, zodat de Kernel-protocoltaak voldoende rekentijd krijgt.
Em Attent-lezers zagen een ander probleem van de code: het programma genereert 3 taken die onafhankelijk van elkaar zijn, bijvoorbeeld op verschillende CPU's, maar nog steeds een bron delen (de COM-poort van de ESP's). In principe weten de taken niets van 'weet' en dus, wanneer een hulpbron wordt bezet of veranderd door een andere taak., Het kan hier komen naar botsingen. Deze veroorzaken een niet-voorspelbaar resultaat, omdat het niet nauwkeurig kan worden bepaald op welke tijd welke taak de bron gebruikt. Dergelijke constellaties kunnen dan op zijn best in een programmatisch Raceconditie of zelfs in één impasse eindigen. Wat is precies een impasse, legt dat uit Philosopher Probleem, waar 5 filosofen een spaghettafel zijn, heel duidelijk. Ik wil wederzijdse problemen vermijden met wederzijdse uitsluiting (Mutex) en botsing bij toegang tot gedeelde bronnen zoeken als variabelen of interfaces.
Dit is waar we in het midden van het onderwerp interprocesscommunicatie bevinden. We hebben veel geleerd over taken en multitasking.
Meer over taakgeneratie en het real-time bedieningssysteem (RTOS) zijn te vinden in het tweede deel van deze serie of op:
https://exploreembedded.com/wiki/index.php?title=Hello%20World%20with%20ESP32%20Explained
En hebben nu het experimenteren van plezier.
5 Reacties
PiffPoff
“Wir müssen also dafür Sorge trage, dass unser eigener Task keine oder nur maximal sehr klein bemessene delay-Anweisungen erhält, damit der Kernel Protokoll Task genügend Rechenzeit zugewiesen bekommt.”
Wenn der andere Task mehr Rechenzeit bekommen soll, dann ist es doch gut wenn der eigene task möglichst lange suspended ist.
Also ist es doch gut wenn der eigene task viele/lange delays hat, oder?
Siggi
Hallo und guten Tag,
herzlichen Dank für die Erklärung. Hat mir sehr dabei geholfen, ein flackerndes Display in den Griff zu bekommen. Unabhängig von der Berechnung wird jetzt die Anzeige über CPU0 ausgegeben.
Kleine Anmerkung zur Ressourcenaufteilung:
Wird eine Funktion aus dem Core Task aufgerufen, wird diese Funktion auch in der zugehörigen CPU ausgeführt.
Liebe Grüße Siggi
doob
{
Serial.begin(9600);
xTaskCreatePinnedToCore(CoreTask0,“CPU_0”,1000,NULL,1,&Core0TaskHnd,0);
xTaskCreatePinnedToCore(CoreTask1,“CPU_1”,1000,NULL,1,&Core0TaskHnd,1);
}
noch ein Tippfehler? sollte es beim zweiten pinning nicht Core1TaskHnd heißen?
Sven
CPU 1 ist für das Anwenderprogramm verantwortlich.
Der Tippfehler wird bestimmt zeitnah korrigiert.
veit
Diese Namentliche Unterscheidung wird getroffen, um zu verdeutlichen, dass die CPU 0 das WLAN, Bluetooth und andere interne Peripheriegeräte wie SPI, I2C, ADC usw. steuert, während die CPU 0 für unser Anwenderprogramm zur Verfügung steht.
bitte korrigieren …. irgendwas müsste von cpu 1 gemacht werden