// Question: How pre-emptive is FreeRTOS on a single core ?
// Answer : It is fully pre-emptive in every way, you won't notice it.
// This Wokwi project:
// https://wokwi.com/projects/403103153803776001
// Previous test with classic ESP32:
// https://wokwi.com/projects/403090705288099841
const int pinLedZero = 7;
const int pinLedOne = 6;
const int pinLedTwo = 5;
const int pinLedThree = 4;
volatile unsigned long counterOne;
bool stateOne = false;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Test with ESP32-C3, single core RISC-V");
pinMode(pinLedZero, OUTPUT);
// Not only the priority can be set,
// some systems have a extra "portPRIVILEGE_BIT"
xTaskCreate(taskOne, "One" , 1000, NULL, 1, NULL);
xTaskCreate(taskTwo, "Two" , 1000, NULL, 1, NULL);
xTaskCreate(taskThree, "Three", 1000, NULL, 1, NULL);
}
void loop()
{
Serial.print("Task Zero: counter of task One is = ");
Serial.println(counterOne);
delay(1000);
digitalWrite(pinLedZero, HIGH);
delay(200);
digitalWrite(pinLedZero, LOW);
}
void taskOne(void * pvParameters)
{
pinMode(pinLedOne, OUTPUT);
// Blocking code ! No delay, no wait.
// Comment out the digitalWrite to be 100% sure.
// The other tasks run as well.
for(;;)
{
counterOne++;
if(counterOne % 500000UL == 0)
{
digitalWrite(pinLedOne, stateOne ? HIGH : LOW);
stateOne = !stateOne;
}
}
}
void taskTwo(void * pvParameters)
{
pinMode(pinLedTwo, OUTPUT);
for(;;)
{
digitalWrite(pinLedTwo, HIGH);
delay(1000); // delay calls vTaskDelay
digitalWrite(pinLedTwo, LOW);
delay(1000); // delay calls vTaskDelay
}
}
void taskThree(void * pvParameters)
{
pinMode(pinLedThree, OUTPUT);
for(;;)
{
digitalWrite(pinLedThree, HIGH);
vTaskDelay(500 / portTICK_PERIOD_MS);
digitalWrite(pinLedThree, LOW);
vTaskDelay(500 / portTICK_PERIOD_MS);
}
}