ESP32 – Nutzung beider CPU Kerne für eigene Projekte

Today I want to show which "power resources" are in at ESP32. It is much less known that our ESP32 microcontroller is not a single processor but rather a multi-processor with 2 cores. In the ESP are working 2 Xtensa 32-bit LX6 CPU sharing RAM and ROM. Thus it differs from its predecessor, the ESP8266. The two cores have different names. CPU 0 is also called Protocol CPU (PRO_CPU) and CPU 1 Application CPU (APP_CPU). The CPU 0 controls the WLAN, Bluetooth and other internal peripherals such as SPI, I2C, ADC, etc., while the CPU 1 is available to our user program. Skits that we write in the main loop and upload to the ESP are always executed on the CPU 1 without exception.The APP_CPU (CPU 0) is omitted by default for the application code. The following diagram shows the standard distribution of tasks between the CPUs:

It can be seen that 2 core, which almost doubles the performance of ESP32, is not directly available for free use.

However, the ESP Framework also provides functions with the Arduino IDE that allow to distribute individual tasks to the ESP32 CPUs and thus to the CPU. 

TaskHandle_t NamedesTaskhadle;

 to disposal. To create a new task, we use the function xTaskCreatePinnedToCore with the following options:

 

xTaskCreatePinnedToCore (
    CoreTask0, / - Task function to be called - /
    "Task1", ​​/ - Name of the task Any Name- /
    1000, / - available heap memory of the task - /
    NULL, / - possibly parameter of the task - /
    1, / - task priority - /
    & Core0TaskHnd, / - used task handle - /

 

Our goal is to execute custom code as a task on the CPU1, so as shown below, our code runs as a task on the CPU1 independent of the CPU0, as illustrated in the following image:

 

 

We now enter the following example code in our IDE and upload it to the ESP32:

 

 

TaskHandle_t  Core0TaskHnd ;  
TaskHandle_t  Core1TaskHnd ; 

void setup() 
{
  Serial.begin(9600);  
  xTaskCreatePinnedToCore(CoreTask0,"CPU_0",1000,NULL,1,&Core0TaskHnd,0);
  xTaskCreatePinnedToCore(CoreTask1,"CPU_1",1000,NULL,1,&Core0TaskHnd,1);
}

void loop() 
{
  Serial.print ("Application CPU is on core:");
  Serial.println (xPortGetCoreID());
  delay (500);
}  

void CoreTask0( void * parameter ) 
{ 
  for (;;) 
  { 
    Serial.print("CoreTask0 runs on Core: "); 
    Serial.println(xPortGetCoreID()); 
    yield();
    delay (600);
  } 
} 

void CoreTask1( void * parameter ) 
{ 
  for (;;) 
  { 
    Serial.print("CoreTask1 runs on Core: "); 
    Serial.println(xPortGetCoreID()); 
    delay (700);
  } 
}

 

 

.

Mit der ESP internen Funktion xPortGetCoreID() können wir uns die Kernnummer ausgeben lassen, auf dem unser Codeabschnitt gerade läuft. Diese Kernnummer kann entweder den Wert 0 oder 1 annehmen. Diese Funktion nutzen wir, um seriell Informationen darüber auszugeben, auf welchem Core der Task gerade läuft:

Serial output shows which task is running on which core

Wir sehen nun in der Ausgabe das insgesamt 3 Tasks laufen. Ein Task mit dem Namen „CoreTask 0“ auf CPU 0, ein Task mit dem Namen „CoreTask1“ auf CPU 1 sowie unser Hauptscheifentask (loop) auf Core 1.

Bis jetzt klingt alles zu schön, um wahr zu sein. In der Tat haben wir mit der Nutzung der CPU 0 ein Problem, dem wir Beachtung schenken müssen: Wie auf der oberen Bild gezeigt, läuft auf der CPU 0 auch der Kernel Protokoll Task. Dieser Task kümmert sich unter anderem auch um den WiFi und TCP/IP Stack. Wenn dieser längeren Zeit nicht ausgeführt wird, weil zum Beispiel unser Task zu viel CPU Zeit fordert, kann das System insgesamt instabil werden und abstürzen. 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.

 

em aufmerksamen Leser wird ein weiteres Problem des Codes aufgefallen sein: Das Programm erzeugt 3 Tasks, die unabhängig voneinander z.T. auf unterschiedlichen CPU’s laufen, sich dennoch aber eine Ressource (den COM Port des ESP‘s) teilen. Da grundsätzlich die Tasks nichts voneinander „wissen“ und somit auch nicht, wann eine Ressource von einem anderen Task belegt oder verändert wird., kann es hier zu Kollisionen kommen. Diese verursachen ein nicht vorhersagbares Ergebnis, da nicht genau bestimmt werden kann, zu welcher Zeit welcher Task die Ressource verwendet. Solche Konstellationen können dann im besten Fall entweder in einer programmatischen Race Kondition oder gar in einem Deadlock enden. Was genau ein Deadlock ist, erklärt das Philosophenproblem, where 5 philosophers sit around a spaghetti table, very vivid. I want to avoid mutually exclusion mutual issues through mutual exclusion ( mutex ) and collisions when accessing shared resources search as variables or interfaces avoid,

That puts us in the middle of the topic of interprocess communication . We've learned a lot about tasks and multitasking.

More about task generation and the Real Time Operation System (RTOS) is available in the second part of this series or on ::

https://exploreembedded.com/wiki/index.php?title=Hello%20World%20with%20ESP32%20Explained

And now have fun experimenting.


 

 

Letzter Artikel 1,8 Zoll TFT am ESP-32 Dev Kit C betreiben
Neuer Artikel Heltec Boards über Boardverwalter installieren

Kommentar

Sven - Mai 15, 2019

CPU 1 ist für das Anwenderprogramm verantwortlich.

Der Tippfehler wird bestimmt zeitnah korrigiert.

veit - Mai 14, 2019

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

Hinterlasse einen Kommentar

Kommentare müssen vor der Veröffentlichung überprüft werden

Erforderliche Angabe