ESP32 Arduino: Creating a FreeRTOS task

The objective of this post is to explain how to launch tasks with the FreeRTOS functions.

Introduction

The objective of this post is to explain how to launch tasks with the FreeRTOS functions. Since this will introduce some complex concepts, we will start by a very simple example where we will create two tasks that will print some “Hello World” messages and then delete them.

For most of the functionalities that we are going to use in this tutorial, you can check the .h file here. Please check this previous post for an introduction on FreeRTOS and tasks.

The setup and loop code

We will start our setup function by opening a serial connection, in order to be able to get the output of our testing program. This will be our regular Arduino function.

Serial.begin(112500);
delay(1000);

Then, we will create the tasks, with a call to the xTaskCreate function. The arguments to this function are the following [1]:

TaskCode: In this argument, we need to pass a pointer to the function that will implement the task. We will create two functions, TaskOne and TaskTwo, which we will define latter and will be passed in this argument.

TaskName: The name of the task, in a string. We will use “TaskOne” and “TaskTwo”.

StackDepth: The size of the stack of the task, specified as the number bytes. There is no simple way of determining the size of the task [2], although some calculations can be made. In this simple example, we will pass a value that is big enough.

Update: In the original post, it was mentioned that the StackDepth was specified in words, like documented in the FreeRTOS xTaskCreate page. Nonetheless, IDF’s version differs from the original implementation and the stack depth is actually specified in bytes, as indicated in IDF’s documentation. We can also confirm this in IDF’s FreeRTOS task.h file.

Parameter: Pointer to a parameter that the task function can receive. It needs to be of type (void *) [2]. In this case, for simplicity of the code, we will not use it, so we pass NULL in the argument.

Priority: Priority of the task. We will create both tasks with the same priority.

TaskHandle: Returns an handle that can be used for latter reference of the task on calls to functions (for example, to delete a task or change its priority) [2]. Also, for this simple example, we are not going to use it, so it will be NULL.

This function returns pdPASS on success or an error code that can be seen here [1]. For now, we will assume that the tasks will be created without any problem, so we are not going to do any error checking. Naturally, for a real case scenario application, we would need to do that to confirm the tasks were created.

So, check bellow the full setup function, already with the calls create the two different tasks.

void setup() {

  Serial.begin(112500);
  delay(1000);

  xTaskCreate(
                    taskOne,          /* Task function. */
                    "TaskOne",        /* String with name of task. */
                    10000,            /* Stack size in bytes. */
                    NULL,             /* Parameter passed as input of the task */
                    1,                /* Priority of the task. */
                    NULL);            /* Task handle. */

  xTaskCreate(
                    taskTwo,          /* Task function. */
                    "TaskTwo",        /* String with name of task. */
                    10000,            /* Stack size in bytes. */
                    NULL,             /* Parameter passed as input of the task */
                    1,                /* Priority of the task. */
                    NULL);            /* Task handle. */

}

In the main loop, we won’t do anything because our tasks will implement all the functionality. So let’s just put a delay.

void loop() {
   delay(1000);
}


The task functions

Now, we only need to specify the functions for the tasks. Remember that we want to create a task implemented by function TaskOne and other implemented by function TaskTwo.

Note that task are implemented with regular functions and they only need to follow a predefined function prototype [3]. So, they must return void and they must receive as input an argument of type (void *) [3]. Check an example bellow.

void taskOne( void * parameter )

A very important thing to take in consideration is that this function should not return. So, they must not contain a return statement or execute until the end of the code [3]. Instead, they should be explicitly deleted [3].

To delete a task from inside its own code, we just need  to call the vTaskDelete function. This function receives as input the handle of the task to be deleted [4] (remember the previously mentioned argument of the xTaskCreate that we are not going to use). Nevertheless, if we pass NULL as input the calling task will be deleted [4], which is what we want, since we are going to call it from the task’s own code.

vTaskDelete( NULL );

Other that these particularities, we are going to implement the two functions in a very simple way. Basically, we are going to do a simple loop where we are going to print a “Hello World” from each task and, after all the iterations of the loop, we will print a message stating the task will end.

Check the full code for this tutorial bellow, with both our tasks implemented.

