FreeRTOS-钩子函数

目录

钩子函数

Tick滴答钩子

空闲钩子

栈溢出钩子

守护进程钩子

钩子应用场景:获取CPU占用率

utils_cpu.h文件

utils_cpu.c文件

FreeRTOSConfig.h配置文件部分内容

实现原理

获取内存


钩子函数

Tick滴答钩子

/* FreeRTOSConfig.h */
#define configUSE_TICK_HOOK                      1

/* cmsis_os2.h */
/**
  Dummy implementation of the callback function vApplicationTickHook().
*/
#if (configUSE_TICK_HOOK == 1)
 __WEAK void vApplicationTickHook (void){}
#endif

vApplicationTickHook()函数在中断服务程序中执行,所以这个函数必须短而有效率,不能加延时,不能大量使用堆栈,也不能调用“FromISR”结尾的API函数。

vApplicationTickHook()函数的运行周期由configTICK_RATE_HZ决定,一般都设置为1ms

/* FreeRTOSConfig.h */
#define configTICK_RATE_HZ                       ((TickType_t)1000)

T = 1/f = 1/1000 = 0.001s = 1ms。 

空闲钩子

/* FreeRTOSConfig.h */
#define configUSE_IDLE_HOOK                      1

/* cmsis_os2.h */
/**
  Dummy implementation of the callback function vApplicationIdleHook().
*/
#if (configUSE_IDLE_HOOK == 1)
__WEAK void vApplicationIdleHook (void){}
#endif

运行周期:没有其它任务时,一直被调用,调用周期非常短。

如果没有其它任务优先级和空闲任务相同,那空闲任务钩子函数里不能阻塞或挂起自身。因为FreeRTOS任何时候都需要有一个任务在运行,否则可能会造成没有任务能够进入运行态。

如果其它任务占用的实际比较少,空闲钩子函数将占用大量的系统时间片资源,则用户可以将一些功能(对时序无要求)在该函数内实现。

栈溢出钩子

/* FreeRTOSConfig.h */
#define configCHECK_FOR_STACK_OVERFLOW                      1    // 或
#define configCHECK_FOR_STACK_OVERFLOW                      2

/**
  Dummy implementation of the callback function vApplicationStackOverflowHook().
*/
#if (configCHECK_FOR_STACK_OVERFLOW > 0)
__WEAK void vApplicationStackOverflowHook (TaskHandle_t xTask, signed char *pcTaskName) {
  (void)xTask;
  (void)pcTaskName;
}
#endif

运行周期:任务栈溢出时

并非所有栈溢出都会触发栈溢出钩子函数。栈溢出可能会把系统栈溢出检测代码的数据也给破坏掉了,而导致栈溢出检测失效,这时栈溢出钩子函数也就无法调用了。

参数可以知道哪个任务的栈溢出。

守护进程钩子

/* FreeRTOSConfig.h */
#define configUSE_DAEMON_TASK_STARTUP_HOOK                      1
#define configUSE_TIMER                                         1    // 钩子函数需要Timer任务下实现

/* cmsis_os2.h */
/**
  Dummy implementation of the callback function vApplicationDaemonTaskStartupHook().
*/
#if (configUSE_DAEMON_TASK_STARTUP_HOOK == 1)
__WEAK void vApplicationDaemonTaskStartupHook (void){}
#endif

钩子应用场景:获取CPU占用率

可以统计在一定周期时间内系统执行空闲任务的tick数,就可以获取到CPU空闲率(如1s内空闲任务运行了0.9s,则CPU占用率为10%)。

utils_cpu.h文件

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __UTILS_CPU_H
#define __UTILS_CPU_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* Private includes ----------------------------------------------------------*/

/* Exported types ------------------------------------------------------------*/

/* Exported constants --------------------------------------------------------*/

/* Exported macro ------------------------------------------------------------*/
#define CALCULATION_PERIOD    1000

/* Exported functions prototypes ---------------------------------------------*/
uint16_t osGetCPUUsage (void);

/* Private defines -----------------------------------------------------------*/

#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

utils_cpu.c文件

/* Includes ------------------------------------------------------------------*/
#include "utils_cpu.h"
#include "main.h"
#include "cmsis_os.h" /* _FS_REENTRANT set to 1 and CMSIS API chosen */

