1 Task Creation and Management
Task Creation
Use <span>xTaskCreate()</span> to create a task:
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // Task function (entry) const char * const pcName, // Task name (for debugging) configSTACK_DEPTH_TYPE usStackDepth, // Stack size (in words) void * const pvParameters, // Task parameters UBaseType_t uxPriority, // Priority (0~configMAX_PRIORITIES-1) TaskHandle_t * const pxCreatedTask // Task handle (can be NULL));
Note: The task function must conform to the prototype
<span>void (*TaskFunction_t)(void *)</span>.
Task Deletion
<span>vTaskDelete(TaskHandle_t xTaskToDelete); </span>
You can delete any task, including itself (pass in <span>NULL</span>).
Task Suspension and Wakeup
-
Suspend a task:
<span>vTaskSuspend(TaskHandle_t xTask);</span> -
Wake up a task:
<span>vTaskResume(TaskHandle_t xTask);</span>
Used to control the execution timing of tasks, but care should be taken to avoid permanently suspending tasks, which can waste system resources.
2 Queues
Definition
A queue is a typical FIFO (First In First Out) data structure used for data communication between tasks or between interrupts and tasks.
Creating a Queue
<span>QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize); </span>
-
<span>uxQueueLength</span>: Maximum number of items the queue can hold -
<span>uxItemSize</span>: Size of each item (in bytes)
Sending Data to the Queue
<span>xQueueSend(xQueue, pvItemToQueue, xTicksToWait); </span>
-
<span>xTicksToWait = 0</span>: Non-blocking send -
<span>portMAX_DELAY</span>: Block until successful (requires blocking API support)
Receiving Data from the Queue
<span>xQueueReceive(xQueue, pvBuffer, xTicksToWait); </span>
3 Semaphores
Semaphores are used for synchronization and resource access control between tasks. FreeRTOS provides several types of semaphores:
1. Binary Semaphore
Used for synchronizing events or interrupt signals (like a “phone booth” model).
-
Create:
<span>xSemaphoreCreateBinary();</span> -
Take:
<span>xSemaphoreTake(xSemaphore, xBlockTime);</span> -
Give:
<span>xSemaphoreGive(xSemaphore);</span>
Feature: The same task cannot take it again without releasing it.
2. Mutex
Suitable for protecting access to shared resources (like peripherals, memory, etc.) to prevent resource conflicts.
-
Create:
<span>xSemaphoreCreateMutex();</span>
Characteristic: Only the task that obtained the mutex can release it; incorrect release can lead to deadlock.
3. Counting Semaphore
Used for resource counting or controlling concurrency (like a “parking space” model).
-
Create:
<span>xSemaphoreCreateCounting(uxMaxCount, uxInitialCount);</span> -
Current remaining resource count:
<span>uxSemaphoreGetCount(xSemaphore);</span>
4. Recursive Mutex
Allows a task to take the lock multiple times within the same logic, with each take needing a corresponding release.
-
Create:
<span>xSemaphoreCreateRecursiveMutex();</span> -
Take:
<span>xSemaphoreTakeRecursive(xMutex, xBlockTime);</span> -
Give:
<span>xSemaphoreGiveRecursive(xMutex);</span>
4 Software Timers
Software timers are used for delaying or periodically executing certain task functions, in a non-blocking manner.
Creating a Software Timer
TimerHandle_t xTimerCreate( const char * const pcTimerName, TickType_t xTimerPeriodInTicks, UBaseType_t uxAutoReload, // pdTRUE: periodic; pdFALSE: one-time void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction // Timer callback);
To start the timer, you need to call
<span>xTimerStart()</span>. The system tick rate is defined by<span>configTICK_RATE_HZ</span>(usually set to 1000, meaning 1ms per tick).
5 Event Groups
Event groups provide a bit manipulation mechanism, suitable for multi-event synchronization (for example, <span>KEY1 & KEY2 -> LED1_ON</span>).
Creating and Setting
-
Create:
<span>xEventGroupCreate();</span> -
Set bits:
<span>xEventGroupSetBits(xEventGroup, uxBitsToSet);</span>
Waiting for Event Bits to be Satisfied
<span>xEventGroupWaitBits( xEventGroup, uxBitsToWaitFor, xClearOnExit, // whether to clear bits on exit xWaitForAllBits, // wait for all bits vs any bit xTicksToWait ); </span>
6 Task Notifications
Task notifications are a lightweight communication mechanism that is more efficient than queues and semaphores (supports up to 32-bit notification values).
Sending Notifications (in Interrupt)
<span>xTaskNotifyFromISR(xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken); </span>
-
<span>ulValue</span>: Notification value -
<span>eAction</span>: Notification mode (e.g., overwrite, accumulate) -
<span>pxHigherPriorityTaskWoken</span>: Used for context switching in interrupts
Waiting for Notifications
<span>xTaskNotifyWait( ulBitsToClearOnEntry, ulBitsToClearOnExit, pulNotificationValue, xTicksToWait ); </span>
Using task notifications can efficiently replace traditional mechanisms like semaphores and events.
Appendix: Common FreeRTOS Configuration Parameters
| Macro Definition | Meaning |
|---|---|
<span>configMAX_PRIORITIES</span> |
Maximum number of priorities (usually 5 or higher) |
<span>configMINIMAL_STACK_SIZE</span> |
Minimum stack size for tasks (128 means 512 bytes) |
<span>configMAX_TASK_NAME_LEN</span> |
Maximum length of task names (usually 16) |
<span>configTICK_RATE_HZ</span> |
Below is a complete and well-structured FreeRTOS demo example code, including the basic process of task creation and starting the task scheduler, suitable for beginners to reference:
✅ Example: FreeRTOS Task Creation and Scheduler Start (in main function)
#include "FreeRTOS.h"#include "task.h"#include <stdio.h>// Task handles (optional)TaskHandle_t Task1Handle = NULL;TaskHandle_t Task2Handle = NULL;// Task function definitionsvoid Task1(void *pvParameters){ while (1) { printf("Task 1 is running...\n"); vTaskDelay(pdMS_TO_TICKS(1000)); // Delay 1000ms }}void Task2(void *pvParameters){ while (1) { printf("Task 2 is running...\n"); vTaskDelay(pdMS_TO_TICKS(500)); // Delay 500ms }}// Main functionint main(void){ // Create Task 1 xTaskCreate( Task1, // Task function "Task1", // Task name (for debugging) 128, // Stack size (in words, 128 x 4 = 512 bytes) NULL, // Parameters 2, // Priority (range: 0 ~ configMAX_PRIORITIES-1) &Task1Handle // Task handle ); // Create Task 2 xTaskCreate( Task2, "Task2", 128, NULL, 1, // Lower priority than Task 1 &Task2Handle ); // Start the task scheduler vTaskStartScheduler(); // Will never reach here unless stack is insufficient or scheduler fails to start while (1);}
🔍 Explanation
-
<span>xTaskCreate()</span>: Registers the task and prepares it for scheduling, must be called before<span>vTaskStartScheduler()</span>. -
<span>vTaskDelay()</span>: Implements task delay, using<span>pdMS_TO_TICKS()</span>macro to avoid hardcoding. -
<span>vTaskStartScheduler()</span>: Starts the scheduler, after which FreeRTOS will automatically manage task switching.