I’m experimenting with FreeRTOS on an ESP32 in Arduino IDE. I have two tasks on the same core: a red LED toggling every 500 ms and a green LED toggling every 1000 ms. *so every 1000 ms both tasks become ready to run at the same time.
Visually both LEDs blink correctly, but I’m trying to understand the exact rule. When two equal-priority tasks become ready to run at same time, who runs first because both can’t run at same time so how does FreeRTOS decide who run first in my case
#include <Arduino.h>
#define RED_LED 16 // external Red LED
#define GREEN_LED 18 // external Green LED
TaskHandle_t redTaskHandle = NULL;
TaskHandle_t greenTaskHandle = NULL;
// Red LED Task (500ms blink)
void TaskRedLED(void *parameter) {
pinMode(RED_LED, OUTPUT);
for (;;) {
digitalWrite(RED_LED, HIGH);
Serial.print("Red LED ON | running on core ");
Serial.println(xPortGetCoreID());
vTaskDelay(pdMS_TO_TICKS(250));
digitalWrite(RED_LED, LOW);
Serial.print("Red LED OFF | running on core ");
Serial.println(xPortGetCoreID());
vTaskDelay(pdMS_TO_TICKS(250));
}
}
// Green LED Task (1000ms blink)
void TaskGreenLED(void *parameter) {
pinMode(GREEN_LED, OUTPUT);
for (;;) {
digitalWrite(GREEN_LED, HIGH);
Serial.print("Green LED ON | running on core ");
Serial.println(xPortGetCoreID());
vTaskDelay(pdMS_TO_TICKS(500));
digitalWrite(GREEN_LED, LOW);
Serial.print("Green LED OFF | running on core ");
Serial.println(xPortGetCoreID());
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void setup() {
Serial.begin(115200);
delay(1000);
// Both tasks pinned to the same core (core 0)
xTaskCreatePinnedToCore(
TaskRedLED,
"Red LED Task",
2048,
NULL,
1,
&redTaskHandle,
0 // core 0
);
xTaskCreatePinnedToCore(
TaskGreenLED,
"Green LED Task",
2048,
NULL,
1,
&greenTaskHandle,
0 // core 0
);
}
void loop() {
// Nothing here
}
If they are of the same priority, FreeRTOS doesn’t make an promises on the order, but it will be deterministic based on the code. Tasks of a given priority run in the order they became ready, so the first one released by the scheduler would run first. The block list is scanned in order to see who should become ready now, on a list that is sorted by the time the task should become ready.
The one thing I don’t know is if a task is added to the block list with a same wakeup time as another task, will it be put in front or behind that task. IE does it scan until if finds the next task doesn’t want to wake up before it, or does it continue until if finds the task that wants to wake up after it. The first is a bit more efficient, so would be my choice, I just haven’t looked at the code in that detail to tell. The second might be used if it make it better for other usess of list, like tasks waiting to take a semaphore, where you would want first come first served at the same priority.
If they are of the same priority, FreeRTOS doesn’t make an promises on the order, but it will be deterministic based on the code.
This is correct in every way.
Now to give the exact order since I happened to have looked at the code recently I will contrive an example. Let’s say you create your red blink task before your green blink task.
At Tick=0 your ready list and delayed list would look like:
At tick 500 the TaskRedLED is removed from the delayed list and added to the ready list. It completes and is added to the back of the delayed list to wake up at tick 1000.
Tasks are removed from the delayed list starting from the front of the list. Tasks are added to the end of the ready list (corresponding the priority). This means that the ordering is preserved - TaskGreenLED will execute before TaskRedLED at Ticks which are a multiple of 1000.
So FreeRTOS doesn’t guarantee one specific task will always run first, but if two tasks become ready to run on the same tick, the one that was placed into the blocked list first will be moved back to the ready list first so in practice, creation order decides. Is that correct?
At the start both Red and Green are ready, but because Red was created first it runs first. Red delays for 250 ms and goes blocked, then Green gets the CPU, toggles, and also blocks. At 250 ms Red wakes, runs, then blocks again until 500 ms. At 500 ms both Red and Green become ready together. Since FreeRTOS preserves the order they were inserted into the delayed list, Green is scheduled first, then Red. So just to confirm, this ordering is strictly because of task creation order if I had created Green before Red, then Red would always run after Green at these collision points, correct?
Not “Creation” order, but the order they last blocked, so the one with the longer block time will run first. If they both have the same block time, it will be the order they last ran to there blocking operation.
If you want to force an order, use priority, that is what it is for.
It should be added here that FreeRTOS, being open source, allows both an in-depth study of the exact beahvior by looking at the source and adjusting the behavior to one’s own needs. The identifier used to determine which task to schedule next is (appropriately named) taskSELECT_HIGHEST_PRIORITY_TASK and can be found here: