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.