简介:
我们基于之前的帖子 已经适配了 shell ,之前都是裸机环境下的开发并没有适配RTOS,我们在此基础上适配FreeRTOS。FreeRTOS的移植适配网上的教程也比较多,理论上只要把FreeRTOS 的系统文件,内存管理,架构相关适配文件,及FreeRTOS 的配置文件适配好基本就完成了移植适配,我们使用SDK软件包(STM32Cube_FW_H7RS_V1.1.0\Middlewares\Third_Party\FreeRTOS)的开始我们的主题。
我们将FreeRTOS 以下源码问价加入工程编译,解决相关的编译错误基本就完成系统的适配。
其中适配代码本地使用的iar 使用的如下的port 文件。
添加系统的配置文件编译通过后就完成了系统的适配工作,在此基础上添加系统的配置文件FreeRTOSConfig.h
/* * FreeRTOS Kernel V10.2.1 * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * http://www.FreeRTOS.org * http://aws.amazon.com/freertos * * 1 tab == 4 spaces! */ #ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H /*----------------------------------------------------------- * this is a template configuration files * * These definitions should be adjusted for your particular hardware and * application requirements. * * These parameters and more 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 *----------------------------------------------------------*/ /* Ensure stdint is only used by the compiler, and not the assembler. */ #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) #include <stdint.h> extern uint32_t SystemCoreClock; #endif /*-------------------- specific defines -------------------*/ #ifndef CMSIS_device_header #define CMSIS_device_header "stm32XXxx.h" #endif /* CMSIS_device_header */ /* If No secure feature is used the configENABLE_TRUSTZONE should be set to 0 * */ #define configENABLE_TRUSTZONE 0 #define configENABLE_FPU 1 #define configENABLE_MPU 0 /*-----------------------------------------------------------------*/ #define configUSE_PREEMPTION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configMAX_PRIORITIES (7) #define configCPU_CLOCK_HZ (SystemCoreClock) #define configTICK_RATE_HZ ((TickType_t)1000) #define configMINIMAL_STACK_SIZE ((uint16_t)128) #define configTOTAL_HEAP_SIZE ((size_t)(15 * 1024)) #define configMAX_TASK_NAME_LEN (16) #define configUSE_TRACE_FACILITY 1 #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 #define configUSE_MUTEXES 1 #define configQUEUE_REGISTRY_SIZE 8 #define configCHECK_FOR_STACK_OVERFLOW 0 #define configUSE_RECURSIVE_MUTEXES 1 #define configUSE_MALLOC_FAILED_HOOK 0 #define configUSE_APPLICATION_TASK_TAG 0 #define configUSE_COUNTING_SEMAPHORES 1 #define configGENERATE_RUN_TIME_STATS 0 /* Co-routine definitions. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES (2) /* Software timer definitions. */ #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY (2) #define configTIMER_QUEUE_LENGTH 10 #define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) /* ARMv8-M secure side port related definitions. */ /* #define secureconfigMAX_SECURE_CONTEXTS 5 */ /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskCleanUpResources 1 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_xTaskDelayUntil 0 #define INCLUDE_vTaskDelay 1 #define INCLUDE_xTaskGetSchedulerState 1 /* Optional functions - most linkers will remove unused functions anyway. */ #define INCLUDE_xQueueGetMutexHolder 1 #define INCLUDE_eTaskGetState 1 #define INCLUDE_uxTaskGetStackHighWaterMark 1 #define INCLUDE_xTimerPendFunctionCall 1 #define INCLUDE_xTaskGetCurrentTaskHandle 1 /*------------- CMSIS-RTOS V2 specific defines -----------*/ /* When using CMSIS-RTOSv2 set configSUPPORT_STATIC_ALLOCATION to 1 * is mandatory to avoid compile errors. * CMSIS-RTOS V2 implmentation requires the following defines */ //#define configSUPPORT_STATIC_ALLOCATION 1 /* cmsis_os threads are created using xTaskCreateStatic() API */ //#define configMAX_PRIORITIES (56) /* Priority range in CMSIS-RTOS V2 is [0 .. 56] */ //#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 /* when set to 1, configMAX_PRIORITIES can't be more than 32 which is not suitable for the new CMSIS-RTOS v2 priority range */ /* the CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used * by the application thus the correct define need to be enabled from the list * below * //define USE_FreeRTOS_HEAP_1 //define USE_FreeRTOS_HEAP_2 //define USE_FreeRTOS_HEAP_3 //define USE_FreeRTOS_HEAP_4 //define USE_FreeRTOS_HEAP_5 */ /* Cortex-M specific definitions. */ #ifdef __NVIC_PRIO_BITS /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ #define configPRIO_BITS __NVIC_PRIO_BITS #else #define configPRIO_BITS 4 /* 15 priority levels */ #endif /* The lowest interrupt priority that can be used in a call to a "set priority" function. */ #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf /* 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) ) /* Normal assert() semantics without relying on the provision of an assert.h header file. */ #define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); } /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS standard names. */ #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler #define xPortSysTickHandler SysTick_Handler /* IMPORTANT: xPortSysTickHandler define MUST be commented, when used with STM32Cube firmware, * to prevent overwriting SysTick_Handler defined within STM32Cube HAL, for all cores * #define xPortSysTickHandler SysTick_Handler * except for CM33, the following define should be added * #define SysTick_Handler xPortSysTickHandler */ #endif /* FREERTOS_CONFIG_H */ /* IMPORTANT: xPortSysTickHandler define MUST be commented, when used with STM32Cube firmware, to prevent overwriting SysTick_Handler defined within STM32Cube HAL, for all cores */ //xPortSysTickHandler
正常上述流程完成后就完成了FreeRTOS 的适配,但是STM32 的hal 库使用了systick 实现Hal 的delay 相关函数,而系统也需要使用systick 来调度任务切换在这块存在冲突,我们需要适配TIM 作为HAL 库的延时timebase使用的是TIM6
对应代码如下因为默认的HAL_InitTick 函数时weak 的我么在此重新定义该函式的实现实现如下。
/** ****************************************************************************** * @file stm32h7rsxx_hal_timebase_tim.c * @author MCD Application Team * @brief Template for HAL time base based on the peripheral hardware TIM6. * * This file override the native HAL time base functions (defined as weak) * the TIM time base: * + Initializes the TIM6 peripheral to generate a Period elapsed Event each 1ms * + HAL_IncTick is called inside HAL_TIM_PeriodElapsedCallback ie each 1ms * ****************************************************************************** * @attention * * Copyright (c) 2024 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ******************************************************************************/ /* Includes ------------------------------------------------------------------*/ #include "stm32h7rsxx_hal.h" /** @addtogroup STM32H7RSxx_HAL_Driver * @{ */ /** @addtogroup HAL_TimeBase * @{ */ /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ #define TIM_CNT_FREQ 1000000U /* Timer counter frequency : 1 MHz */ #define TIM_FREQ 1000U /* Timer frequency : 1 kHz => to have 1 ms interrupt */ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ TIM_HandleTypeDef htim6; /* Private function prototypes -----------------------------------------------*/ #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1U) void TimeBase_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ /* Private functions ---------------------------------------------------------*/ /** * @brief This function configures the TIM6 as a time base source. * The time source is configured to have 1ms time base with a dedicated * Tick interrupt priority. * @note This function is called automatically at the beginning of program after * reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig(). * @param TickPriority Tick interrupt priority. * @retval HAL status */ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) { RCC_ClkInitTypeDef clkconfig; uint32_t uwTimclock; uint32_t uwAPB1Prescaler; uint32_t uwPrescalerValue; uint32_t pFLatency; HAL_StatusTypeDef Status; /* Enable TIM6 clock */ __HAL_RCC_TIM6_CLK_ENABLE(); /* Get clock configuration */ HAL_RCC_GetClockConfig(&clkconfig, &pFLatency); /* Get APB1 prescaler */ uwAPB1Prescaler = clkconfig.APB1CLKDivider; /* Compute TIM6 clock */ if (uwAPB1Prescaler == RCC_APB1_DIV1) { uwTimclock = HAL_RCC_GetPCLK1Freq(); } else if (uwAPB1Prescaler == RCC_APB1_DIV2) { uwTimclock = 2UL * HAL_RCC_GetPCLK1Freq(); } else { if (__HAL_RCC_GET_TIMCLKPRESCALER() == RCC_TIMPRES_DISABLE) { uwTimclock = 2UL * HAL_RCC_GetPCLK1Freq(); } else { uwTimclock = 4UL * HAL_RCC_GetPCLK1Freq(); } } /* Compute the prescaler value to have TIM6 counter clock equal to TIM_CNT_FREQ */ uwPrescalerValue = (uint32_t)((uwTimclock / TIM_CNT_FREQ) - 1U); /* Initialize TIM6 */ htim6.Instance = TIM6; /* Initialize TIMx peripheral as follow: + Period = [uwTickFreq * (TIM_CNT_FREQ/TIM_FREQ) - 1]. to have a (uwTickFreq/TIM_FREQ) s time base. + Prescaler = (uwTimclock/TIM_CNT_FREQ - 1) to have a TIM_CNT_FREQ counter clock. + ClockDivision = 0 + Counter direction = Up */ htim6.Init.Period = ((uint32_t)uwTickFreq * (TIM_CNT_FREQ / TIM_FREQ)) - 1U; htim6.Init.Prescaler = uwPrescalerValue; htim6.Init.ClockDivision = 0; htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; Status = HAL_TIM_Base_Init(&htim6); if (Status == HAL_OK) { #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1U) HAL_TIM_RegisterCallback(&htim6, HAL_TIM_PERIOD_ELAPSED_CB_ID, TimeBase_TIM_PeriodElapsedCallback); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ /* Start the TIM time Base generation in interrupt mode */ Status = HAL_TIM_Base_Start_IT(&htim6); if (Status == HAL_OK) { if (TickPriority < (1UL << __NVIC_PRIO_BITS)) { /* Configure the TIM6 global Interrupt priority */ HAL_NVIC_SetPriority(TIM6_IRQn, TickPriority, 0); /* Enable the TIM6 global Interrupt */ HAL_NVIC_EnableIRQ(TIM6_IRQn); uwTickPrio = TickPriority; } else { Status = HAL_ERROR; } } } /* Return function status */ return Status; } /** * @brief Suspend Tick increment. * @note Disable the tick increment by disabling TIM6 update interrupt. * @retval None */ void HAL_SuspendTick(void) { /* Disable TIM6 update interrupt */ __HAL_TIM_DISABLE_IT(&htim6, TIM_IT_UPDATE); } /** * @brief Resume Tick increment. * @note Enable the tick increment by enabling TIM6 update interrupt. * @retval None */ void HAL_ResumeTick(void) { /* Enable TIM6 update interrupt */ __HAL_TIM_ENABLE_IT(&htim6, TIM_IT_UPDATE); } /** * @brief Period elapsed callback in non blocking mode * @note This function is called when TIM6 interrupt took place, inside * HAL_TIM6_IRQHandler(). It makes a direct call to HAL_IncTick() to increment * a global variable "uwTick" used as application time base. * @param htim TIM handle * @retval None */ #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1U) void TimeBase_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { /* Prevent unused argument(s) compilation warning */ UNUSED(htim); HAL_IncTick(); } #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ /** * @} */ /** * @} */
添加tim6 的超时函数更新HAL库计数器数值。
/** * @brief Period elapsed callback in non blocking mode * @note This function is called when TIM17 interrupt took place, inside * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment * a global variable "uwTick" used as application time base. * @param htim TIM handle * @retval None */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { /* USER CODE BEGIN Callback 0 */ /* USER CODE END Callback 0 */ if (htim->Instance == TIM6) { HAL_IncTick(); } /* USER CODE BEGIN Callback 1 */ /* USER CODE END Callback 1 */ }
至此FreeRTOS 的适配工作就结束了,饿哦们添加如下代码启动之前裸机的shell 任务及task1 / task2 周期打印log 验证FreeRTOS 是否正常调度。
#define START_TASK_PRIO 2 #define START_STK_SIZE 128 TaskHandle_t StartTask_Handler; void start_task(void *pvParameters); #define TASK1_TASK_PRIO 2 #define TASK1_STK_SIZE 128 TaskHandle_t Task1Task_Handler; void start_task1(void *pvParameters); #define SHELL_TASK_PRIO 2 #define SHELL_STK_SIZE 256 TaskHandle_t ShellTask_Handler; void start_task(void *pvParameters) { while(1) { PRINTF("task1 .\r\n"); vTaskDelay(500); } } void start_task1(void *pvParameters) { while(1) { PRINTF("task2 .\r\n"); vTaskDelay(1000); } } main() { xTaskCreate((TaskFunction_t )start_task, (const char* )"task1", (uint16_t )START_STK_SIZE, (void* )NULL, (UBaseType_t )START_TASK_PRIO, (TaskHandle_t* )&StartTask_Handler); xTaskCreate((TaskFunction_t )start_task1, (const char* )"task2", (uint16_t )TASK1_STK_SIZE, (void* )NULL, (UBaseType_t )TASK1_TASK_PRIO, (TaskHandle_t* )&Task1Task_Handler); xTaskCreate((TaskFunction_t )littleshell_main_entry, (const char* )"shell", (uint16_t )SHELL_STK_SIZE, (void* )NULL, (UBaseType_t )SHELL_TASK_PRIO, (TaskHandle_t* )&Task1Task_Handler); vTaskStartScheduler(); }
将代码烧录到板子中运行发现 task1/task2 回周期的打印log,shell 任务也可以响应输入,至此FreeRTOS 已经正常的跑起来了。