Task Create
Note
This document is automatically translated using AI. Please excuse any detailed errors. The official English version is still in progress.
Task create is a core feature of FreeRTOS, involving the creation, scheduling, and status management of tasks.
Dynamic Task Creation
xTaskCreate()
is used to dynamically create tasks. It automatically allocates the control block and stack space for the task, and initializes the task to the ready state, waiting for the scheduler to schedule execution.
API Prototype
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE uxStackDepth,
void *pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask );
Input Parameter |
Parameter Function |
Parameter Description |
---|---|---|
|
Pointer to the task entry function. |
This function implements the specific function of the task, usually an infinite loop. The task function should not return or exit, but it can delete itself. |
|
The name of the task. |
Mainly used for debugging, the maximum name length is determined by |
|
The size of the task stack. |
In |
|
Parameters passed to the task. |
It is necessary to ensure that the parameters are still valid when the task is executed, and the address of the local variable cannot be passed. |
|
The priority when creating the task. |
The larger the value, the higher the priority. The priority cannot exceed |
|
Used to return the handle of the created task. |
This is an optional parameter, which can be used for subsequent deletion, suspension, recovery, etc. of this task. If you do not want to pass this parameter, you can set it to |
Return Value |
Description |
---|---|
|
Task creation successful. |
|
Memory allocation failed. |
Note
If the task stack or control block memory is insufficient, it will cause the task creation to fail. This can be adjusted by increasing configTOTAL_HEAP_SIZE
or reducing stack depth.
Example 1: Creating two tasks with the same priority
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// Task 1 function
void vTask1 (void *pvParameters)
{
// The body of the task function is usually an infinite loop
while (1) {
printf("Task 1 is running\n");
vTaskDelay(pdMS_TO_TICKS(1000)); // Delay 1 s
}
}
// Task 2 function
void vTask2 (void *pvParameters)
{
while (1) {
printf("Task 2 is running\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void app_main(void)
{
xTaskCreate(vTask1, "Task1", 2048, NULL, 1, NULL);
xTaskCreate(vTask2, "Task2", 2048, NULL, 1, NULL);
}
The execution result of the above code is as follows:
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running
This example creates two tasks with the same priority. Each task periodically prints its own information and delays for 1 second. Since the two tasks have the same priority, the FreeRTOS scheduler uses a time slice rotation strategy to make them run in turn. After each task is executed once, it actively enters the delay state (blocked state), releases the CPU usage right, and the scheduler chooses another task in the ready state to run. This scheduling method ensures that the two tasks are executed alternately, and the output results are orderly. After the delay is over, the task re-enters the ready state, waiting to be scheduled for execution. Through this mechanism, even if the task priorities are the same, the system can still achieve fair scheduling and stable operation among multiple tasks.
Example 2: Create two tasks with different priorities
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// Task 1 function
void vTask1 (void *pvParameters)
{
while (1) {
printf("Task 1 is running\n");
}
}
// Task 2 function
void vTask2 (void *pvParameters)
{
while (1) {
printf("Task 2 is running\n");
}
}
void app_main(void)
{
xTaskCreate(vTask1, "Task1", 2048, NULL, 1, NULL);
xTaskCreate(vTask2, "Task2", 2048, NULL, 2, NULL);
}
The execution result of the above code is as follows:
Task 2 is running
Task 2 is running
Task 2 is running
Task 2 is running
Task 2 is running
Task 2 is running
In this example, two tasks with different priorities are created, where task 2 has a higher priority than task 1. Since task 2 does not actively release the CPU during execution (does not call vTaskDelay()
or other blocking functions), the scheduler always prioritizes the execution of this high-priority task, resulting in the low-priority task 1 not getting the opportunity to run.
Add the following delay function in task 2:
vTaskDelay(pdMS_TO_TICKS(10));
The execution result is as follows:
Task 2 is running
Task 1 is running
Task 1 is running
Task 1 is running
Task 1 is running
Task 1 is running
Task 2 is running
Task 1 is running
Task 1 is running
Task 1 is running
By calling vTaskDelay()
in a high-priority task, the task will voluntarily suspend for a period of time after each execution, releasing the CPU usage right. During this period, the scheduler will prioritize scheduling low-priority but ready-to-run tasks. In this way, low-priority tasks get the opportunity to run, thus achieving the alternating execution of two tasks with different priorities.
Example 3: Task Parameter Passing
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// Task 1 function
void vTask1 (void *pvParameters)
{
const char *param = pvParameters; // Accept the passed parameter
while (1) {
printf(param); // Print the content of the parameter
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
static const char *pcTextForTask1 = "Task 1 is running\n";
static const char *pcTextForTask2 = "Task 2 is running\n";
void app_main(void)
{
xTaskCreate(vTask1, "Task1", 2048, (void *)pcTextForTask1, 1, NULL);
xTaskCreate(vTask1, "Task2", 2048, (void *)pcTextForTask2, 1, NULL);
}
The execution result of the above code is as follows:
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running
Without using parameter passing, it is usually necessary to write separate task functions for each task. Through the task parameter passing mechanism, you can use only one task function to create multiple tasks with similar functions by passing in different parameters. This method has the following advantages:
Reduce duplicate code: Avoid writing multiple functions for tasks with similar logic.
Improve maintainability and scalability: Unified task logic, easy to modify and expand later.
Simplify task creation process: Unified task function and variable parameters make task creation more flexible.
But the following points should be noted in use:
Ensure that the parameters passed to the task remain valid during the execution of the task. If the parameters are local variables or dynamically allocated memory, make sure they are not destroyed or released at runtime.
Ensure that the type of
pvParameters
is correctly converted in the task function:
When creating a task, you first need to define the correct type for the parameters passed to the task, such as
int
,float
,char *
, etc., or structure type, depending on the needs of the task.When calling
xTaskCreate
, convert the task parameters tovoid *
type and pass the parameters throughpvParameters
.Inside the task function, you must convert the
void *
type parameter to the correct type so that the task can use the parameter correctly. The conversion process needs to match the actual parameter type.For basic data type values, such as
int
, you must pass the address of the variable, not its value itself. Therefore, when passing an integer type parameter, you must use the address operator&
to pass the address of the parameter toxTaskCreate
, rather than directly passing the value of the variable.
Static Task Creation
xTaskCreateStatic()
is used to create tasks in a static way, suitable for applications that disable dynamic memory allocation or have high memory control requirements. Unlike dynamic task creation, static creation requires the caller to explicitly provide the memory required for the task stack and task control block.
API Prototype
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer );
Input Parameter |
Parameter Function |
Parameter Description |
---|---|---|
|
Pointer to the task entry function. |
This function implements the specific function of the task, usually an infinite loop. The task function should not return or exit, but it can delete itself. |
|
The name of the task. |
Mainly used for debugging, the maximum name length is determined by |
|
The size of the task stack. |
In |
|
The parameters passed to the task. |
It is necessary to ensure that the parameters are still valid when the task is executed, and the address of the local variable cannot be passed. |
|
The priority when creating the task. |
The larger the value, the higher the priority. The priority cannot exceed |
|
Pointer to the stack space used by the task. |
Points to a pre-allocated |
|
Memory pointer of the task control block. |
Points to a |
Return Value |
Description |
---|---|
Returns the handle of the created task |
The task is created successfully. This handle is used for subsequent operations, such as task management or deletion. |
|
Memory allocation failed. |
Note
If either puxStackBuffer
or pxTaskBuffer
is NULL
, the task will not be created and the function will return NULL
.
If there is not enough stack memory allocated for the task, or the stack buffer is
NULL
,puxStackBuffer
will beNULL
.If there is no memory allocated for the task control block, or the provided buffer is
NULL
,pxTaskBuffer
will beNULL
.
When calling the task creation function, make sure to provide a valid memory address and sufficient memory space to avoid task creation failure.
Example 1: Creating two tasks with the same priority
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define STACK_DEPTH 2048 // Define the size of the task stack
StackType_t xStackTask1[STACK_DEPTH]; // Stack space used by Task 1, size is STACK_DEPTH
StaticTask_t xTaskBuffer1; // Task control block 1
StackType_t xStackTask2[STACK_DEPTH]; // Stack space used by Task 2, size is STACK_DEPTH
StaticTask_t xTaskBuffer2; // Task control block 2
// Task 1 function
void vTask1 (void *pvParameters)
{
// The body of the task function is usually a dead loop
while (1) {
printf("Task 1 is running\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
// Task 2 function
void vTask2 (void *pvParameters)
{
while (1) {
printf("Task 2 is running\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void app_main(void)
{
xTaskCreateStatic(vTask1, "Task1", STACK_DEPTH, NULL, 1, xStackTask1, &xTaskBuffer1);
xTaskCreateStatic(vTask2, "Task2", STACK_DEPTH, NULL, 1, xStackTask2, &xTaskBuffer2);
}
The execution result of the above code is as follows:
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running
This example creates two tasks with the same priority in a static way through xTaskCreateStatic()
. The two tasks alternate in printing output during operation. The system adopts a time slice rotation scheduling mechanism, allowing Task 1 and Task 2 to alternate continuously.
Compared with the method of dynamically creating tasks with xTaskCreate
, static creation with user-provided task control block StaticTask_t
and task stack space StackType_t[]
does not depend on system heap memory, has higher memory controllability and reliability, and is particularly suitable for embedded environments where memory resources are limited or dynamic allocation is prohibited. The dynamic method allows the system to automatically allocate task resources in the heap, which is more flexible to use, but there is a risk of creation failure due to insufficient heap space or fragmentation.
There are essential differences between static and dynamic task creation in memory management mechanisms and resource life cycles: in the static method, the resources used by the task are allocated and managed by the user, and will not be automatically released after the task ends; in the dynamic method, the resources are automatically managed by the system, and the corresponding memory can be automatically released when the task is deleted, which is suitable for scenarios where the number of tasks changes dynamically.
When using xTaskCreateStatic()
to create tasks, the following points should be noted:
Multiple tasks can set the same stack size, the specific value should be determined according to the actual needs of the task.
Each task must use independent stack space, and the stack array cannot be shared among multiple tasks.
Each task must use an independent task control block, which cannot be shared.
The task control block parameter must be passed in through the address operator
&
, otherwise the control information of the task cannot be correctly written into this structure, resulting in an invalid task handle or creation failure.All stack arrays and task control blocks should be global or static variables to avoid being released due to the end of the scope of local variables.
Tasks created statically can be deleted through
vTaskDelete()
, but their stack space and control blocks will not be reclaimed by the system, and users should ensure the validity of resources.
Other usage notes
When using the static method to create tasks, in addition to manually providing the task’s stack space and task control block, the task priority setting and parameter passing method are exactly the same as dynamically creating tasks.
Setting tasks with different priorities: Through the
uxPriority
parameter in thexTaskCreateStatic()
function, you can specify the priority value for different tasks. The definition and scheduling behavior of priority is the same as the dynamic creation method, and tasks with higher priority will get higher execution priority in the scheduler.Passing parameters to tasks: You can pass pointers of any type (such as strings, structures, or integer addresses) to tasks through the
pvParameters
parameter. In the task function, it is received through its formal parameters and converted into an appropriate type for use, which is consistent with the parameter passing mechanism when dynamically creating tasks.
Since these two usage scenarios are the same as dynamically creating tasks in terms of interface call logic and behavior, and only differ in the name of the task creation function and the method of stack space allocation, no complete code examples are provided separately. For detailed implementation of different priority scheduling and task parameter usage, please refer to the related examples of dynamically creating tasks in the previous text.
Delete Task
vTaskDelete()
is used to remove a specified task from the RTOS kernel. The deleted task will be removed from all related scheduling management structures, including the ready list, blocking list, suspension list, and event list. This function can be used to delete other tasks or for tasks to self-delete.
API Prototype
void vTaskDelete( TaskHandle_t xTaskToDelete );
Input Parameter |
Parameter Function |
Parameter Description |
---|---|---|
|
The task handle to be deleted. |
When used for task self-deletion, the input parameter is |
Example 1: Delete Task Itself
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// Task 1 function
void vTask1 (void *pvParameters)
{
int *cnt = pvParameters;
while (1) {
if (*cnt < 2) {
(*cnt)++;
printf("Task 1 is running\n");
}
else {
printf("Task 1 is about to be deleted!\n");
vTaskDelete(NULL);
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
// Task 2 function
void vTask2 (void *pvParameters)
{
while (1) {
printf("Task 2 is running\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
static int i = 0;
void app_main(void)
{
xTaskCreate(vTask1, "Task1", 2048, (void *)&i, 1, NULL);
xTaskCreate(vTask2, "Task2", 2048, NULL, 1, NULL);
}
The execution result of the above code is as follows:
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running
Task 1 is about to be deleted!
Task 2 is running
Task 2 is running
Task 2 is running
Task 2 is running
In this example, the system creates two tasks: Task1
and Task2
. Task1
receives a pointer to an integer variable as an argument for count control. When the count is less than 2, the task outputs Task 1 is running
once per second and increments the count by 1. When the count reaches 2, it outputs About to delete Task 1!
and then calls vTaskDelete(NULL)
to delete itself. Task2
does not receive any arguments and continuously outputs Task 2 is running
every second.
Since both tasks have the same priority, the system scheduler uses a time slice rotation strategy, and the two tasks alternate in the early stages of operation. After Task1
completes the specified logic and successfully deletes itself, only Task2
remains in the system and continues to run independently.
This example clearly demonstrates how to share data through task parameters and how to use vTaskDelete(NULL)
to implement the basic mechanism of task self-deletion. It is suitable for tasks that need to automatically exit after performing a limited number of operations.
Note
When a task self-deletes, its resources are not immediately released at the time of the API call, but are delayed by the idle task. Therefore, the system design should ensure that the idle task has enough CPU time to execute, otherwise it may lead to resource leakage.
Example 2: Deleting Other Tasks
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
TaskHandle_t xHandleTask2 = NULL;
// Task 1 function
void vTask1 (void *pvParameters)
{
int *cnt = pvParameters;
while (1) {
if (*cnt != 2) {
printf("Task 1 is running\n");
}
else {
if (xHandleTask2 != NULL) {
printf("About to delete Task 2!\n");
vTaskDelete(xHandleTask2);
xHandleTask2 = NULL;
}
}
(*cnt)++;
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
// Task 2 function
void vTask2 (void *pvParameters)
{
while (1) {
printf("Task 2 is running\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
static int i = 0;
void app_main(void)
{
xTaskCreate(vTask1, "Task1", 2048, (void *)&i, 1, NULL);
xTaskCreate(vTask2, "Task2", 2048, NULL, 1, &xHandleTask2);
}
The execution result of the above code is as follows:
Task 1 is running
Task 2 is running
Task 1 is running
Task 2 is running
About to delete Task 2!
Task 1 is running
Task 1 is running
Task 1 is running
Task 1 is running
In this example, the system uses the task handle xHandleTask2
to delete Task2
from Task1
. When the count variable in Task1
reaches a certain condition, it calls vTaskDelete(xHandleTask2)
to delete Task2
and sets the handle to NULL
to prevent subsequent repeated operations. Task2
originally ran continuously with a 1-second cycle, but after being deleted, it stopped outputting, leaving only Task1
running in the system.
This example demonstrates the basic usage of control between tasks through handles, suitable for scenarios where other tasks need to be dynamically terminated during operation. Compared to the self-deletion method of tasks, the following points should be noted when deleting other tasks:
The task handle does not need to be manually assigned. You can declare and initialize the task handle variable to
NULL
first, and then pass its address into the task creation API. After the task is successfully created, this variable will be automatically filled with the handle of the new task.The task handle must be passed in the form of an address, that is, use the
&
address operator before the variable, otherwise, a valid handle cannot be obtained externally.Task creation must be successful. Ensure that the return value of
xTaskCreate()
ispdPASS
before using the handle to perform deletion operations.After deleting a task, the handle should be set to null to prevent the use of an expired task reference again, avoiding system exceptions.
Tasks should establish clear deletion conditions to avoid mistakenly deleting other tasks due to logical errors.
Note
When a task calls
vTaskDelete()
to delete another task, FreeRTOS will automatically release the RTOS kernel resources occupied by the task within the function, such as the task control block and stack space.
Based on the dual-core architecture of ESP32, ESP-IDF has extended the task creation mechanism of standard FreeRTOS and provides APIs that support multi-core task scheduling. Developers can specify the running core when creating tasks, achieving more flexible resource scheduling and performance optimization. For specific content, please refer to the Task section of the FreeRTOS (IDF) document.
ESP-IDF Extension: Dynamically Create Tasks and Bind Cores
xTaskCreatePinnedToCore()
is a FreeRTOS extension function provided by ESP-IDF, used to create tasks with specific core affinity, and task memory is dynamically allocated. Compared to the standard xTaskCreate()
, this interface provides more detailed task scheduling control, suitable for high real-time scenarios in multi-core systems.
API Prototype
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask,
const BaseType_t xCoreID );
Input Parameter |
Function |
Description |
---|---|---|
|
Pointer to the task entry function. |
This function implements the task’s functionality, typically as an infinite loop. The task function should not return or exit but may delete itself. |
|
Name of the task. |
Mainly used for debugging. |
|
Stack size of the task. |
Specified in |
|
Parameters passed to the task. |
Ensure the parameter remains valid during task execution; do not pass addresses of local variables. |
|
Priority assigned when the task is created. |
Higher value means higher priority. |
|
Handle to the created task. |
Optional. Can be used for later task operations such as deletion, suspension, or resumption. Set to |
|
Core ID on which the task should run. |
Can be |
Note
The stack depth unit in
xTaskCreate()
iswords
(typically 4 bytes), while inxTaskCreatePinnedToCore()
, it isbytes
. Conversion: 1 word = 4 bytes (on 32-bit architectures). Be cautious to avoid insufficient stack space due to unit mismatch.A task pinned to a core will always execute on the assigned core and will not migrate automatically.
Return Value |
Description |
---|---|
|
Task successfully created and added to the ready list. |
|
Memory allocation failed or an invalid core ID was specified. |
Example 1: Creating Three Tasks with the Same Priority Bound to Different Cores
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/idf_additions.h"
// Task 1 function
void vTask1 (void *pvParameters)
{
while (1) {
printf("Task 1 is running on Core %d\n", xPortGetCoreID());
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vTask2 (void *pvParameters)
{
const int *pcTaskIndex = pvParameters;
while (1) {
printf("Task %d is running on Core %d\n", *pcTaskIndex, xPortGetCoreID());
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
static const int pcTextForTask2 = 2;
static const int pcTextForTask3 = 3;
void app_main(void)
{
xTaskCreatePinnedToCore(vTask1, "Task1", 2048, NULL, 1, NULL, 0);
xTaskCreatePinnedToCore(vTask2, "Task2", 2048, (void *)&pcTextForTask2, 1, NULL, 1);
xTaskCreatePinnedToCore(vTask2, "Task3", 2048, (void *)&pcTextForTask3, 1, NULL, tskNO_AFFINITY);
}
Expected output:
Task 1 is running on Core 0
Task 3 is running on Core 0
Task 2 is running on Core 1
Task 1 is running on Core 0
Task 3 is running on Core 0
Task 2 is running on Core 1
This example demonstrates how to use xTaskCreatePinnedToCore()
to create three tasks with the same priority and bind them to core 0, core 1, and no specific core (i.e., equivalent to using xTaskCreate()
).
Two tasks share the same function vTask2
and differentiate themselves by receiving different integer constants as input. This method is explained in detail in Example 3 of xTaskCreate()
.
The output shows each task running on the expected core. The use of xPortGetCoreID()
verifies task scheduling. In this simple scenario, binding a task to a core doesn’t significantly change behavior.
Note
When creating a task with tskNO_AFFINITY
, it typically starts on the current core and may later migrate between cores (unless configUSE_CORE_AFFINITY
is configured).
Advantages of pinning tasks to cores in real-world applications:
Isolating critical tasks: Assign latency-sensitive tasks to less-loaded cores to avoid interference.
Improving performance: Reduces core switching and increases CPU cache efficiency.
Easier debugging: Identifying where a task runs simplifies analysis.
Load balancing: Manually controlling task-core affinity for optimal resource use.
ESP-IDF Extension: Static Task Creation with Core Affinity
xTaskCreateStaticPinnedToCore()
is an ESP-IDF extension of FreeRTOS that creates tasks with core affinity and static memory allocation. Compared to xTaskCreateStatic()
, it provides explicit control over task-core binding and is suitable for constrained systems requiring precise task placement.
API Prototype
TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer,
const BaseType_t xCoreID );
Input Parameter |
Function |
Description |
---|---|---|
|
Pointer to the task entry function. |
Implements the task functionality, usually an infinite loop. |
|
Task name. |
Used for debugging. |
|
Task stack size. |
Specified in |
|
Parameters passed to the task. |
Must remain valid during task execution. |
|
Task priority at creation. |
Higher value = higher priority. |
|
Stack memory pointer. |
Must point to a pre-allocated |
|
Pointer to task control block memory. |
Must point to a |
|
Core to bind the task. |
Can be |
Return Value |
Description |
---|---|
Task handle |
Task created successfully. Use handle for management or deletion. |
|
Memory allocation failed. |
Example 1: Static Creation of Tasks with Different Core Affinity
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/idf_additions.h"
#define STACK_DEPTH 2048
StackType_t xStackTask1[STACK_DEPTH];
StaticTask_t xTaskBuffer1;
StackType_t xStackTask2[STACK_DEPTH];
StaticTask_t xTaskBuffer2;
StackType_t xStackTask3[STACK_DEPTH];
StaticTask_t xTaskBuffer3;
// Task 1 function
void vTask1 (void *pvParameters)
{
while (1) {
printf("Task 1 is running on Core %d\n", xPortGetCoreID());
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vTask2 (void *pvParameters)
{
const int *pcTaskIndex = pvParameters;
while (1) {
printf("Task %d is running on Core %d\n", *pcTaskIndex, xPortGetCoreID());
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
static const int pcTextForTask2 = 2;
static const int pcTextForTask3 = 3;
void app_main(void)
{
xTaskCreateStaticPinnedToCore(vTask1, "Task1", STACK_DEPTH, NULL, 1, xStackTask1, &xTaskBuffer1, 0);
xTaskCreateStaticPinnedToCore(vTask2, "Task2", STACK_DEPTH, (void *)&pcTextForTask2, 1, xStackTask2, &xTaskBuffer2, 1);
xTaskCreateStaticPinnedToCore(vTask2, "Task3", STACK_DEPTH, (void *)&pcTextForTask3, 1, xStackTask3, &xTaskBuffer3, tskNO_AFFINITY);
}
Expected output:
Task 1 is running on Core 0
Task 3 is running on Core 0
Task 2 is running on Core 1
Task 1 is running on Core 0
Task 3 is running on Core 0
Task 2 is running on Core 1
This example shows three statically created tasks, each bound to a different core. Topics such as static task creation, core affinity, and parameter passing are covered in the earlier sections on xTaskCreateStatic()
and xTaskCreatePinnedToCore()
.
ESP-IDF Extension: Task Deletion
ESP-IDF improves the internal implementation of task deletion but retains the same API prototype and parameters. Therefore, it is not discussed separately here. For more information, refer to the Task Deletion section in the ESP-IDF FreeRTOS documentation.