Master The ESP32 WiFi: Practical Tasks
Written by Harry Fairhead and Mike James   
Wednesday, 07 January 2026
Article Index
Master The ESP32 WiFi: Practical Tasks
First To Finish

Keeping track of tasks can be tough but using semaphores it can be easey. Find out how to wait for the first to finish and more. This is an extract from our latest book on the ESP in C.

MasterThe ESP32In C:
WiFi with the ESP-IDF, FreeRTOS, LwIP & MbedTLS

By Harry Fairhead & Mike James

ESPMaster360

Buy from Amazon.

Contents

  • Chapter 1 FreeRTOS Basics 
  • Chapter 2 Locks and Synchronization
  • Chapter 3 Practical Tasks 
     Extract:
     Practical Tasks  NEW!!!
  • Chapter 4 Data Structures
  • Chapter 5 Basic WiFi
  • Chapter 6 Using LwIP
  • Chapter 7 Sockets and HTTP Clients 
  • Chapter 8 Socket Server
  • Chapter 9 Details of Cryptography
  • Chapter 10 SSL/TLS and HTTPS
  • Chapter 11 SSL Server
  • Chapter 12 UDP For Speed
  • Chapter 13 SNTP For Timekeeping
  • Chapter 14 SMTP For Email
  • Chapter 15 MQTT For The IoT
  • Chapter 16 Advanced WiFi and AP Mode
      Extract: 
     ESPNow 
  • Appendix I Advanced WiFi Configuration

<ASIN:B0G5M76KLB> 

 

Understanding how locking and synchronization primitives work is important, but at the end of the day all it really provides is a kit of parts that you can use to implement more complex solutions. In this chapter we take a look at some of the common situations and uses of tasks, locking and synchronization.

There is a dogma that FreeRTOS tasks should be written so that they never end. This is because an RTOS is usually regarded as a way of extending the polling loop at the heart of all real time applications. Instead of one big polling loop, the idea is that each task is its own polling loop. This idea is so strongly held that there are many proposed reasons for preferring it, but none are conclusive. If you want to start a task to do a job and then delete it when it is finished then this is a perfectly reasonable way to design the system as long as you are happy with the overhead of creating and deleting a task. This raises some basic questions about knowing when a task has completed its job.

Waiting For a Task

Ideally tasks should be organized so that they get on with their jobs independently of one another, but occasionally one task may need to wait for another to complete and deliver some data.

The solution is very simple. Just wait on a semaphore and arrange for the task to Give it before deleting itself, the program can be found in folder Wait1:

#include <stdio.h>
#include "freertos/FreeRTOS.h"
SemaphoreHandle_t xSemaphore;
void task0(void *arg)
{
    vTaskDelay(100);
    printf("task0\n");
    xSemaphoreGive(xSemaphore);
    vTaskDelete(NULL);
}
void app_main()
{
    xSemaphore = xSemaphoreCreateBinary();
    xTaskCreatePinnedToCore(task0,"task0",4000,
NULL,0,NULL,1); xSemaphoreTake(xSemaphore, portMAX_DELAY); printf("task complete\n"); }

If you run this you will see task0 followed by task complete, demonstrating that the app_main task has waited for task0 to complete.

The alternative is to use a notification in roughly the same way, (in folder Wait2):

#include <stdio.h>
#include "freertos/FreeRTOS.h"
void task0(void *arg)
{
    vTaskDelay(100);
    printf("task0\n");
    xTaskNotifyGiveIndexed(*(TaskHandle_t*)arg, 0);
    vTaskDelete(NULL);
}
void app_main()
{
   TaskHandle_t main = xTaskGetCurrentTaskHandle();
   ulTaskNotifyTakeIndexed(0, true, 1);
   xTaskCreatePinnedToCore(task0, "task0", 4000, 
&main, 0,NULL, 1); ulTaskNotifyTakeIndexed(0, true, portMAX_DELAY); printf("task complete\n"); }

Notice that in this case we have to pass the task handle of app_main to task0 so that it can notify it. This could be extended to notify more than one task of completion, but it would require keeping a list of who to notify. In this situation the semaphore is preferable.



Last Updated ( Wednesday, 07 January 2026 )