🎀 Article Author: Ertu Electronics 🌸 Follow the public account at the end of the article to obtain other materials and project files!🐸 Looking forward to learning and communicating together!
@TOC
1. Related API Functions
First, let’s understand some API functions for querying task state information and runtime statistics. There are many functions available.

We will not introduce all these functions here; if you are interested, you can refer to ZD Atom’s “FreeRTOS Development Manual,” which provides detailed descriptions. Here, we will focus on two functions that we use the most: vTaskList() and vTaskGetRunTimeStats().
2. vTaskList() Function
By calling this function, you can obtain detailed information about each task in a tabular format. Let’s take a closer look at this function.
void vTaskList( char * pcWriteBuffer )
As you can see, this function only requires a variable to store the output information. Finally, we can print the output information through the serial port, which mainly includes the following information:
- • Name: Task name;
- • State: Task state information, R represents Ready state, B represents Blocked state, S represents Suspended state, D represents Deleted state;
- • Priority: Task priority;
- • Stack: The minimum remaining size of the task stack;
- • Num: Task number;
Let’s introduce what a Task Number is.
The task number is a unique numeric identifier assigned by the FreeRTOS kernel to each task (similar to a simplified form of a task handle). It is automatically assigned by the kernel when the task is created. The task number is mainly used for debugging and logging, allowing us to quickly identify different tasks, especially when tasks have the same name or are created dynamically. FreeRTOS assigns numbers to tasks in the order they are created, and once a task is deleted, its corresponding task number will not be reclaimed (i.e., new tasks will not reuse old numbers).
<span>It is worth noting that since the output information when calling this function can be extensive, it is best to define the variable for storing the output content as a global variable. Defining it within a task may lead to stack overflow; if you must define it within a task, ensure that the task has a larger stack to prevent overflow.</span>
Some may wonder why we do not use the tick timer to provide a time base for FreeRTOS task runtime statistics?
Indeed, the tick timer is the core time base source for the FreeRTOS system, but it cannot serve as the time base for FreeRTOS task runtime statistics. The fundamental reason is that the tick timer is too slow! In a typical FreeRTOS configuration, the tick timer frequency is 1kHz (interrupt every 1ms). If the task runtime is shorter than 1ms, the statistical results will lose precision (for example, a task runs for only 0.3ms but is counted as 0ms).
3. vTaskGetRunTimeStats() Function
This function outputs the total CPU usage time for each task in a tabular format. Let’s take a closer look at this function.
void vTaskGetRunTimeStats( char *pcWriteBuffer )
Similar to the function introduced above, this function also requires a variable to store the output content. Finally, we can print it through the serial port, and the output information mainly includes the following:
- • Task: Task name;
- • Abs Time: Absolute time the task occupies CPU usage;
- • Time: Proportion of CPU usage time for the task;
Additionally, unlike the previous function, this function requires enabling a macro and defining two additional macros. FreeRTOS actually uses a timer to implement task time statistics, so we need to initialize a timer for FreeRTOS and prepare a counting variable to track time. The two macros we defined correspond to these two parts.
According to FreeRTOS official documentation, when setting the timer, the timer’s resolution must be higher than the FreeRTOS system clock, typically 10 to 20 times higher. For example, if our FreeRTOS system clock frequency is 1KHz, which means 1ms:
#define configTICK_RATE_HZ (1000) // Clock tick frequency, set to 1000, period is 1ms
As required, the timer we provide should enter an interrupt every 50us to 100us.
<span>It is important to note that calling this function is time-consuming. We can call it during debugging to help us understand the time occupied by each task and reasonably split or merge tasks. However, do not use this function in the final product.</span>
4. Programming Test
4.1 Testing vTaskList() Function
Based on the previous article, we modified the original list-related task into a task state query task, defining a string array to store the output content. Make sure it is long enough;
// Task priority
#define INQUIRY_TASK_PRIO 3
// Task stack size
#define INQUIRY_STK_SIZE 128
// Task handle
TaskHandle_t INQUIRYTask_Handler;
// Task function
void inquiry_task(void *pvParameters);
char gTaskInfor[500]; // Store task information
// Create task information query task
xTaskCreate((TaskFunction_t )inquiry_task,
(const char* )"inquiry_task",
(uint16_t )INQUIRY_STK_SIZE,
(void* )NULL,
(UBaseType_t )INQUIRY_TASK_PRIO,
(TaskHandle_t* )&INQUIRYTask_Handler);
void inquiry_task(void *pvParameters)
{
vTaskList(gTaskInfor);
printf ("%s\r\n",gTaskInfor);
while(1)
{
Med_Led_StateReverse(LED1); // Toggle LED1 state
vTaskDelay(10);
}
}
Finally, let’s look at the output result from the serial port.

