赞
踩
SEGGER Embedded Studio虽然可以支持embOS,但是我们也可能更多的时候想移植FreeRTOS。这里我把做这个移植的操作放在这里。以便未来查阅。
在本案例中,笔者不打算使用动态内存。
移植的技术路线是
这一步非常简单,就是从FreeRTOS官网下载源码包。得到的源码文件里面是这个样子。
参考《Mastering the FreeRTOS™ Real Time Kernel》第13页的文件结构。
我们把除了croutine.c的其他的文件放到项目文件夹下新建的FreeRTOS/目录下。
一共有2个文件要用。在FreeRTOS/Source/portable/GCC/ARM-CM4F下面把cortex-m4的编译器支持包port.c和portmacro.h考过去。
记得在Project->Option->Preprocessor的User Include Directory中加入我们新建的FreeRTOS/文件夹。
因为我没有使用动态内存,所以不需要添加heap_x.c的那些文件。那些文件在FreeRTOS/Source/portable/MemMang/下面
除了那个要自己创建的FreeRTOSConfig.h,其他的在FreeRTOSv202212.01\FreeRTOS\Source\include\下面的头文件可以都考过来。虽然有那么零星的几个其实是用不上的。
这个文件必须要自己创建的。虽然官方给了很多的模板。笔者比较推荐[官方网页的模板]。(https://www.freertos.org/a00110.html)
#ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H /* Here is a good place to include header files that are required across your application. */ #include "something.h" #define configUSE_PREEMPTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 #define configUSE_TICKLESS_IDLE 0 #define configCPU_CLOCK_HZ 60000000 #define configSYSTICK_CLOCK_HZ 1000000 #define configTICK_RATE_HZ 250 #define configMAX_PRIORITIES 5 #define configMINIMAL_STACK_SIZE 128 #define configMAX_TASK_NAME_LEN 16 #define configUSE_16_BIT_TICKS 0 #define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_16_BITS #define configIDLE_SHOULD_YIELD 1 #define configUSE_TASK_NOTIFICATIONS 1 #define configTASK_NOTIFICATION_ARRAY_ENTRIES 3 #define configUSE_MUTEXES 0 #define configUSE_RECURSIVE_MUTEXES 0 #define configUSE_COUNTING_SEMAPHORES 0 #define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ #define configQUEUE_REGISTRY_SIZE 10 #define configUSE_QUEUE_SETS 0 #define configUSE_TIME_SLICING 0 #define configUSE_NEWLIB_REENTRANT 0 #define configENABLE_BACKWARD_COMPATIBILITY 0 #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 #define configUSE_MINI_LIST_ITEM 1 #define configSTACK_DEPTH_TYPE uint32_t #define configMESSAGE_BUFFER_LENGTH_TYPE size_t #define configHEAP_CLEAR_MEMORY_ON_FREE 1 #define configUSE_APPLICATION_TASK_TAG 0 #define configSTATS_BUFFER_MAX_LENGTH 0xFFFF /* Memory allocation related definitions. */ #define configSUPPORT_STATIC_ALLOCATION 1 #define configSUPPORT_DYNAMIC_ALLOCATION 1 #define configKERNEL_PROVIDED_STATIC_MEMORY 1 #define configTOTAL_HEAP_SIZE 10240 #define configAPPLICATION_ALLOCATED_HEAP 1 #define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 1 #define configENABLE_HEAP_PROTECTOR 1 /* Hook function related definitions. */ #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCHECK_FOR_STACK_OVERFLOW 0 #define configUSE_MALLOC_FAILED_HOOK 0 #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 #define configUSE_SB_COMPLETED_CALLBACK 0 /* Run time and task stats gathering related definitions. */ #define configGENERATE_RUN_TIME_STATS 0 #define configUSE_TRACE_FACILITY 0 #define configUSE_STATS_FORMATTING_FUNCTIONS 0 /* Co-routine related definitions. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES 1 /* Software timer related definitions. */ #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY 3 #define configTIMER_QUEUE_LENGTH 10 #define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE /* Interrupt nesting behaviour configuration. */ #define configKERNEL_INTERRUPT_PRIORITY [dependent of processor] #define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application] #define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application] /* Define to trap errors during development. */ #define configASSERT( ( x ) ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) /* FreeRTOS MPU specific definitions. */ #define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 #define configTOTAL_MPU_REGIONS 8 /* Default value. */ #define configTEX_S_C_B_FLASH 0x07UL /* Default value. */ #define configTEX_S_C_B_SRAM 0x07UL /* Default value. */ #define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 1 #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1 #define configENABLE_ERRATA_837070_WORKAROUND 1 #define configUSE_MPU_WRAPPERS_V1 0 #define configPROTECTED_KERNEL_OBJECT_POOL_SIZE 10 #define configSYSTEM_CALL_STACK_SIZE 128 #define configENABLE_ACCESS_CONTROL_LIST 1 /* ARMv8-M secure side port related definitions. */ #define secureconfigMAX_SECURE_CONTEXTS 5 /* Optional functions - most linkers will remove unused functions anyway. */ #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_xResumeFromISR 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 #define INCLUDE_xTaskGetSchedulerState 1 #define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_uxTaskGetStackHighWaterMark 0 #define INCLUDE_uxTaskGetStackHighWaterMark2 0 #define INCLUDE_xTaskGetIdleTaskHandle 0 #define INCLUDE_eTaskGetState 0 #define INCLUDE_xEventGroupSetBitFromISR 1 #define INCLUDE_xTimerPendFunctionCall 0 #define INCLUDE_xTaskAbortDelay 0 #define INCLUDE_xTaskGetHandle 0 #define INCLUDE_xTaskResumeFromISR 1 /* A header file that defines trace macro can be included here. */ #endif /* FREERTOS_CONFIG_H */
当然这个只是个模板。比较好的原因是这里面的每一个定义下面都有说明。我们稍加修改就可以了。
这里,笔者删掉了#include "something.h"
。
下面这三句
/* Interrupt nesting behaviour configuration. */
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
根据stm32f407改成了
/* Interrupt nesting behaviour configuration. */
#define configKERNEL_INTERRUPT_PRIORITY ( 15 << 4 )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( 5 << 4 )
#define configMAX_API_CALL_INTERRUPT_PRIORITY
因为STM32F4的中断优先级是0 - 15,所以我设置成上面的参数。当然如果觉得不保险的话还可以参考例程。
configASSERT( x )
的处理这个宏的处理方法非常多。但是如果并不真的用它,可以像我这样处理。
/* Define to trap errors during development. */
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }
configCPU_CLOCK_HZ
和configSYSTICK_CLOCK_HZ
的一点说明为了测试方便,笔者这里只是使用了芯片内部的RC震荡时钟。所以要把configCPU_CLOCK_HZ
设置成16MHz。
关于configCPU_CLOCK_HZ
和configSYSTICK_CLOCK_HZ
这个的设计的初衷我不清楚。但是根据调试的效果来看,如果定义了configSYSTICK_CLOCK_HZ
,系统的sysTick会使能8分频。
vApplicationGetIdleTaskMemory
符号把configSUPPORT_DYNAMIC_ALLOCATION
关掉。但是编译后会出现要vApplicationGetIdleTaskMemory
这个符号的问题。
参考官网上FreeRTOSConfig.h的模板的阐述,点一下configSUPPORT_STATIC_ALLOCATION的蓝字,就可以找到解决方案。就是把后面的代码加上去。
笔者的做法是在工程中建立一个新的文件,起名叫user_port.c,把这些代码加进去就好了。
/* configSUPPORT_STATIC_ALLOCATION is set to 1, so the application must provide an implementation of vApplicationGetIdleTaskMemory() to provide the memory that is used by the Idle task. */ void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, configSTACK_DEPTH_TYPE *puxIdleTaskStackSize ) { /* If the buffers to be provided to the Idle task are declared inside this function then they must be declared static - otherwise they will be allocated on the stack and so not exists after this function exits. */ static StaticTask_t xIdleTaskTCB; static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; /* Pass out a pointer to the StaticTask_t structure in which the Idle task's state will be stored. */ *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; /* Pass out the array that will be used as the Idle task's stack. */ *ppxIdleTaskStackBuffer = uxIdleTaskStack; /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. Note that, as the array is necessarily of type StackType_t, configMINIMAL_STACK_SIZE is specified in words, not bytes. */ *puxIdleTaskStackSize = configMINIMAL_STACK_SIZE; } /*-----------------------------------------------------------*/ /* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the application must provide an implementation of vApplicationGetTimerTaskMemory() to provide the memory that is used by the Timer service task. */ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, configSTACK_DEPTH_TYPE *puxTimerTaskStackSize ) { /* If the buffers to be provided to the Timer task are declared inside this function then they must be declared static - otherwise they will be allocated on the stack and so not exists after this function exits. */ static StaticTask_t xTimerTaskTCB; static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; /* Pass out a pointer to the StaticTask_t structure in which the Timer task's state will be stored. */ *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; /* Pass out the array that will be used as the Timer task's stack. */ *ppxTimerTaskStackBuffer = uxTimerTaskStack; /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. Note that, as the array is necessarily of type StackType_t, configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */ *puxTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; }
我们都知道,RTOS的运行离不开SVC_Handler、PendSV_Handler和SysTick_Handler。但是系统已经给实现了vPortSVCHandler、xPortPendSVHandler和xPortSysTickHandler。这里只要用#define把名称对应一下就可以了。
/* A header file that defines trace macro can be included here. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
FreeRTOSConfig.h
的代码根据上面的操作,笔者最后的FreeRTOSConfig.h
的代码如下所示
#ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H /* Here is a good place to include header files that are required across your application. */ #define configUSE_PREEMPTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 #define configUSE_TICKLESS_IDLE 0 #define configCPU_CLOCK_HZ 16000000 //#define configSYSTICK_CLOCK_HZ 16000000 #define configTICK_RATE_HZ 1000 #define configMAX_PRIORITIES 255 #define configMINIMAL_STACK_SIZE 128 #define configMAX_TASK_NAME_LEN 16 #define configUSE_16_BIT_TICKS 0 #define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_16_BITS #define configIDLE_SHOULD_YIELD 1 #define configUSE_TASK_NOTIFICATIONS 1 #define configTASK_NOTIFICATION_ARRAY_ENTRIES 3 #define configUSE_MUTEXES 0 #define configUSE_RECURSIVE_MUTEXES 0 #define configUSE_COUNTING_SEMAPHORES 0 #define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ #define configQUEUE_REGISTRY_SIZE 10 #define configUSE_QUEUE_SETS 0 #define configUSE_TIME_SLICING 0 #define configUSE_NEWLIB_REENTRANT 0 #define configENABLE_BACKWARD_COMPATIBILITY 0 #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 #define configUSE_MINI_LIST_ITEM 1 #define configSTACK_DEPTH_TYPE uint32_t #define configMESSAGE_BUFFER_LENGTH_TYPE size_t #define configHEAP_CLEAR_MEMORY_ON_FREE 1 #define configUSE_APPLICATION_TASK_TAG 0 #define configSTATS_BUFFER_MAX_LENGTH 0xFFFF /* Memory allocation related definitions. */ #define configSUPPORT_STATIC_ALLOCATION 1 #define configSUPPORT_DYNAMIC_ALLOCATION 0 #define configKERNEL_PROVIDED_STATIC_MEMORY 1 #define configTOTAL_HEAP_SIZE 1024 #define configAPPLICATION_ALLOCATED_HEAP 1 #define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 1 #define configENABLE_HEAP_PROTECTOR 1 /* Hook function related definitions. */ #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCHECK_FOR_STACK_OVERFLOW 0 #define configUSE_MALLOC_FAILED_HOOK 0 #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 #define configUSE_SB_COMPLETED_CALLBACK 0 /* Run time and task stats gathering related definitions. */ #define configGENERATE_RUN_TIME_STATS 0 #define configUSE_TRACE_FACILITY 0 #define configUSE_STATS_FORMATTING_FUNCTIONS 0 /* Co-routine related definitions. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES 1 /* Software timer related definitions. */ #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY 3 #define configTIMER_QUEUE_LENGTH 10 #define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE /* Interrupt nesting behaviour configuration. */ #define configKERNEL_INTERRUPT_PRIORITY ( 15 ) #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( 5 ) #define configMAX_API_CALL_INTERRUPT_PRIORITY /* Define to trap errors during development. */ #define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); } /* FreeRTOS MPU specific definitions. */ #define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 #define configTOTAL_MPU_REGIONS 8 /* Default value. */ #define configTEX_S_C_B_FLASH 0x07UL /* Default value. */ #define configTEX_S_C_B_SRAM 0x07UL /* Default value. */ #define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 1 #define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1 #define configENABLE_ERRATA_837070_WORKAROUND 1 #define configUSE_MPU_WRAPPERS_V1 0 #define configPROTECTED_KERNEL_OBJECT_POOL_SIZE 10 #define configSYSTEM_CALL_STACK_SIZE 128 #define configENABLE_ACCESS_CONTROL_LIST 1 /* ARMv8-M secure side port related definitions. */ #define secureconfigMAX_SECURE_CONTEXTS 5 /* Optional functions - most linkers will remove unused functions anyway. */ #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_xResumeFromISR 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 #define INCLUDE_xTaskGetSchedulerState 1 #define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_uxTaskGetStackHighWaterMark 0 #define INCLUDE_uxTaskGetStackHighWaterMark2 0 #define INCLUDE_xTaskGetIdleTaskHandle 0 #define INCLUDE_eTaskGetState 0 #define INCLUDE_xEventGroupSetBitFromISR 1 #define INCLUDE_xTimerPendFunctionCall 0 #define INCLUDE_xTaskAbortDelay 0 #define INCLUDE_xTaskGetHandle 0 #define INCLUDE_xTaskResumeFromISR 1 /* A header file that defines trace macro can be included here. */ #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler #define xPortSysTickHandler SysTick_Handler #endif /* FREERTOS_CONFIG_H */
参考手册,做了下面的这样一个测试用例。
/********************************************************************* * SEGGER Microcontroller GmbH * * The Embedded Experts * ********************************************************************** -------------------------- END-OF-HEADER ----------------------------- File : main.c Purpose : Generic application start */ #include "stm32f407xx.h" #include <stdio.h> #include <stdlib.h> #include "FreeRTOS.h" #include "task.h" #include "hardware.h" /********************************************************************* * * main() * * Function description * Application entry point. * **********************************************************************/ #define STACK_SIZE 200 static void vTaskMain(void *p); static StaticTask_t xTaskBuffer; static StackType_t xStack[ STACK_SIZE ]; int main(void) { int i; SystemCoreClockUpdate(); prvSetupHardware(); TaskHandle_t xHandle = NULL; /* Create the task without using any dynamic memory allocation. */ xHandle = xTaskCreateStatic( vTaskMain, /* Function that implements the task. */ "NAME", /* Text name for the task. */ STACK_SIZE, /* The number of indexes in the xStack array. */ ( void * ) 1, /* Parameter passed into the task. */ 155, /* Priority at which the task is created. */ xStack, /* Array to use as the task's stack. */ &xTaskBuffer ); /* Variable to hold the task's data structure. */ vTaskStartScheduler(); while(1); } void vTaskMain(void *p){ while(1){ GPIOA->BSRR = 1<<7; vTaskDelay(pdMS_TO_TICKS(10)); GPIOA->BSRR = 1<<7<<16; vTaskDelay(pdMS_TO_TICKS(20)); } } /*************************** End of file ****************************/
运行,用示波器测PA7的输出。
根据上述步骤,完成FreeRTOS的移植。但是本例子中没有采用到动态内存。如果要启动动态内存,就在FreeRTOSConfig.h中把configSUPPORT_DYNAMIC_ALLOCATION
这一项启用;将heap_x.c挑1个放入工程文件夹中;手动实现vPortFree函数。这次这里就不做介绍。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。