[STM32] vTaskList() and vTaskGetRunTimeStats() functions are called in FreeRTOS to get the status information and running time of each task.

Software used

  • STM32CubeMX
  • Keil5
  • xcom serial assistant
  • (HAL library used)

Introduction to FreeRTOS

RTOS (Real Time OS) real time operating system logic diagram:

  • Note: the source of the picture is the punctual atomic teaching video

FreeRTOS, released by Richard Barry of the United States in 2003, is the RTOS system with the highest market share at present.

FreeRTOS is a tailorable and deprivable multitasking kernel, and there is no limit on the number of tasks. FreeRTOS provides all the functions required by the real-time operating system, including resource management, synchronization, task communication, etc.

FreeRTOS is written in C and assembly, most of which are written in C language. Only a very few codes closely related to the processor are written in assembly. FreeRTOS has simple structure and strong readability.

FreeRTOS source code:
Latest version: www.freertos.org
Previous versions: https://sourceforge.net/projects/freertos/files/FreRTOS/

  • PS: the author uses STM32CubeMX to generate the source file of FreeRTOS. If you don't want to use Cube to generate it, you can download it from the FreeRTOS official website address above.

About vTaskList() function

vTaskList() function is a function provided in FreeRTOS to obtain task information. This function will create a list containing task name, task status information, task priority, remaining stack and task number.

The function prototype is:

void vTaskList( char * pcWriteBuffer )

About vtask getruntimestats() function

vTaskGetRunTimeStats() function is a function built-in in FreeRTOS to count the CPU time occupied by each Task. Using this function, we can clearly see the time occupied by each Task, percentage and overall CPU occupancy. The running time information of the Task provides the total CPU usage time obtained by each Task.

The vTaskGetRunTimeStats() function will fill the statistics into another list, so that we can know the CPU preemption results of all tasks at any time, so that we can plan and arrange these tasks reasonably.

The function prototype is:

void vTaskGetRunTimeStats( char *pcWriteBuffer )

How to use

Although vTaskList() function and vTaskGetRunTimeStats() function have been given in FreeRTOS, we cannot use them directly. Before using these two functions, we need to enable the following four macros:

  • configUSE_TRACE_FACILITY
  • configGENERATE_RUN_TIME_STATS
  • configUSE_STATS_FORMATTING_FUNCTIONS
  • configSUPPORT_DYNAMIC_ALLOCATION

Add the following code to FreeRTOSConfig.h to enable these four macros:

#define configUSE_TRACE_FACILITY                 1
#define configGENERATE_RUN_TIME_STATS            1
#define configUSE_STATS_FORMATTING_FUNCTIONS     1
#define configSUPPORT_DYNAMIC_ALLOCATION         1

After enabling these four macros, we must also define the following two macros:

  • portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()

  • portGET_RUN_TIME_COUNTER_VALUE()

The first macro is used to initialize a peripheral to provide the time base required for statistical functions. The resolution of this time base must be higher than the system clock of FreeRTOS, which is generally 10 ~ 20 times higher.

Add the following code to FreeRTOSConfig.h to define these two macros:

#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()   ConfigureTimerForRunTimeStates()
#define portGET_RUN_TIME_COUNTER_VALUE()           FreeRTOSRunTimeTicks

Next, we need to write the ConfigureTimerForRunTimeStates() function and define the variable freertosruntimesticks. Freertosruntimticks is used for beat counting.

Add the following code to tim.c:

  • Note: here, because the timer is initialized in tim.c, the following code is also put in tim.c for convenience
volatile unsigned long long FreeRTOSRunTimeTicks=0;
void ConfigureTimerForRunTimeStates(void)
{
	FreeRTOSRunTimeTicks= 0;
	MX_TIM3_Init();
}

Because it will need to be invoked in other C files, so don't forget to declare it again in tim.h.

extern volatile unsigned long long FreeRTOSRunTimeTicks;
void ConfigureTimerForRunTimeStates(void);

The board of stm32f427 and timer 3 (TIM3) are used here. Timer 3 is hung on APB1, and the APB1 frequency of f427 is 90MHz.

Therefore, the frequency division coefficient is set to 90 and the reload value is set to 50. At this time, the interrupt frequency = 90M/90/50=20kHz, which meets the condition that it is 20 times the beat frequency of FreeRTOS system 1000Hz. Refer to the following code for specific timer initialization configuration:

void MX_TIM3_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 90-1;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 50-1;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {

Then add the following code to the timer interrupt in main.c. for each interrupt, the FreeRTOSRunTimeTicks variable + 1:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */
  
  /* USER CODE BEGIN Callback 1 */
  if (htim->Instance == TIM3) {
    HAL_IncTick();
	FreeRTOSRunTimeTicks++;
	}
  /* USER CODE END Callback 1 */
}

After completing the above steps, the author will see an error: a1586e: bad operation types (undefot, constant) for operator ().

Here, just follow this path in port.c: configmax_syscall_interrupt_priority - > configprio_bits - > _NVIC_PRIO_BITS F12 to _NVIC_PRIO_BITS to change 4U to 4.

Here, the basic configuration has been completed. Next, you need to create a new task to count the task time:

osThreadDef(CPU_RunTime, CPU_RunTime, osPriorityHigh, 0, 128);
CPU_RunTimeHandle = osThreadCreate(osThread(CPU_RunTime), NULL);
uint8_t InfoBuffer[1000];

void CPU_RunTime(void)
{
	portTickType xLastWakeTime;
	xLastWakeTime = xTaskGetTickCount();
	while(1)
		{
			
		  osDelayUntil(&xLastWakeTime,1);//1000HZ
		  vTaskList((char *)&InfoBuffer);
		  vTaskGetRunTimeStats((char *)&InfoBuffer); 
	   if(RC_Ctl.rc.s1 == 2)
		   {
				 printf("=================================================\r\n");
				 printf("Task name        Task status priority remaining stack task number \r\n");
				 printf("=================================================\r\n");
                 printf("%s\r\n", InfoBuffer);
				 printf("  B: block  R: be ready  D: delete  S: suspend  X: function \r\n");
				 printf("=================================================\r\n");
				 printf("=================================================\r\n");
			     printf("Task name         Run count        CPU Utilization rate \r\n");
				 printf("=================================================\r\n");
		  	     printf("%s\r\n",InfoBuffer);
				 printf("=================================================\r\n");
				 printf("=================================================\r\n\n\n");
				 vTaskDelay(1300);
		   }//Total access to CPU
    }	
}

Finally, you can output the data to the computer through the serial port. Here, you also need to redirect the printf function. For details, please refer to the author's previous blog, which will not be repeated here.
[STM32] how to print data to the serial port big flicker blog CSDN blog through printf

Effect demonstration

The first table is the task status information table listed by the vtask list() function, and the second table is the CPU utilization information listed by the vtask getruntimestats() function.

Tags: Single-Chip Microcomputer stm32 FreeRTOS

Posted on Tue, 12 Oct 2021 02:37:33 -0400 by cyanblue