FreeRTOS Development: How to Create Tasks

1. Task-Related APIs

Function Purpose
xTaskCreate() Create a task
vTaskDelete() Delete a task (NULL can be passed to delete itself)
vTaskSuspend() Suspend a task (NULL can be passed to suspend itself)
vTaskResume() Resume a task
vTaskDelay() Delay (block the task for a period)
vTaskDelayUntil() Periodic delay (ensure constant period)
uxTaskPriorityGet() Get task priority
vTaskPrioritySet() Set task priority

Create Task

FreeRTOS Development: How to Create Tasks

  • Function Purpose: Create a task and add it to the schedulable list
  • Function Prototype:
BaseType_t xTaskCreate(
    TaskFunction_t pxTaskCode,    // Task function
    const char * const pcName,    // Task name (for debugging)
    uint16_t usStackDepth,        // Stack size (in words)
    void *pvParameters,           // Parameters passed to the task
    UBaseType_t uxPriority,       // Priority (higher value means higher priority)
    TaskHandle_t *pxCreatedTask   // Return task handle (can be NULL)
);
  • Example Call
TaskHandle_t s_task_lcd_handle;

void task_func_lcd(void *arg)
{
    while(1)
    {
        // Run related function features
        vTaskDelay(1);
    }
}

xTaskCreate(task_func_lcd, "task_lcd", 128, NULL, 2, &s_task_lcd_handle);

Delete Task

  • Function Purpose: Delete a task
  • Function Prototype:
void vTaskDelete(TaskHandle_t xTaskToDelete); ///< xTaskToDelete is the task handle to delete
  • Note:
    • Passing <span>NULL</span> indicates deleting the current task
    • Once a task is deleted, it will not run again, and resources may not be released immediately (usually released in the <span>Idle</span> task)
  • Example Call
vTaskDelete(s_task_lcd_handle);  // Delete specified task
vTaskDelete(NULL);               // Delete current task

Suspend Task

  • Function Purpose: Suspend a task, stopping it from running
  • Function Prototype:
void vTaskSuspend(TaskHandle_t xTaskToSuspend); /// xTaskToSuspend is the handle of the task to suspend, NULL indicates suspending the current task
  • Example Call
vTaskSuspend(s_task_lcd_handle); // Suspend task

Resume Task

  • Function Purpose: Resume a suspended task.
  • Function Prototype:
void vTaskResume(TaskHandle_t xTaskToSuspend);
  • Example Call
vTaskResume(s_task_lcd_handle); // Resume task

Task Delay

  • Function Purpose: Delay a task (block) for a period.
  • Function Prototype:
void vTaskDelay(const TickType_t xTicksToDelay);
  • Note:
    • <span>xTicksToDelay</span> indicates the number of ticks to delay, not the millisecond value
    • If you need to delay a specified millisecond value, you need to use <span>pdMS_TO_TICKS(ms)</span> to convert milliseconds to system <span>Ticks</span> count.
  • Example Call
vTaskDelay(pdMS_TO_TICKS(1000));  // Delay 1000 milliseconds

Periodic Task

  • Function Purpose: For precise periodic delays, maintaining fixed intervals.
  • Function Prototype:
BaseType_t xTaskDelayUntil(
    TickType_t * const pxPreviousWakeTime, /// Last wake time tick
    const TickType_t xTimeIncrement ///&lt; Running period
);
  • Example Call
void task_func_led(void *arg)
{
    TickType_t xLastWakeTime = xTaskGetTickCount();
    const TickType_t xFrequency = pdMS_TO_TICKS(1000);

    while(1)
    {
        // Precise delay, ensure fixed period
        vTaskDelayUntil(&amp;xLastWakeTime, xFrequency);
        printf("Executed once per second\n");
    }
}

Get Priority

  • Function Purpose: Get the current priority of a task
  • Function Prototype:
UBaseType_t uxTaskPriorityGet(TaskHandle_t xTask);
  • Example Call
UBaseType_t  curr_task_pri = uxTaskPriorityGet();

Modify Priority

  • Function Purpose: Modify the priority of a task
  • Function Prototype:
void vTaskPrioritySet(TaskHandle_t xTask, UBaseType_t uxNewPriority);
  • Example Call
UBaseType_t priority = uxTaskPriorityGet(Task1Handle);
vTaskPrioritySet(Task1Handle, priority + 1);  // Increase priority

2. Dynamically Creating Tasks

Example Code
#include "sys/bsp_sys.h"
#include &lt;stdio.h&gt;
#include "FreeRTOS.h"
#include "task.h"

TaskHandle_t s_task_demo_handle;

void task_func_demo(void *arg)
{
    const TickType_t x1000ms = pdMS_TO_TICKS( 1000 );
    while(1)
    {
        printf("hello\n");
        vTaskDelay(x1000ms); 
    }
}

void create_task_demo(void)
{
    xTaskCreate(task_func_demo,
                "task_demo", ///&lt; Task name
                128,         ///&lt; Stack size 128 words (512 bytes)
                NULL,        ///&lt; Parameters
                1,           ///&lt; Priority
                &amp;s_task_demo_handle);
}

int main(void)
{
    // BSP component initialization
    BspSysInit(); 
    // Enter critical section
    taskENTER_CRITICAL();
    // Create task
    create_task_demo();
    // Exit critical section
    taskEXIT_CRITICAL();
    // Start scheduler
    vTaskStartScheduler();
    while(1);
}
Overall Process
  • Initialize underlying hardware (<span>BspSysInit()</span>)
  • Enter critical section (to prevent issues when creating tasks concurrently)
  • Create task (<span>create_task_demo()</span>)
  • Exit critical section
  • Start scheduler (<span>vTaskStartScheduler()</span>)