/* Private includes ----------------------------------------------------------*/
#include "FreeRTOS.h"                   // ARM.FreeRTOS::RTOS:Core
#include "task.h"                       // ARM.FreeRTOS::RTOS:Core

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
xTaskHandle    xIdleHandle = NULL;
__IO uint32_t  osCPU_Usage = 0; 
uint32_t       osCPU_IdleStartTime = 0; 
uint32_t       osCPU_IdleSpentTime = 0; 
uint32_t       osCPU_TotalIdleTime = 0; 

/* Private function prototypes -----------------------------------------------*/

/* Private user code ---------------------------------------------------------*/
/**
  * @brief  Application Idle Hook
  * @param  None 
  * @retval None
  */
void vApplicationIdleHook(void) 
{
	if( xIdleHandle == NULL )
	{
		/* Store the handle to the idle task. */
		xIdleHandle = xTaskGetCurrentTaskHandle();
	}
}

/**
  * @brief  Application Idle Hook
  * @param  None 
  * @retval None
  */
void vApplicationTickHook (void)
{
	static int tick = 0;
	
	if(tick ++ > CALCULATION_PERIOD)
	{
		tick = 0;
		
		if(osCPU_TotalIdleTime > 1000)
		{
		osCPU_TotalIdleTime = 1000;
		}
		osCPU_Usage = (100 - (osCPU_TotalIdleTime * 100) / CALCULATION_PERIOD);
		osCPU_TotalIdleTime = 0;
	}
}

/**
  * @brief  Start Idle monitor
  * @param  None 
  * @retval None
  */
void StartIdleMonitor (void)
{
	if( xTaskGetCurrentTaskHandle() == xIdleHandle ) 
	{
		osCPU_IdleStartTime = xTaskGetTickCountFromISR();
	}
}

/**
  * @brief  Stop Idle monitor
  * @param  None 
  * @retval None
  */
void EndIdleMonitor (void)
{
	if( xTaskGetCurrentTaskHandle() == xIdleHandle )
	{
		/* Store the handle to the idle task. */
		osCPU_IdleSpentTime = xTaskGetTickCountFromISR() - osCPU_IdleStartTime;
		osCPU_TotalIdleTime += osCPU_IdleSpentTime; 
	}
}

/**
  * @brief  Stop Idle monitor
  * @param  None 
  * @retval None
  */
uint16_t osGetCPUUsage (void)
{
	return (uint16_t)osCPU_Usage;
}

FreeRTOSConfig.h配置文件部分内容

/* FreeRTOSConfig.h */
#define configUSE_IDLE_HOOK                      1
#define configUSE_TICK_HOOK                      1

#define traceTASK_SWITCHED_IN()  extern void StartIdleMonitor(void); \
						StartIdleMonitor()
#define traceTASK_SWITCHED_OUT() extern void EndIdleMonitor(void); \
						EndIdleMonitor()

实现原理

在第一次进入空闲钩子函数时获取空闲任务的句柄到xIdleHandle,之后进入该钩子函数时忽略操作。

Tick滴答钩子函数运行周期由configTICK_RATE_HZ决定,假设设置为1ms。则每秒进一次Tick滴答钩子函数的条件判断。        

traceTASK_SWITCHED_IN()函数是每次切入到一个任务时执行,traceTASK_SWITCHED_OUT()函数是每次从一个任务中切出时执行。所以通过判断当前是不是空闲任务的进入和退出,并记录空闲任务的开始和结束时间。

traceTASK_SWITCHED_IN()函数中获取时间计数器值,traceTASK_SWITCHED_OUT()函数中获取空闲任务一次进入和退出的计数差值,即运行一次空闲任务的计数值,并进行累加。累加值在Tick滴答钩子函数中有使用到。每秒都会进一次Tick滴答钩子函数的条件判断,每次清零累加值。累加值最大1000,CPU占用率 = 1 - 空闲计数 / 1000,1000为1s计数值。代码中osCPU_Usage为CPU占用率(去掉%)。 

获取内存

获取空闲内存:xPortGetFreeHeapSize(),返回size_t(uint32_t)类型,单位为字节。

获取总内存:configTOTAL_HEAP_SIZE。

你可能感兴趣的:(#,FreeRTOS个人笔记,stm32)