void setup() {

  Serial.begin(112500);
  delay(1000);

  xTaskCreate(
                    taskOne,          /* Task function. */
                    "TaskOne",        /* String with name of task. */
                    10000,            /* Stack size in bytes. */
                    NULL,             /* Parameter passed as input of the task */
                    1,                /* Priority of the task. */
                    NULL);            /* Task handle. */

  xTaskCreate(
                    taskTwo,          /* Task function. */
                    "TaskTwo",        /* String with name of task. */
                    10000,            /* Stack size in bytes. */
                    NULL,             /* Parameter passed as input of the task */
                    1,                /* Priority of the task. */
                    NULL);            /* Task handle. */

}

void loop() {
  delay(1000);
}

void taskOne( void * parameter )
{

    for( int i = 0;i<10;i++ ){

        Serial.println("Hello from task 1");
        delay(1000);
    }

    Serial.println("Ending task 1");
    vTaskDelete( NULL );

}

void taskTwo( void * parameter)
{

    for( int i = 0;i<10;i++ ){

        Serial.println("Hello from task 2");
        delay(1000);
    }
    Serial.println("Ending task 2");
    vTaskDelete( NULL );

}

Running the code

To run the code, simply upload it to the ESP32 board using the Arduino IDE. You should get a result similar to figure 1, with both “Hello World” messages being printed to the serial console. In the end, also both the termination messages should be printed.

ESP32 Create FreeRTOS Task

Figure 1 – Output of the program.

Note that both tasks were running in parallel, which is way the prints from each task are mixed. Naturally, the time of execution for each one of the tasks was decided by the RTOS scheduler.

Related Posts

References

[1] http://esp32.info/docs/esp_idf/html/dd/d3c/group__xTaskCreate.html

[2] http://www.freertos.org/Documentation/161204_Mastering_the_FreeRTOS_Real_Time _Kernel-A_Hands-On_Tutorial_Guide.pdf   [Page 50]

[3] http://www.freertos.org/Documentation/161204_Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf [Page 46]

[4] http://www.freertos.org/a00126.html