3. Static Task Creation Example

Key Code
#include "sys/bsp_sys.h"
#include &lt;stdio.h&gt;
#include "FreeRTOS.h"
#include "task.h"

// Stack space and TCB (Task Control Block) space must be global or static variables
#define DEMO_TASK_STACK_SIZE 128
#define DEMO_TASK_PRIORITY   1

static StackType_t demo_task_stack[DEMO_TASK_STACK_SIZE];
static StaticTask_t demo_task_tcb;
TaskHandle_t s_task_demo_handle;

void task_func_demo(void *arg)
{
    const TickType_t x1000ms = pdMS_TO_TICKS(1000);
    while (1)
    {
        printf("hello (static)\n");
        vTaskDelay(x1000ms);
    }
}

void create_task_demo(void)
{
    // Use xTaskCreateStatic to create a task, manually pass TCB and stack space
    s_task_demo_handle = xTaskCreateStatic(task_func_demo,
                                           "task_demo",
                                           DEMO_TASK_STACK_SIZE,
                                           NULL,
                                           DEMO_TASK_PRIORITY,
                                           demo_task_stack,
                                           &amp;demo_task_tcb);

    if (s_task_demo_handle == NULL)
    {
        printf("Static task creation failed!\n");
        while (1);
    }
}

int main(void)
{
    BspSysInit();
    create_task_demo();
    vTaskStartScheduler();
    while (1);
}
Configuration

Need to add in <span>FreeRTOSConfig.h</span>:

  • <span>#define configSUPPORT_STATIC_ALLOCATION 1</span> : Enable static creation
Hook Functions

If both static and dynamic task creation are enabled (which is a common practice in many projects), <span>FreeRTOS</span> allows selectively creating tasks either statically or dynamically, while some internal tasks (like <span>Idle Task</span> and <span>Timer Task</span>) still require static creation, so hook functions must be implemented.

#define configMINIMAL_STACK_SIZE                 ( ( unsigned short ) 128 )
#define configTIMER_TASK_STACK_DEPTH             256
static StackType_t idle_task_stack[configMINIMAL_STACK_SIZE];
static StackType_t timer_task_stack[configTIMER_TASK_STACK_DEPTH];

static StaticTask_t idle_task_tcb;
static StaticTask_t timer_task_tcb;

void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, StackType_t ** ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
  *ppxIdleTaskTCBBuffer = &amp;idle_task_tcb;
  *ppxIdleTaskStackBuffer = &amp;idle_task_stack[0];
  *pulIdleTaskStackSize = (uint32_t)configMINIMAL_STACK_SIZE;
}

void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer, StackType_t ** ppxTimerTaskStackBuffer, uint32_t * pulTimerTaskStackSize )
{
  *ppxTimerTaskTCBBuffer = &amp;timer_task_tcb;
  *ppxTimerTaskStackBuffer = &amp;timer_task_stack[0];
  *pulTimerTaskStackSize = (uint32_t)configTIMER_TASK_STACK_DEPTH;
}

4. Differences Between Static and Dynamic Creation

Core Differences
Item Dynamic Creation (xTaskCreate) Static Creation (xTaskCreateStatic)
Memory Allocation Method Uses heap for automatic memory allocation User provides stack and TCB buffer
Depends on Heap Yes (heap must be enabled) No (does not depend on heap)
Using Function <span>xTaskCreate()</span> <span>xTaskCreateStatic()</span>
Memory Release Can be automatically released after using <span>vTaskDelete()</span> to free heap space <span>vTaskDelete()</span> only destroys the task, does not release static memory
Portability Limited by heap size More suitable for resource-constrained devices (MCUs)
Safety Allocation failure may lead to unpredictable system behavior More controllable (memory is fully managed by the user)
Creation Process
  • Dynamic Creation
    • Internally calls pvPortMalloc() to request memory
    • Allocates TCB + Stack space
    • Creates task and returns TaskHandle_t
  • Static Creation
    • User defines TCB + stack space in advance
    • Passes to API for direct use, no heap required
Applicable Scenarios
Scenario Recommended Method Reason
Large memory, dynamically changing tasks Dynamic Creation Flexible, convenient
MCU resource-constrained, seeking determinism Static Creation Safer, no heap overflow risk
System startup initialization tasks Static Creation System initial tasks are safer
Number of tasks uncertain, need dynamic addition/removal Dynamic Creation Can dynamically add or remove

FreeRTOS Development: How to Create Tasks

Previous Recommendations

RECOMMEND

FreeRTOS Development: How to Create Tasks

[1]. FreeRTOS Development: Core Mechanisms and Important Concepts

[2]. FreeRTOS Development: How to Port to Projects

[3]. FreeRTOS Development: In-Depth Understanding of Various Configurations

[4]. Embedded Layered Design: Streamlined and Efficient Project Structure

I am Aike, an embedded software engineer.

Follow me for more embedded insights.

Remember to like, share, and click to view,

Your encouragement is my greatest motivation to continue sharing!

See you next time.

Looking forward to your

sharing

likes

views

NEWS

WeChat IDaike_eureka

Baijiahao|Master Embedded Systems

Leave a Comment