4.2 Testing vTaskGetRunTimeStats() Function
Next, we will test the vTaskGetRunTimeStats() function. As mentioned above, we need to provide a timer and a time counting variable for FreeRTOS, which means defining two macros. You can refer to the STM32 introductory notes for the timer content; we will not introduce it here, just provide the code.
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() FreeRTOSRunTimerInit() // Initialize FreeRTOS runtime statistics timer (interrupt frequency must be 10 to 20 times the FreeRTOS system clock)
#define portGET_RUN_TIME_COUNTER_VALUE() FreeRTOSRuntimeCunt // FreeRTOS runtime counting variable
volatile unsigned long long FreeRTOSRuntimeCunt = 0;
/*
*==============================================================================
* Function Name: TIM2_Init
* Function Function: Initialize Timer 2
* Input Parameters: per: Auto-reload value; psc: Prescaler coefficient
* Return Value: None
* Note: None
*==============================================================================
*/
void TIM2_Init(u16 per,u16 psc)
{
// Structure definition
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); // Enable TIM2 clock
TIM_TimeBaseInitStructure.TIM_Period = per; // Auto-reload value
TIM_TimeBaseInitStructure.TIM_Prescaler = psc; // Prescaler coefficient
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; // No prescaling
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; // Set to up counting mode
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); // Enable timer interrupt
TIM_ClearITPendingBit(TIM2,TIM_IT_Update); // Enable update interrupt
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; // Timer interrupt channel
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; // Preemption priority
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; // Sub-priority
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // Enable IRQ channel
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE); // Enable timer
}
/*
*==============================================================================
* Function Name: FreeRTOSRunTimerInit
* Function Function: FreeRTOS runtime timer initialization
* Input Parameters: None
* Return Value: None
* Note: The terminal frequency must be 10 to 20 times the FreeRTOS system clock frequency
*==============================================================================
*/
void FreeRTOSRunTimerInit(void)
{
FreeRTOSRuntimeCunt = 0; // Clear time counting variable
TIM2_Init(50 - 1,72 - 1); // Enter interrupt every 50us
}
// TIM2 interrupt service function
void TIM2_IRQHandler(void) // TIM2 interrupt
{
// Generate update interrupt
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
FreeRTOSRuntimeCunt = FreeRTOSRuntimeCunt + 1;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // Clear TIM2 update interrupt flag
}
Finally, let’s write a test function to test the functionality of the task runtime query function, directly modifying the previous task state query task into a task runtime query task, and adding a button function to trigger the output of task runtime. You can refer to the STM32 introductory notes for button detection content; we will not introduce it here, just provide the code.
// Task priority
#define RUNTIMESTATUS_TASK_PRIO 3
// Task stack size
#define RUNTIMESTATUS_STK_SIZE 128
// Task handle
TaskHandle_t RUNTIMESTATUSTask_Handler;
// Task function
void runTimeStatus_task(void *pvParameters);
char gRunTimeStatus[500];
// Create task runtime query task
xTaskCreate((TaskFunction_t )runTimeStatus_task,
(const char* )"runTimeStatus_task",
(uint16_t )RUNTIMESTATUS_STK_SIZE,
(void* )NULL,
(UBaseType_t )RUNTIMESTATUS_TASK_PRIO,
(TaskHandle_t* )&RUNTIMESTATUSTask_Handler);
// Runtime statistics task function
void runTimeStatus_task(void *pvParameters)
{
u8 keyValue = 0;
u8 i = 0;
while(1)
{
keyValue = Med_KeyScan();
if (keyValue == 1)
{
vTaskGetRunTimeStats(gRunTimeStatus);
printf ("%s\r\n",gRunTimeStatus);
}
i = i + 1;
if (i >= 50)
{
Med_Led_StateReverse(LED1); // Toggle LED1 state
i = 0;
}
vTaskDelay(10);
}
}
Let’s look at the output results.

We pressed the button multiple times, and we can see that the runtime and proportion of the runTimeStatus_task task are increasing, which is why we mentioned that the time here refers to the total time.
Program Project
Task state query and task runtime statistics.zip
https://pan.baidu.com/s/1XWEntINt2U4U2FUq_Uze_Q
Extraction code: ertu

About Us
WeChat Official Account | QQ | Learning Group

Scan to follow to discover more differences
Share
Collect
View
Like