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 29. Initialize a FreeRTOS task
 1#include <FreeRTOS.h>
 2#include <task.h>
 3#include <stdarg.h>
 4
 5#define TASK_PRIORITY 1
 6#define TASK_STACK_SIZE 2048 /* bytes */
 7
 8TaskHandle_t taskHandle = NULL;
 9
10/* Task function */
11void taskFunction(void* a0)
12{
13    /* Local variables. Variables here go onto task stack!! */
14
15    /* Run one-time code when task starts */
16
17    while (1) /* Run loop forever (unless terminated) */
18    {
19        /*
20         * Block on a signal or for a duration. Examples:
21         *  ``xSemaphoreTake()``
22         *  ``xQueueReceive``
23         *  ``vTaskDelay()``
24         *
25         * "Process data"
26         */
27    }
28
29    /* Tasks must not attempt to return from their implementing
30    function or otherwise exit. If it is necessary for a task to
31    exit then have the task call vTaskDelete( NULL ) to ensure
32    its exit is clean. */
33    vTaskDelete( NULL );
34}
35
36int main() {
37
38    BaseType_t xReturned;
39
40    /* Create the task, storing the handle. */
41    xReturned = xTaskCreate(
42            taskFxn,                                /* Function that implements the task. */
43            "MY_NEW_TASK",                          /* Text name for the task. */
44            TASK_STACK_SIZE / sizeof(uint32_t),     /* Stack size in words, not bytes. */
45            ( void * ) 1,                           /* Parameter passed into the task. */
46            TASK_PRIORITY,                          /* Priority at which the task is created. */
47            &taskHandle );                                /* Used to pass out the created task's handle. */
48
49    if(xReturned == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
50    {
51        /* Creation of FreeRTOS task failed */
52        while(1);
53    }
54
55    /* Start the FreeRTOS scheduler */
56            vTaskStartScheduler();
57
58}

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.

Creating Additional ICall Enabled Tasks

The objective of this section is to familiarize the programmer with the process of adding an RTOS task that can communicate with the BLE5-Stack. Tasks that call functions within the BLE5-Stack must follow a few additional steps to register with ICall. These details are covered below:

  1. Follow all the steps detailed in FreeRTOS Task Overview to create an RTOS task.

  2. Open SysConfig -> BLE -> Advanced Settings -> ICALL and add one to the “Max Number of Icall Enabled Tasks” entry.

  3. Modify the task’s init function to register with ICall (explained in ICall Initialization and Registration)

Listing 30. ICall Registration for custom task
1// ******************************************************************
2// N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp
3// ******************************************************************
4// Register the current thread as an ICall dispatcher application
5// so that the application can send and receive messages.
6ICall_registerApp(&selfEntity, &syncEvent);
  1. Modify the task’s main function to pend on syncEvent (explained in ICall Thread Synchronization)

Listing 31. ICall Wait
 1static void NotificationTask_taskFxn(UArg a0, UArg a1)
 2{
 3  // Initialize application
 4  NotificationTask_init();
 5
 6  // Application main loop
 7  for (;;)
 8  {
 9      // Waits for an event to be posted associated with the calling thread.
10      // Note that an event associated with a thread is posted when a
11      // message is queued to the message receive queue of the thread
12      events = Event_pend(syncEvent, Event_Id_NONE, SP_ALL_EVENTS, ICALL_TIMEOUT_FOREVER);
13
14      //...
15  }
16  // ...
17}