ESP32 - infinite loops on both cores without delay()

My code uses both cores of the ESP32 and seems to work well. I have pinned one task to each core with infinite loops. However, the loops don't have delay() or vTaskDelay() in them and I was wondering if that would cause issues with the pinned tasks blocking other system/housekeeping tasks from executing, as discussed in this thread.
(ESP32 - using 2nd core)

Unlike the code in the above thread though, I don't have delay() or vTaskDelay() in my code, and I am still not facing any reboot issues. So, even though Task1 and Task2 never finish, are the tasks yielding between each iteration of the for(;;) loops and letting the system /housekeeping tasks run?

A sketch of my code is below (based on this). Also, loop() is empty following the advice in the thread above.

TaskHandle_t Task1, Task2;
long t1 = 0;
long t2 = 0;

void Task1code(void *parameter) {
  for (;;) {
    if (millis() - t1 > 20) {
      t1 = millis();

      // CODE TO BE EXECUTED EVERY 20ms
      // ...

      // Should I add vTaskDelay() here?
    }
  }
}

void Task2code(void *parameter) {
  for (;;) {
    if (millis() - t2 > 30) {
      t2 = millis();

      // CODE TO BE EXECUTED EVERY 30ms
      // ...

      // Should I add vTaskDelay() here?
    }
  }
}

xTaskCreatePinnedToCore(
  Task1code, /* Task function. */
  "Task1",   /* name of task. */
  10000,     /* Stack size of task */
  NULL,      /* parameter of the task */
  1,         /* priority of the task */
  &Task1,    /* Task handle to keep track of created task */
  0);        /* pin task to core 0 */

xTaskCreatePinnedToCore(
  Task2code, /* Task function. */
  "Task2",   /* name of task. */
  10000,     /* Stack size of task */
  NULL,      /* parameter of the task */
  1,         /* priority of the task */
  &Task2,    /* Task handle to keep track of created task */
  1);        /* pin task to core 1 */

Do not worry about using delay in the tasks unless needed. House cleaning tasks will be performed when there is no code in loop(), so no issue there.

I'd shy away from millis() and use the ESP32's cycle count values.

here is a task using the ESP32's millis cycle counter and the freeRTOS tick counter.


void fDoMoistureDetector( void * parameter )
{
  //wait for a mqtt connection
  while ( !MQTTclient.connected() )
  {
    vTaskDelay( 250 );
  }
  int      TimeToPublish = 5000000; //5000000uS
  int      TimeForADreading = 100 * 1000; // 100mS
  uint64_t TimePastPublish = esp_timer_get_time(); // used by publish
  uint64_t TimeADreading   = esp_timer_get_time();
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 10; //delay for 10mS
  float    RemainingMoisture = 100.0f; //prevents pump turn on during start up
  bool     pumpOn = false;
  uint64_t PumpOnTime = esp_timer_get_time();
  int      PumpRunTime = 11000000;
  uint64_t PumpOffWait = esp_timer_get_time();
  uint64_t PumpOffWaitFor = 60000000; //one minute
  float    lowMoisture = 23.0f;
  float    highMoisture = 40.0f;
  for (;;)
  {
    xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
    //read AD values every 100mS.
    if ( (esp_timer_get_time() - TimeADreading) >= TimeForADreading )
    {
      xEventGroupSetBits( eg, evtADCreading0 );
      TimeADreading = esp_timer_get_time();
    }
    xQueueReceive(xQ_RM, &RemainingMoisture, 0 ); //receive queue stuff no waiting
    //read gpio 0 is water level good. Yes: OK to run pump : no pump off.   remaining moisture good, denergize water pump otherwise energize water pump.
    if ( RemainingMoisture >= highMoisture )
    {
      WaterPump0_off();
    }
    if ( !pumpOn )
    {
      log_i( "not pump on ");
      if ( gpio_get_level( GPIO_NUM_0 ) )
      {
        if ( RemainingMoisture <= lowMoisture )
        {
          //has one minute passed since last pump energize, if so then allow motor to run
          if ( (esp_timer_get_time() - PumpOffWait) >= PumpOffWaitFor )
          {
            WaterPump0_on();
            log_i( "pump on " );
            pumpOn = !pumpOn;
            PumpOnTime = esp_timer_get_time();
          }
        }
        //xSemaphoreGive( sema_RemainingMoisture );
      } else {
        log_i( "water level bad " );
        WaterPump0_off();
        PumpOffWait = esp_timer_get_time();
      }
    } else {
      /*
         pump goes on runs for X seconds then turn off, then wait PumpOffWaitTime before being allowed to energize again
      */
      if ( (esp_timer_get_time() - PumpOnTime) >= PumpRunTime )
      {
        log_i( "pump off " );
        WaterPump0_off(); // after 5 seconds turn pump off
        pumpOn = !pumpOn;
        PumpOffWait = esp_timer_get_time();
      }
    }
    // publish to MQTT every 5000000uS
    if ( (esp_timer_get_time() - TimePastPublish) >= TimeToPublish )
    {
      xQueueOverwrite( xQ_RemainingMoistureMQTT, (void *) &RemainingMoisture );// data for mqtt publish
      TimePastPublish = esp_timer_get_time(); // get next publish time
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete( NULL );
}// end fDoMoistureDetector()

The macro esp_timer_get_time(); returns microseconds and overflows in a bit over 204 years.

The freeRTOS tick count can be had from xTaskGetTickCount() and is in millis().

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.