- Discussion
- Useful Resources
- Quick Guide
- Next steps for you as a developer
- Applications of ESP32
- Performing the (OTA) update of ESP32 firmware
- Getting current time using NTP Client
- Transmitting data over Bluetooth
- Transmitting data over WiFi using MQTT
- Transmitting data over WiFi using HTTPS
- Transmitting data over WiFi using HTTP
- WiFi on ESP32
- Interfacing OLED Display with ESP32
- ESP32 SPIFFS storage (A mini-SD Card in the chip itself)
- ESP32 Preferences
- Interfacing ESP32 with Analog sensors
- Interfacing ESP32 with MPU6050
- Setting up RTOS for dual-core and multi-threaded operation
- Installing the ESP32 Board in Arduino IDE
- Introduction to ESP32
- Brief Overview of IoT
- Home
Selected Reading
- Who is Who
- Computer Glossary
- HR Interview Questions
- Effective Resume Writing
- Questions and Answers
- UPSC IAS Exams Notes
Setting up RTOS for dual-core & multi-threaded operation
A key feature of ESP32 that makes it so much more popular than its predecessor, ESP8266, is the presence of two cores on the chip. This means that we can have two processes executing in parallel on two different cores. Of course, you can argue that parallel operation can also be achieved on a single thread using FreeRTOS/ any other equivalent RTOS. However, there is a difference between two processes running in parallel on a single core, and they running in parallel on different cores. On a single core, often, one thread has to wait for the other to pause before it can begin execution. On two cores, parallel execution is pterally parallel, because they are pterally occupying different processors.
Sounds exciting? Let s get started with a real example, that demonstrates how to create two tasks and assign them to specific cores within ESP32.
Code Walkthrough
GitHub pnk:
To use FreeRTOS within the Arduino IDE, no additional imports are required. It comes inbuilt. What we need to do is define two functions that we wish to run on the two cores. They are defined first. One function evaluates the first 25 terms of the Fibonacci series and prints every 5th of them. It does so in a loop. The second function evaluates the sum of numbers from 1 to 100. It too does so in a loop. In other words, after calculating the sum from 1 to 100 once, it does so again, after printing the ID of the core it is executing on. We are not printing all the numbers, but only every 5th number in both the sequences, because both the cores will try to access the same Serial Monitor. Therefore, if we print every number, they will try to access the Serial Monitor at the same time frequently.
void print_fibonacci() { int n1 = 0; int n2 = 1; int term = 0; char print_buf[300]; sprintf(print_buf, "Term %d: %d ", term, n1); Serial.print(print_buf); term = term + 1; sprintf(print_buf, "Term %d: %d ", term, n1); Serial.print(print_buf); for (;;) { term = term + 1; int n3 = n1 + n2; if(term%5 == 0){ sprintf(print_buf, "Term %d: %d ", term, n3); Serial.println(print_buf); } n1 = n2; n2 = n3; if (term >= 25) break; } } void sum_numbers() { int n1 = 1; int sum = 1; char print_buf[300]; for (;;) { if(n1 %5 == 0){ sprintf(print_buf, " Term %d: %d ", n1, sum); Serial.println(print_buf); } n1 = n1 + 1; sum = sum+n1; if (n1 >= 100) break; } } void codeForTask1( void * parameter ) { for (;;) { Serial.print("Code is running on Core: ");Serial.println( xPortGetCoreID()); print_fibonacci(); } } void codeForTask2( void * parameter ) { for (;;) { Serial.print(" Code is running on Core: ");Serial.println( xPortGetCoreID()); sum_numbers(); } }
You can see above that we have shifted the print statement for Task 2 to the right. This will help us differentiate between the prints happening from Task 1 and Task 2.
Next we define task handles. Task handles serve the purpose of referencing that particular task in other parts of the code. Since we have two tasks, we will define two task handles.
TaskHandle_t Task1, Task2;
Now that the functions are ready, we can move to the setup part. Within setup(), we simply pin the two tasks to the respective cores. First, let me show you the code snippet.
void setup() { Serial.begin(115200); /*Syntax for assigning task to a core: xTaskCreatePinnedToCore( coreTask, // Function to implement the task "coreTask", // Name of the task 10000, // Stack size in words NULL, // Task input parameter 0, // Priority of the task NULL, // Task handle. taskCore); // Core where the task should run */ xTaskCreatePinnedToCore( codeForTask1, "FibonacciTask", 5000, NULL, 2, &Task1, 0); //delay(500); // needed to start-up task1 xTaskCreatePinnedToCore( codeForTask2, "SumTask", 5000, NULL, 2, &Task2, 1); }
Now let s spane deeper into the xTaskCreatePinnedToCore function. As you can see, it takes a total of 7 arguments. Their description is as follows.
The first argument codeForTask1 is the function that will be executed by the task
The second argument "FibonacciTask" is the label or name of that task
The third argument 1000 is the stack size in bytes that is allotted to this task
The fourth argument NULL is the task input parameter. Basically, if you wish to input any parameter to the task, it goes here
The fifth argument 1 defines the priority of the task. The higher the value, the more is the priority of the task.
The sixth argument &Task1 is the Task Handle
The final argument 0 is the Code on which the task will run. If the value is 0, the task will run on Core 0. If it is 1, the task will run on Code 1.
Finally, the loop can be left empty, since the two tasks running on the two cores are of more importance here.
void loop() {}
You can see the output on the Serial Monitor. Note that there are no delays anywhere in the code. Therefore, both the series getting incremented shows that the computations are happening in parallel. The Core IDs printed on the Serial Monitor also confirm that.
Please note that Arduino sketches, by default, run on Core 1. This can be verified using Serial.print( xPortGetCoreID()); So if you add some code in loop(), it will run as another thread on Core 1. In that case, Core 0 will have a single task running, while Core 1 will have two tasks running.
Advertisements