freeRtos学习笔记 (9) 移植和CPU利用率统计
freeRtos學習筆記 (9) 移植和CPU利用率統計
使用官方固件移植
首先準備一個能跑的裸機工程
- 注意,freertos需要使用systick定時器,而stm32HAL庫默認使用systick作為時基
- 方法一 :可以在stm32CUBEMX創建工程時修改HAL庫時基使用的定時器
- 方法二 :修改HAL庫關于時基的函數
由于這兩個函數HAL庫中都是帶__weak前綴的(如果用戶不提供則用該函數,如果用戶重寫則會覆蓋帶__weak前綴的函數),直接寫自己的即可
下載freeRtos固件
下載地址 https://freertos.org/a00104.html
GitHub地址 https://github.com/FreeRTOS/FreeRTOS
將freeRtos添加進工程
將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倍的定時器,當任務切換時,任務控制塊記錄任務累計運行時長(利用高精度定時器)
創建回調函數,記錄高精度定時器節拍,注意高精度定時器中斷會嚴重影響系統性能。
使用FreeRTOS中自帶的性能統計函數需要開啟一些宏定義,任務切換時,任務控制塊記錄任務累計運行時長(利用高精度定時器)
為了提高效率,將printf重定向到Event Recorder中間件,詳細過程參考 https://blog.csdn.net/weixin_42378319/article/details/117920784
使用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))/* !!!! 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 */編寫閃燈任務,驗證移植結果
/*!* @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利用率外,還有一種更為簡單的方法
使用keil的Event Recorder中間件可以十分簡單的觀察RTOS運行時的狀態, Event Recorder中間件使用可以參考博客 https://blog.csdn.net/weixin_42378319/article/details/110131289?spm=1001.2014.3001.5501
細心的童鞋可能會發現,使用MDK中間件創建的FreeRTOS工程多了一個文件,這個文件是官方專為FreeRTOS調試編寫的
3. 調出FreeRTOS RTOS窗口和System Analyzer窗口,查看RTOS運行狀態
本質上還是利用Event Recorder中間件,啟用Event Recorder中間件后,FreeRTOS代碼會通過宏定義開啟一些函數,例如任務在創建時,會通過Event Recorder中間件在RAM中緩存固定格式數據,MDK讀取固定格式數據,轉換到窗體上顯示出來
System Analyzer窗口有點小問題,不能顯示任務名稱,只顯示了任務的地址信息,可以兩個窗口結合著看
使用中間件缺點是需要安裝對應中間件,不方便更換電腦,但是也可以根據文件目錄,將對應中間件文件復制添加到工程中,從而不適用中間件
總結
以上是生活随笔為你收集整理的freeRtos学习笔记 (9) 移植和CPU利用率统计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 调试笔记--keil 测量周期小技巧
- 下一篇: 调试笔记--jlink 变量转实时波形小