Tasks

FreeRTOS is structured as a set of independent Tasks. Each task executes within its own context with no coincidental dependency on other tasks within the system or FreeRTOS scheduler itself. Additional details can be found in FreeRTOS Task Overview.

Task States

A task can exist in one of the following states:

  • Running
  • Ready
  • Blocked
  • Suspended

Additional details can be found in FreeRTOS Task States Overview.

Initializing a Task

Each task requires RAM that is used to hold the task state, and used by the task as its stack (see FreeRTOS How big should the stack be?):

  • If a task is created using xTaskCreate() then the required RAM is automatically allocated from the FreeRTOS heap.
  • If a task is created using xTaskCreateStatic() then the RAM is provided by the application writer, which requires a greater number of parameters, but allows the RAM to be statically allocated at compile time. Additional details can be found on FreeRTOS Static Vs Dynamic allocation page.
Listing 24. Initialize a FreeRTOS task
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <FreeRTOS.h>
#include <task.h>
#include <stdarg.h>

#define TASK_PRIORITY 1
#define TASK_STACK_SIZE 2048 /* bytes */

TaskHandle_t taskHandle = NULL;

/* Task function */
void taskFunction(void* a0)
{
    /* Local variables. Variables here go onto task stack!! */

    /* Run one-time code when task starts */

    while (1) /* Run loop forever (unless terminated) */
    {
        /*
         * Block on a signal or for a duration. Examples:
         *  ``xSemaphoreTake()``
         *  ``xQueueReceive``
         *  ``vTaskDelay()``
         *
         * "Process data"
         */
    }

    /* Tasks must not attempt to return from their implementing
    function or otherwise exit. If it is necessary for a task to
    exit then have the task call vTaskDelete( NULL ) to ensure
    its exit is clean. */
    vTaskDelete( NULL );
}

int main() {

    BaseType_t xReturned;

    /* Create the task, storing the handle. */
    xReturned = xTaskCreate(
            taskFxn,                                /* Function that implements the task. */
            "MY_NEW_TASK",                          /* Text name for the task. */
            TASK_STACK_SIZE / sizeof(uint32_t),     /* Stack size in words, not bytes. */
            ( void * ) 1,                           /* Parameter passed into the task. */
            TASK_PRIORITY,                          /* Priority at which the task is created. */
            &taskHandle );                                /* Used to pass out the created task's handle. */

    if(xReturned == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
    {
        /* Creation of FreeRTOS task failed */
        while(1);
    }

    /* Start the FreeRTOS scheduler */
            vTaskStartScheduler();

}

The task creation is done in the main() function, before the FreeRTOS Kernel’s scheduler is started by vTaskStartScheduler(). The task executes at its assigned priority level after the scheduler is started (see FreeRTOS Task Priorities Overview).

A Task Function

The type TaskFunction_t is defined as a function that returns void and takes a void pointer as its only parameter. All functions that implement a task should be of this type. The parameter can be used to pass information of any type into the task - this is demonstrated by several of the FreeRTOS Demo Applications.

Task functions should never return so are typically implemented as a continuous loop. However, normally it is best to create tasks that are event-driven so as not to starve lower priority tasks of processing time (see FreeRTOS Avoid Task Starvation).

Additional details can be found in FreeRTOS Task Implementation Overview.