I’m using FreeRTOS for the first time. I’m using v10.4.3 with an ESP32 devboard in PlatformIO with the Arduino framework. I’ve got plenty of experience of writing multi tasking code for embedded systems using a few other proprietry schedulers.
I tried using vPrintLine(“text”), which seems to be the standard in the latest version of “Mastering the FreeRTOS Real Time Kernel” (sorry new user can’t include links). That gives a compiler error due to not being able to find the function’s declaration. Searching all the FreeRTOS header files also doesn’t find “vPrintLine”.
Is that because vPrintLine() is not included in the ESP32 build of free RTOS, because the doc I refer to is for a later version of free RTOS, or some other reason?
I’m currently using the normal Arduino Serial.print()/println().
I want to provide exclusive access to Serial.print()/println() to prevent one task’s partial output being merged with the output from another task.
I first tried putting Serial.print()s in critical sections using taskENTER_CRITICAL()/taskEXIT_CRITICAL(), but that caused the ESP32 to continually reboot, due to an unhandled exception, after a small amount of serial output.
I suppose it could have been a watchdog timer timing out, but at 112500 baud, none of the Serial.print()s should take much time. Can you tell me why this didn’t work?
My current solution, which seems to work fine using a semaphore, is as shown in the following code (it was the same code that kept rebooting when I used critical sections, before replacing them with the semaphore method).
#include <Arduino.h>
void vTask1( void * pvParameters );
void vTask2( void * pvParameters );
SemaphoreHandle_t serialSem;
void setup() {
Serial.begin(115200);
Serial.println("\nFreeRTOS Experiment 1");
Serial.print("FreeRTOS Version = ");
Serial.println(tskKERNEL_VERSION_NUMBER);
serialSem = xSemaphoreCreateMutex();
if (serialSem==NULL){
Serial.println("xSemaphoreCreateMutex returned NULL");
while(1);
}
BaseType_t result;
result = xTaskCreate(vTask1,"Task1",1000,NULL,1,NULL);
xSemaphoreTake(serialSem, portMAX_DELAY);
Serial.print("xTaskCreate(vTask1...) returned ");
Serial.println(result==pdPASS ? "pdPASS" : "pdFAIL");
xSemaphoreGive(serialSem);
result = xTaskCreate(vTask2,"Task2",1000,NULL,1,NULL);
xSemaphoreTake(serialSem, portMAX_DELAY);
Serial.print("xTaskCreate(vTask2...) returned ");
Serial.println(result==pdPASS ? "pdPASS" : "pdFAIL");
xSemaphoreGive(serialSem);
}
void loop() {
}
void vTask1(void * pvParameters){
while(1){
xSemaphoreTake(serialSem, portMAX_DELAY);
Serial.println("Task 1 is running");
xSemaphoreGive(serialSem);
vTaskDelay(1000);
}
}
void vTask2(void * pvParameters){
while(1){
xSemaphoreTake(serialSem, portMAX_DELAY);
Serial.println("Task 2 is running");
xSemaphoreGive(serialSem);
vTaskDelay(1000);
}
}
Serial monitor output:
FreeRTOS Experiment 1
FreeRTOS Version = V10.4.3
xTaskCreate(vTask1...) returned pdPASS
Task 1 is running
xTaskCreate(vTask2...) returned pdPASS
Task 2 is running
Task 1 is running
Task 2 is running
Task 1 is running
Is the above code a recommended way of doing it? Is there a better way?
It’s a bit clumsy. I suppose I could wrap calls to Serial.print()/println() and include the semaphore take / give in the wrapper.