43 thoughts on “ESP32 Arduino: Creating a FreeRTOS task”

  1. hi…
    i made some projetc arduino and esp8266,, and i got noting for esp8266 to upload data by wifi.

    i was trai cange task and all, but esp8266 still not working.
    please help.
    thanks.

  2. hi…
    i made some projetc arduino and esp8266,, and i got noting for esp8266 to upload data by wifi.
    i was trai cange task and all, but esp8266 still not working.
    please help.
    thanks.

  3. Thank you for this example, it got me up and running very quickly using FreeRTOS on the ESP32 as a .ino
    I am currently programming in the Visual Studio environment (with VisualGDB added to support the ESP32). The problem is, there are much fewer examples of working code/libraries for modules such as temp/humidity (BME280) RTC (DS3231), RFID, etc. in the .C and .CPP world. I have been “spoiled” by all of the support and .ino code that is out there.
    The problem is, the Arduino IDE is not very easy to use with more complex projects – I need better tools, even if I have to pay for them.
    So the solution I am currently pursuing is to use VisualMicro inside Visual Studio. This allows me to import .ino files and use libraries such as wire.h, arduino.h, etc. I compiled your example (I already had FreeRTOS installed) and it ran, first time, with no errors.
    So it seems that now I have the best of all worlds – Arduino code and libraries, a solid development environment, the ability to write my own functions in CPP for my custom stuff, RTOS, and the ESP32.

    Thanks Santa Claus, but I already have everything I want for Christmas…

    1. Hi!

      Thank you very much for your feedback, I’m glad you found the content useful and easy for getting started 🙂

      It is indeed true what you mention, once we get used to the Arduino community support, it gets harder to go back to a lower level programming.

      Note however that Arduino is CPP / C (as they mention in their faqs section) so we can write CPP and C code in the Arduino environment. In fact, many of the libraries out there for Arduino are written taking advantage of many CPP language functionalities.
      https://www.arduino.cc/en/Main/FAQ

      But also as you point, the Arduino IDE is not that flexible when it comes to big projects, handling includes of custom .CPP files, etc..

      To be honest, I didn’t know there was a solution for that on visual studio, so thank you very much for pointing that 🙂

      I use visual studio a lot for C# and web development, so I will definitely check that out since it’s a very powerful and easy to use IDE.

      Best regards,
      Nuno Santos

      PS: Have a nice Christmas! 🙂

  4. Thank you for this example, it got me up and running very quickly using FreeRTOS on the ESP32 as a .ino
    I am currently programming in the Visual Studio environment (with VisualGDB added to support the ESP32). The problem is, there are much fewer examples of working code/libraries for modules such as temp/humidity (BME280) RTC (DS3231), RFID, etc. in the .C and .CPP world. I have been “spoiled” by all of the support and .ino code that is out there.
    The problem is, the Arduino IDE is not very easy to use with more complex projects – I need better tools, even if I have to pay for them.
    So the solution I am currently pursuing is to use VisualMicro inside Visual Studio. This allows me to import .ino files and use libraries such as wire.h, arduino.h, etc. I compiled your example (I already had FreeRTOS installed) and it ran, first time, with no errors.
    So it seems that now I have the best of all worlds – Arduino code and libraries, a solid development environment, the ability to write my own functions in CPP for my custom stuff, RTOS, and the ESP32.
    Thanks Santa Claus, but I already have everything I want for Christmas…

    1. Hi!
      Thank you very much for your feedback, I’m glad you found the content useful and easy for getting started 🙂
      It is indeed true what you mention, once we get used to the Arduino community support, it gets harder to go back to a lower level programming.
      Note however that Arduino is CPP / C (as they mention in their faqs section) so we can write CPP and C code in the Arduino environment. In fact, many of the libraries out there for Arduino are written taking advantage of many CPP language functionalities.
      https://www.arduino.cc/en/Main/FAQ
      But also as you point, the Arduino IDE is not that flexible when it comes to big projects, handling includes of custom .CPP files, etc..
      To be honest, I didn’t know there was a solution for that on visual studio, so thank you very much for pointing that 🙂
      I use visual studio a lot for C# and web development, so I will definitely check that out since it’s a very powerful and easy to use IDE.
      Best regards,
      Nuno Santos
      PS: Have a nice Christmas! 🙂

  5. Pingback: ESP32 Arduino: Using the pthreads library | techtutorialsx

  6. Pingback: ESP32 Arduino: Using the pthreads library | techtutorialsx

  7. hi, your tutorial helping me lot in understanding freertos
    i have problem that
    i’m having two tasks which are running on semaphore and i want to add another simple task without semaphore, this task should work in parallel with semaphore but the problem is while it’s executing all three tasks it’s getting stuck after executing first task, I don’t know why?
    is their any alternative method that i can go for? or should i make any changes within the program ?
    please help me regarding this.

    Thank you

    1. Hi!

      Thanks for the feedback 🙂

      What to you mean by the tasks running on semaphore? Are you blocking the two tasks on the semaphore and the third not?

      Do the tasks have different priorities? Are they running on the same core?

      Concurrency is always difficult, there are many variables that may be causing problems in your program.

      Let me know more about your program to see if I can help 🙂

      Best regards,
      Nuno Santos

  8. hi, your tutorial helping me lot in understanding freertos
    i have problem that
    i’m having two tasks which are running on semaphore and i want to add another simple task without semaphore, this task should work in parallel with semaphore but the problem is while it’s executing all three tasks it’s getting stuck after executing first task, I don’t know why?
    is their any alternative method that i can go for? or should i make any changes within the program ?
    please help me regarding this.
    Thank you

    1. Hi!
      Thanks for the feedback 🙂
      What to you mean by the tasks running on semaphore? Are you blocking the two tasks on the semaphore and the third not?
      Do the tasks have different priorities? Are they running on the same core?
      Concurrency is always difficult, there are many variables that may be causing problems in your program.
      Let me know more about your program to see if I can help 🙂
      Best regards,
      Nuno Santos

  9. Pingback: ESP32 Arduino web server: Sending data to JavaScript client via websocket – techtutorialsx

  10. Pingback: ESP32 Arduino web server: Sending data to JavaScript client via websocket – techtutorialsx

Leave a Reply