Contributed by WangChong, curated by Ai-Thinker
FreeRTOS Primer 01 - Creating and Scheduling Tasks - Based on Ai-M61-32S-Kit
Porting
Operation Steps
The Ai-M61 SDK already integrates the FreeRTOS component. When creating a project from scratch, you only need to enable the FreeRTOS library in your local project’s proj.conf
set(CONFIG_FREERTOS 1)
You also need to copy FreeRTOSConfig.h into your project folder (not required)
Include FreeRTOS.h in your program
Modify line 59 of FreeRTOS.h to point to your FreeRTOSConfig.h file (absolute path)
Congratulations! You have successfully completed the FreeRTOS configuration for the Xiao An Pai M61-32S-Kit
API Introduction
Before introducing the API, let me briefly mention the OS. Just remember the most important sentence: the OS is responsible for task scheduling.
First, let's introduce today's first API
BaseType_t xTaskCreate(
TaskFunction_t pvTaskCode,
const char * const pcName,
configSTACK_DEPTH_TYPE usStackDepth,
void *pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask
);| pvTaskCode | Pointer to the task entry function (i.e., the name of the function that implements the task; see the example below). Tasks are usually implemented as infinite loops; the function implementing a task must never attempt to return or exit. However, a task can delete itself. |
|---|---|
| pcName | A descriptive name for the task. It is mainly for debugging convenience, but can also be used to obtain the task handle. The maximum length of a task name is defined by configMAX_TASK_NAME_LEN in FreeRTOSConfig.h. |
| usStackDepth | The number of words (not bytes) to be allocated for the task stack. For example, if the stack width is 16 bits and usStackDepth is 100, then 200 bytes will be allocated as the stack for this task. As another example, if the stack width is 32 bits and usStackDepth is 400, then 1600 bytes will be allocated as the stack for this task. The product of stack depth and stack width must not exceed the maximum value that can be held in a variable of type size_t. See the FAQ: How big should the stack be? |
| pvParameters | A value passed as a parameter to the created task. If pvParameters is set to the address of a variable, that variable must still exist when the created task executes—so passing the address of a stack variable is invalid. |
| uxPriority | The priority at which the created task will execute. Systems with MPU support can optionally create tasks in privileged (system) mode by setting the portPRIVILEGE_BIT bit in uxPriority. For example, to create a privileged task with priority 2, set uxPriority to (2 | portPRIVILEGE_BIT). |
| pxCreatedTask | Used to pass a handle to the task created by the xTaskCreate() function. pxCreatedTask is optional and can be set to NULL. |
The method above is used to create a task and hand it over to FreeRTOS for scheduling. Note the uxPriority parameter: it is the task priority. The higher the priority, the more likely the task will be scheduled by the CPU first—but a higher priority does not guarantee it will always be scheduled first!
Creating a Task
Here is a calling example:
void turnGreenLed()
{
while (1)
{
bflb_gpio_set(gpio, GPIO_PIN_14);
bflb_mtimer_delay_ms(1000);
bflb_gpio_reset(gpio, GPIO_PIN_14);
vTaskDelay(pdMS_TO_TICKS(1000));
// wait 1 second
}
}In the code above, I created a task that blinks the green LED. Note that this task is an infinite loop, i.e., while(1), and inside the loop the LED blinks every 1 second.
void turnRedLed()
{
while (1)
{
bflb_gpio_set(gpio, GPIO_PIN_12);
bflb_mtimer_delay_ms(1000);
bflb_gpio_reset(gpio, GPIO_PIN_12);
vTaskDelay(pdMS_TO_TICKS(1000));
// wait 1 second
}
}
void turnBlueLed()
{
while (1)
{
bflb_gpio_set(gpio, GPIO_PIN_15);
bflb_mtimer_delay_ms(1000);
bflb_gpio_reset(gpio, GPIO_PIN_15);
vTaskDelay(pdMS_TO_TICKS(1000));
// wait 1 second
}
}Above, I created two more functions for lighting the blue and red LEDs. If the OS is not used for scheduling and the program is single-threaded, once one of these functions starts executing, the program can never reach any other code (because they are infinite loops).
Handing the tasks to the RTOS for scheduling
xTaskCreate(turnRedLed, // task function
"Task1", // task name, for debugging
128, // task stack size (in words)
NULL, // parameters passed to the task function
1, // task priority, the higher the value the higher the priority
NULL); // task handle, can be used for later operations
xTaskCreate(turnBlueLed, // task function
"Task2", // task name, for debugging
128, // task stack size (in words)
NULL, // parameters passed to the task function
2, // task priority, the higher the value the higher the priority
NULL); // task handle, can be used for later operations
xTaskCreate(turnGreenLed, // task function
"Task3", // task name, for debugging
128, // task stack size (in words)
NULL, // parameters passed to the task function
3, // task priority, the higher the value the higher the priority
NULL); // task handle, can be used for later operationsIn the method above, xTaskCreate hands the tasks to the OS for scheduling.
Today's second API
void vTaskStartScheduler( void );
- Description: Starts the RTOS scheduler. After calling it, the RTOS kernel controls when each task is executed. (The RTOS is responsible for task scheduling)
Calling example:
vTaskStartScheduler();Complete Code
#include "bflb_mtimer.h"
#include "board.h"
#include "FreeRTOS.h"
#define DBG_TAG "MAIN"
#include "bflb_gpio.h"
#include "log.h"
struct bflb_device_s *gpio;
void turnRedLed()
{
while (1)
{
bflb_gpio_set(gpio, GPIO_PIN_12);
bflb_mtimer_delay_ms(1000);
bflb_gpio_reset(gpio, GPIO_PIN_12);
vTaskDelay(pdMS_TO_TICKS(1000));
// wait 1 second
}
}
void turnBlueLed()
{
while (1)
{
bflb_gpio_set(gpio, GPIO_PIN_15);
bflb_mtimer_delay_ms(1000);
bflb_gpio_reset(gpio, GPIO_PIN_15);
vTaskDelay(pdMS_TO_TICKS(1000));
// wait 1 second
}
}
void turnGreenLed()
{
while (1)
{
bflb_gpio_set(gpio, GPIO_PIN_14);
bflb_mtimer_delay_ms(1000);
bflb_gpio_reset(gpio, GPIO_PIN_14);
vTaskDelay(pdMS_TO_TICKS(1000));
// wait 1 second
}
}
int main(void)
{
board_init();
gpio = bflb_device_get_by_name("gpio");
// Red
bflb_gpio_init(gpio, GPIO_PIN_12, GPIO_OUTPUT | GPIO_PULLUP | GPIO_DRV_3);
// Blue
bflb_gpio_init(gpio, GPIO_PIN_15, GPIO_OUTPUT | GPIO_PULLUP | GPIO_DRV_3);
// Green
bflb_gpio_init(gpio, GPIO_PIN_14, GPIO_OUTPUT | GPIO_PULLUP | GPIO_DRV_3);
xTaskCreate(turnRedLed, // task function
"Task1", // task name, for debugging
128, // task stack size (in words)
NULL, // parameters passed to the task function
1, // task priority, the higher the value the higher the priority
NULL); // task handle, can be used for later operations
xTaskCreate(turnBlueLed, // task function
"Task2", // task name, for debugging
128, // task stack size (in words)
NULL, // parameters passed to the task function
2, // task priority, the higher the value the higher the priority
NULL); // task handle, can be used for later operations
xTaskCreate(turnGreenLed, // task function
"Task3", // task name, for debugging
128, // task stack size (in words)
NULL, // parameters passed to the task function
3, // task priority, the higher the value the higher the priority
NULL); // task handle, can be used for later operations
// start the scheduler
vTaskStartScheduler();
while (1)
{
}
}Expected Result
The RGB LED blinks.
- Note: never use a non-RTOS delay function inside a task; if you do, the RTOS may make scheduling errors. Use vTaskDelay(pdMS_TO_TICKS(1000)) instead.
Have questions?
For other questions, please visit the unified discussion area: Ai-Thinker Discussions

