Search code examples
freertos

Is this the right way to create and delete tasks dynamically in freertos?


I have some rookie questions on how to port an existing application on ESP32 to freeRTOS. I have a first setup running but am hitting some roadblocks.

We have built a test device that exercises a unit under test by stepping through several steps. The proof-of-concept is running freeRTOS on an ESP32 with an LCD display, user buttons, and all the needed I/O circuits. In general, the procedure for each measurement step is:

  • Set up HW (open/close relays)
  • Measure values (voltages, currents)
  • Wait for readings to stabilize
  • Validate if readings are correct for given stage
  • Determine pass/fail, eventually upload results to server

We have 12 different steps as outlined above plus some extra ones to select the test protocol and configure the WiFi interface. We reasoned (wrongly?) that we want to create individual tasks on the fly when needed and not create them at the start and kept in suspended mode. This is as safety measure since we want to avoid that (inadvertently) two different tasks would be running simultaneously when they shouldn't: that might create the danger of messing up the relays that control AC power.

So, we want to create two tasks for each test step:

  • Task1: with an infinite loop that reads the corresponding values
  • CheckTask1: waits x seconds then should delete Task1, determine pass/fail and then delete itself

The problem I have is that the for(;;) that is in the function that creates Task1 never ends, so we can´t fire off TaskCheck1.

The abbreviated code is below:

 /************************************************************************
 * 
 *                                  MAIN LOOP
 * 
 ************************************************************************/

void loop()
{
  
  // We keep the main loop always running and firing off the different tasks. 


  if (some_condition_to_create_task_1){
    startTask1();   // Creates a task that shows an analog reading on the display
    startCheckTask1();  // Creates a task that waits x secs, then deletes Task1 and deletes itself
                    // --> PROBLEM: startCheckTask1() is never executed, the for(;;) in startTask1() never exits
  }  

  // Similar code to above for additional tasks to create when their turn comes

}


/************************************************************************
 * 
 *                                 TASKS
 * 
 ************************************************************************/


void Task1(void *pvParameters)  // Reads analog value and shows on display
{
  (void) pvParameters;

  for(;;){
    readAnalogValue();
    showOnDisplay();
    vTaskDelay(500); // Update reading every 0,5 sec to avoid flicker
  }
}

void startCheckTask1(void *pvParameters)  // Waits for 5 seconds, then deletes Task1, interprets results and shows 
                                      // passed/failed on screen
{
  (void) pvParameters;

  unsigned long oldTicks, NewTicks;
  
  vTaskDelay(5000);         // Allow 5 secs for readings to stabilize

  showResultOnDisplay();    // Show passed/failed on the display
  
  // Now delete both tasks
  vTaskDelete(hTask1);
  vTaskDelete(hCheckTask1);  
  
}

/************************************************************************
 * 
 *                         FUNCTIONS
 * 
 ************************************************************************/

void startTask1(){
  xTaskCreatePinnedToCore(Task1,"Task 1", 1024, NULL, 1, &hTask1, 1);
  for(;;){  // PROBLEM: This is the loop that prevents creating CheckTask1
  }
}

void startCheckTask1(){
  xTaskCreatePinnedToCore(CheckTask1,"Check Task 1", 1024, NULL, 1, &hCheckTask1, 1);
  for(;;){
  }
}

Any ideas how to solve this? Thx!


Solution

  • I would put some vTaskDelay(1000) inside each for() loop both into startTask1() and into startCheckTask1().

    I assume loop() is called by app_main() which is a priority 1 task itself. If you don't put something that blocks the fors(), same priority tasks that you created never get CPU.

    Hope this helps.

    Have a nice day

    PS. Take into account that vTaskDelay() is not measured in msecs, but in RTOS ticks. You must use pdMS_TO_TICKS(x) macro instead, as in: vTaskDelay( pdMS_TO_TICKS(1000) ) // This blocks until passed 1sec