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添加进工程

  1. 将下载后的freeRtos固件解压,将Source文件夹复制到准备好的裸机工程中并将文件夹名由Source改为FreeRtos
    在这里插入图片描述
  2. 向工程中添加一个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 */
  1. 将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
    在这里插入图片描述

  2. 屏蔽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倍的定时器,当任务切换时,任务控制块记录任务累计运行时长(利用高精度定时器)

在这里插入图片描述

  1. 开启高精度定时器
    在这里插入图片描述
    创建回调函数,记录高精度定时器节拍,注意高精度定时器中断会严重影响系统性能。
/* 高精度定时器计数器 */
volatile uint32_t g_ulTick = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim->Instance == TIM6)
  {
    g_ulTick++;
  }
}
  1. 修改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

在这里插入图片描述

  1. 创建一个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利用率统计的主要内容,如果未能解决你的问题,请参考以下文章

FreeRTOS学习笔记1—FreeRTOS移植

FreeRTOS学习笔记1—FreeRTOS移植

FreeRTOS学习笔记1—FreeRTOS移植

FreeRTOS学习笔记1—FreeRTOS移植

FreeRTOS学习笔记4

FreeRTOSFreeRTOS学习笔记— 使用STM32CubeMX对F407ZGT6移植FreeRTOS(CMSIS API)