freeRtos学习笔记 移植和CPU利用率统计
Posted 不咸不要钱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了freeRtos学习笔记 移植和CPU利用率统计相关的知识,希望对你有一定的参考价值。
freeRtos学习笔记 (9) 移植和CPU利用率统计
使用官方固件移植
首先准备一个能跑的裸机工程
- 注意,freertos需要使用systick定时器,而stm32HAL库默认使用systick作为时基
- 方法一 :可以在stm32CUBEMX创建工程时修改HAL库时基使用的定时器
- 方法二 :修改HAL库关于时基的函数
由于这两个函数HAL库中都是带__weak前缀的(如果用户不提供则用该函数,如果用户重写则会覆盖带__weak前缀的函数),直接写自己的即可
/*!
* @brief 汇编延时
*
* @param ulCount:延时时钟数
*
* @return 无
*
* @note ulCount每增加1,该函数增加6个时钟(M4是3个时钟)
*
* @see
*/
#if defined (__CC_ARM) /*!< ARM Compiler */
__asm void userDelay(unsigned long ulCount)
{
subs r0, #1;
bne userDelay;
bx lr;
}
#elif defined ( __ICCARM__ ) /*!< IAR Compiler */
void userDelay(unsigned long ulCount)
{
__asm(" subs r0, #1\\n"
" bne.n userDelay\\n"
" bx lr");
}
#elif defined (__GNUC__) /*!< GNU Compiler */
void __attribute__((naked)) userDelay(unsigned long ulCount)
{
__asm(" subs r0, #1\\n"
" bne userDelay\\n"
" bx lr");
}
#elif defined (__TASKING__) /*!< TASKING Compiler */
/*?*/
#endif /* __CC_ARM */
#include "FreeRTOS.h"
#include "task.h"
uint32_t HAL_GetTick (void)
{
static uint32_t ticks = 0U;
if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
{
return ((uint32_t)xTaskGetTickCount());
}
/* 如果OS还没有运行,采用下面方式 */
userDelay((SystemCoreClock/6000));
return ++ticks;
}
HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)
{
return HAL_OK;
}
下载freeRtos固件
下载地址 https://freertos.org/a00104.html
GitHub地址 https://github.com/FreeRTOS/FreeRTOS
将freeRtos添加进工程
- 将下载后的freeRtos固件解压,将Source文件夹复制到准备好的裸机工程中并将文件夹名由Source改为FreeRtos
- 向工程中添加一个FreeRTOSConfig.h文件模板,并根据要求自行裁剪
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
#if (defined(__ARMCC_VERSION) || defined(__GNUC__) || defined(__ICCARM__))
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
/* Constants that describe the hardware and memory usage. */
#define configCPU_CLOCK_HZ (SystemCoreClock)
#define configTICK_RATE_HZ ((TickType_t)1000)
#define configTOTAL_HEAP_SIZE ((size_t)1024*40)
#define configMINIMAL_STACK_SIZE ((uint16_t)256)
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configSUPPORT_STATIC_ALLOCATION 0
/* Constants related to the behaviour or the scheduler. */
#define configMAX_PRIORITIES 5
#define configUSE_PREEMPTION 1
#define configUSE_TIME_SLICING 1
#define configIDLE_SHOULD_YIELD 0
#define configMAX_TASK_NAME_LEN (10)
#define configUSE_16_BIT_TICKS 0
/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY 2
#define configTIMER_QUEUE_LENGTH 5
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2)
/* Constants that build features in or out. */
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_QUEUE_SETS 1
#define configUSE_TASK_NOTIFICATIONS 1
#define configUSE_TRACE_FACILITY 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_NEWLIB_REENTRANT 0
#define configUSE_CO_ROUTINES 0
/* Constants provided for debugging and optimisation assistance. */
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configQUEUE_REGISTRY_SIZE 0
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }
/* Constants that define which hook (callback) functions should be used. */
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
#define configUSE_MALLOC_FAILED_HOOK 0
/* Port specific configuration. */
#define configENABLE_MPU 0
#define configENABLE_FPU 1
#define configENABLE_TRUSTZONE 1
#define configMINIMAL_SECURE_STACK_SIZE ((uint32_t)1024)
#define configRUN_FREERTOS_SECURE_ONLY 0
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __NVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
/* 7 priority levels */
#define configPRIO_BITS 4
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x0f
/* The highest interrupt priority that can be used by any interrupt service
* routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT
* CALL INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A
* HIGHER PRIORITY THAN THIS! (higher priorities are lower numeric values). */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/* Interrupt priorities used by the kernel port layer itself. These are generic
* to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
* See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
/* Set the following definitions to 1 to include the API function, or zero
* to exclude the API function. NOTE: Setting an INCLUDE_ parameter to 0 is
* only necessary if the linker does not automatically remove functions that are
* not referenced anyway. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xQueueGetMutexHolder 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_uxTaskGetStackHighWaterMark2 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTaskResumeFromISR 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
/* Map the FreeRTOS port interrupt handlers to their CMSIS standard names. */
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#define xPortSysTickHandler SysTick_Handler
#if (defined(__ARMCC_VERSION) || defined(__GNUC__) || defined(__ICCARM__))
/* Include debug event definitions */
//#include "freertos_evr.h"
#endif
#endif /* FREERTOS_CONFIG_H */
-
将FreeRTOS文件和文件路径信息添加到工程中
heap_4.c文件和内存分配有关,可以根据需要自行选择 heap_1-4文件,不过一般选择heap_4.c文件即可
需要注意的是port.c文件,当选择不同编译器版本时,使用的port.c是不同的,AC5用的是RVDS文件夹下ARM_CM3(STM32F1系列是CM3内核的)内的port.c
AC6用的是GCC文件夹下ARM_CM3(STM32F1系列是CM3内核的)内的port.c,个人比较喜欢用AC6,因为编译速度更快,但是有个小问题,不能有中文路径 否则不能gotodef
最后记得将头文件路径告诉MDK,FreeRTOSConfig.h的头文件路径也要记得告诉MDK
-
屏蔽HAL库中的中断服务函数
freeRtos使用了三个中断 SVC、PenSVC、Systick。SVC只在vTaskStartScheduler中被调用一次,用作启动第一个任务,简单来说就是进入线程模式,将MSP变成PSP。PenSVC用作任务切换,Systick用作系统时基。
编写闪灯任务,验证移植结果
/*!
* @brief 汇编延时
*
* @param ulCount:延时时钟数
*
* @return 无
*
* @note ulCount每增加1,该函数增加6个时钟(M4是3个时钟)
*
* @see
*/
#if defined (__CC_ARM) /*!< ARM Compiler */
__asm void userDelay(unsigned long ulCount)
{
subs r0, #1;
bne userDelay;
bx lr;
}
#elif defined ( __ICCARM__ ) /*!< IAR Compiler */
void userDelay(unsigned long ulCount)
{
__asm(" subs r0, #1\\n"
" bne.n userDelay\\n"
" bx lr");
}
#elif defined (__GNUC__) /*!< GNU Compiler */
void __attribute__((naked)) userDelay(unsigned long ulCount)
{
__asm(" subs r0, #1\\n"
" bne userDelay\\n"
" bx lr");
}
#elif defined (__TASKING__) /*!< TASKING Compiler */
/*?*/
#endif /* __CC_ARM */
#include "FreeRTOS.h"
#include "task.h"
uint32_t HAL_GetTick (void)
{
static uint32_t ticks = 0U;
if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
{
return ((uint32_t)xTaskGetTickCount());
}
/* 如果OS还没有运行,采用下面方式 */
userDelay((SystemCoreClock/6000));
return ++ticks;
}
HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)
{
return HAL_OK;
}
void vTaskLED(void * pvParameters)
{
while(1)
{
vTaskDelay(100);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
}
static TaskHandle_t ledTaskHandle;
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* 关闭中断 防止初始化过程中进入中断 因为中断服务函数中可能使用freertos API
而此时freertos还未启动 freertos启动时会自动开启中断
*/
taskDISABLE_INTERRUPTS();
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
BaseType_t pd = xTaskCreate(vTaskLED, "TaskLED", 128, 0, 1, &ledTaskHandle);
if(pd != pdPASS)
{
//创建任务失败
}
vTaskStartScheduler();
while (1)
{
}
/* USER CODE END 3 */
}
CPU利用率
CPU利用率的原理就是定义一个精度至少是systick精度10倍的定时器,当任务切换时,任务控制块记录任务累计运行时长(利用高精度定时器)
- 开启高精度定时器
创建回调函数,记录高精度定时器节拍,注意高精度定时器中断会严重影响系统性能。
/* 高精度定时器计数器 */
volatile uint32_t g_ulTick = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM6)
{
g_ulTick++;
}
}
- 修改FreeRTOSConfig.h配置文件
使用FreeRTOS中自带的性能统计函数需要开启一些宏定义,任务切换时,任务控制块记录任务累计运行时长(利用高精度定时器)
#define configUSE_TRACE_FACILITY 1
#define configGENERATE_RUN_TIME_STATS 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (g_ulTick = 0ul)
#define portGET_RUN_TIME_COUNTER_VALUE() g_ulTick
- 创建一个CPU利用率统计任务
为了提高效率,将printf重定向到Event Recorder中间件,详细过程参考 https://blog.csdn.net/weixin_42378319/article/details/117920784
/*!
* @brief 汇编延时
*
* @param ulCount:延时时钟数
*
* @return 无
*
* @note ulCount每增加1,该函数增加6个时钟(M4是3个时钟)
*
* @see
*/
#if defined (__CC_ARM) /*!< ARM Compiler */
__asm void userDelay(unsigned long ulCount)
{
subs r0, #1;
bne userDelay;
bx lr;
}
#elif defined ( __ICCARM__ ) /*!< IAR Compiler */
void userDelay(unsigned long ulCount)
{
__asm(" subs r0, #1\\n"
" bne.n userDelay\\n"
" bx lr");
}
#elif defined (__GNUC__) /*!< GNU Compiler */
void __attribute__((naked)) userDelay(unsigned long ulCount)
{
__asm(" subs r0, #1\\n"
" bne userDelay\\n"
" bx lr");
}
#elif defined (__TASKING__) /*!< TASKING Compiler */
/*?*/
#endif /* __CC_ARM */
#include "FreeRTOS.h"
#include "task.h"
#include <stdio.h>
#include "EventRecorder.h"
uint32_t HAL_GetTick (void)
{
static uint32_t ticks = 0U;
if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
{
return ((uint32_t)xTaskGetTickCount());
}
/* 如果OS还没有运行,采用下面方式 */
userDelay((SystemCoreClock/6000));
return ++ticks;
}
HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)
{
return HAL_OK;
}
void vTaskLED(void * pvParameters)
{
while(1)
{
vTaskDelay(100);
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
}
}
void vTaskTaskUtilization(void *pvParameters)
{
uint8_t ucKeyCode;
uint8_t pcWriteBuffer[500];
while(1)
{
printf("=================================================\\r\\n");
printf("任务名 任务状态 优先级 剩余栈 任务序号\\r\\n");
vTaskList((char *)&pcWriteBuffer);
printf("%s\\r\\n", pcWriteBuffer);
printf("\\r\\n任务名 运行计数 使用率\\r\\n");
vTaskGetRunTimeStats((char *)&pcWriteBuffer);
printf("%s\\r\\n", pcWriteBuffer);
vTaskDelay(2000);
}
}
static TaskHandle_t ledTaskHandle;
static TaskHandle_t taskUtilizationTaskHandle;
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* 关闭中断 防止初始化过程中进入中断 因为中断服务函数中可能使用freertos API
而此时freertos还未启动 freertos启动时会自动开启中断
*/
taskDISABLE_INTERRUPTS();
EventRecorderInitialize(EventRecordAll, 1);
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM6_Init();
HAL_TIM_Base_Start_IT(&htim6);
BaseType_t pd = xTaskCreate(vTaskLED, "TaskLED", 128, 0, 2, &ledTaskHandle);
if(pd != pdPASS)
{
//创建任务失败
}
pd = xTaskCreate(vTaskTaskUtilization, "TaskUtilization", 1024, 0, 1, &taskUtilizationTaskHandle);
if(pd != pdPASS)
{
//创建任务失败
}
vTaskStartScheduler();
while (1);
}
/* 高精度定时器计数器 */
volatile uint32_t g_ulTick = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM6)
{
g_ulTick++;
}
}
使用MDK中间件移植
首先准备一个能跑的裸机工程
和使用固件库移植第一步一样
安装MDK中间件
如果网不好,可以通过 http://www.armbbs.cn/forum.php?mod=viewthread&tid=96992&highlight=pack 镜像下载后,自行安装
安装完组件后,向工程中添加组件
修改FreeRTOSConfig.h文件模板,并根据要求自行裁剪
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
#if (defined(__ARMCC_VERSION) || defined(__GNUC__) || defined(__ICCARM__))
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
/* Constants that describe the hardware and memory usage. */
#define configCPU_CLOCK_HZ (SystemCoreClock)
#define configTICK_RATE_HZ ((TickType_t)1000)
#define configTOTAL_HEAP_SIZE ((size_t)1024*40)
#define configMINIMAL_STACK_SIZE ((uint16_t)256)
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configSUPPORT_STATIC_ALLOCATION 0
/* Constants related to the behaviour or the scheduler. */
#define configMAX_PRIORITIES 5
#define configUSE_PREEMPTION 1
#define configUSE_TIME_SLICING 1
#define configIDLE_SHOULD_YIELD 0
#define configMAX_TASK_NAME_LEN (10)
#define configUSE_16_BIT_TICKS 0
/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY 2
#define configTIMER_QUEUE_LENGTH 5
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2)
/* Constants that build features in or out. */
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_QUEUE_SETS 1
#define configUSE_TASK_NOTIFICATIONS 1
#define configUSE_TRACE_FACILITY 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_NEWLIB_REENTRANT 0
#define configUSE_CO_ROUTINES 0
/* Constants provided for debugging and optimisation assistance. */
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configQUEUE_REGISTRY_SIZE 0
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }
/* Constants that define which hook (callback) functions should be used. */
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
#define configUSE_MALLOC_FAILED_HOOK 0
/* Port specific configuration. */
#define configENABLE_MPU 0
#define configENABLE_FPU 1
#define configENABLE_TRUSTZONE 1
#define configMINIMAL_SECURE_STACK_SIZE ((uint32_t)1024)
#define configRUN_FREERTOS_SECURE_ONLY 0
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __NVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
/* 7 priority levels */
#define configPRIO_BITS 4
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x0f
/* The highest interrupt priority that can be used by any interrupt service
* routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT
* CALL INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A
* HIGHER PRIORITY THAN THIS! (higher priorities are lower numeric values). */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/* Interrupt priorities used by the kernel port layer itself. These are generic
* to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
/* !!!! con以上是关于freeRtos学习笔记 移植和CPU利用率统计的主要内容,如果未能解决你的问题,请参考以下文章
FreeRTOSFreeRTOS学习笔记— 使用STM32CubeMX对F407ZGT6移植FreeRTOS(CMSIS API)