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

- 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 ///< 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(&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 <stdio.h>
#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", ///< Task name
128, ///< Stack size 128 words (512 bytes)
NULL, ///< Parameters
1, ///< Priority
&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 <stdio.h>
#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,
&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 = &idle_task_tcb;
*ppxIdleTaskStackBuffer = &idle_task_stack[0];
*pulIdleTaskStackSize = (uint32_t)configMINIMAL_STACK_SIZE;
}
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer, StackType_t ** ppxTimerTaskStackBuffer, uint32_t * pulTimerTaskStackSize )
{
*ppxTimerTaskTCBBuffer = &timer_task_tcb;
*ppxTimerTaskStackBuffer = &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 |

Previous Recommendations
RECOMMEND

[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 ID|aike_eureka
Baijiahao|Master Embedded Systems