So am wondering if anyone here has experience using FreeRtos on the S3. I want to use both cores, core 0 to handle the I2C sensor (ina238 using Adafruit lib), core 1 to handle the display (a 2.8 TFT Ili9341 using tft_espi).
I already have working code and hardware reading I2C data, and working code and hardware using PSRAM to update two sprites on the display.
I'm learning how the dual core concept works so I can run two processes in parallel.
I don't HAVE TO use 2 cores. I just want to for my own learning purposes. It's not for school. I do have a basic understanding of how it works, using a Mutex to 'hand over a key' between cores, and the stack size.
Have to say the stack size it what concerns me because I have no idea a ballpark to set it at, especially using the libraries I am.
Question: Does anyone have experience using dual cores that can tell me of any potential pitfalls? Any knowledge on stack sizes or any other recommendations is certainly welcome. I do have basic practice code using two cores. Implementing it is going to be a challenge(love it!) ![]()
Again it's mainly for my own learning (and pending frustration
)
Thank you
1. To gain exerience in blinking two LEDs at different rates on seperate cores, you may try the following example:
Figure-1:
//function declarations
TaskHandle_t Task01Handle;
TaskHandle_t Task11Handle;
//GPIO definitions
#define LED 2
#define LED01 21
#define LED11 22
//task creation using FreeRTOS.h Librray functions
void setup()
{
Serial.begin(9600);
pinMode(LED, OUTPUT);
pinMode(LED01, OUTPUT);
pinMode(LED11, OUTPUT);
xTaskCreatePinnedToCore(Task01, "Task-01", 2048, NULL, 0, &Task01Handle, 0);
xTaskCreatePinnedToCore(Task11, "Task-11", 2048, NULL, 1, &Task11Handle, 1);
}
//LED blinks at 4000 ms interval
void loop()
{
digitalWrite(LED, HIGH);
vTaskDelay(2000);
digitalWrite(LED, LOW);
vTaskDelay(2000);
}
//LED10 blinks at 2000 ms interval
void Task01(void *pvParameters)
{
while (true)
{
digitalWrite(LED10, HIGH);
vTaskDelay(1000);
digitalWrite(LED10, LOW);
vTaskDelay(1000);
}
}
//LED11 blinks at 1000 ms interval
void Task11(void *pvParameters)
{
while (true)
{
digitalWrite(LED11, HIGH);
vTaskDelay(500);
digitalWrite(LED11, LOW);
vTaskDelay(500);
}
}
2. The following diagram (Fig-2) may give you some idea.
Figure-2:
3. You may ask ChatGPT for the meaing of each code line of Step-1, but you need to be careful to accept what they deliver. For example: the meaing of this code line: xTaskCreatePinnedToCore(Task01, "Task-01", 2048, NULL, 0, &Task01Handle, 0); is given as:
Create the task with the following parameters:
Task01 (arg1 = the function that will run as the task),
"Task-01" (arg2 = name of the task (for debugging),
2048 (arg3 = give it a 2048-byte stack),
NULL (arg4 = no parameter passed to the task function),
0 (arg5 = priority 0),
Task01Handle (arg6 = save its handle in `Task01Handle`),
0 (arg7 = run the task on Core-0.
4. Please, post a picture of yor ESP32S3 Board.
Even taking into account the size of local variables, nesting between functions, depth of recursive calls, etc., you will probably want to actually check the stack usage of a task.
I haven't looked into how it's done in detail, but you can find out using the following function:
Below are the results for an application currently under development.
Tasks: 8, Runtime: 463s, Period: 463649627us
Num Name Load Prio Free Core State
8 loopTask 4% 1 3328 1 Running
5 IDLE0 5% 0 468 0 Ready
6 IDLE1 2% 0 572 1 Ready
10 audioplay 2% 2 1928 0 Blocked
7 Tmr Svc 0% 1 3604 * Blocked
2 ipc1 0% 24 476 1 Suspended
1 ipc0 0% 24 484 0 Suspended
3 esp_timer 0% 22 8156 0 Suspended
I usually start with a larger stack size than I estimate and gradually reduce it to a reasonable value.
Edit:
The word "watermark" appears on this page.
I think that to estimate memory usage, like the waterline of a quay, the stack area is filled with a specific pattern (e.g., eeeeee...) and the continuation of that pattern is checked. If anyone knows, please let us know ![]()
At the beginning pick a huge stack size somewhere in the range 8k to 16k and use uxTaskGetStackHighWaterMark to see how much is actually being used, then downsize as needed.
Generally speaking FreeRTOS queues provide better decoupling than just using mutexes on their own.
Also tasks that consume data need to run faster than those that generate data otherwise your system can grind to a halt because one is waiting for the other.
Happy to hear that you are keen to practice and learn multitasking using RTOS on an ESP32 variant. I use the 30-pin ESP32, while I also have a few ESP32S3 modules, which have different packages from yours.



