在添加FreeRTOS支持前,需要确认现有MCU已经被FreeRTOS官方支持,可以通过以下链接判断。https://freertos.org/RTOS_ports.html。

github commit相关代码:

https://github.com/DIBULI/Dibuli-flight-controller/commit/b662fd7c50b6ffca13b77f75cfd56bfbb436620a

下载最新的FreeRTOS LTS version

  1. 进入官方github的LTS仓库,选择202210-LTS branch,然后在FreeRTOS文件夹下找到名为FreeRTOS-Kernel的submodule并且进入。

  2. 在项目根目录下执行git clone [[email protected]](<mailto:[email protected]>):FreeRTOS/FreeRTOS-Kernel.git,从而加入FreeRTOS支持。

    1. 之后进入下载好的FreeRTOS-Kernel文件夹,执行git checkout def7d2d命令来更新Kernel至LTS版本。
    2. 然后删除.git目录和.github目录和.gitmodules文件
    3. 各个文件夹下的文件有什么用可以阅读FreeRTOS-Kernel文件夹下的README.md进行了解
  3. 由于我们使用GCC工具链进行编译,所以我们可以在portable文件夹下只保留GCC和MemMang的相关文件

    1. 由于我们目前的STM32F103属于Arm Cortex-M3架构(可以从Datasheet中得知),所以在GCC文件夹下只保留ARM CM3相关文件夹
  4. 将FreeRTOS加入项目CMakeLists

    1. 由于FreeRTOS本身就支持了使用CMakeLists.txt进行编译,我们只需要在项目的CMakeLists.txt定义好FREERTOS_PORT和FREERTOS_CONFIG_FILE_DIRECTORY中加入

      1. 加入定义 set(FREERTOS_PORT “GCC_ARM_CM3“)
      2. 加入定义 set(FREERTOS_CONFIG_FILE_DIRECTORY “${PROJECT_SOURCE_DIR}/Core/inc”)
      3. 在Core/inc文件夹下创建FreeRTOSConfig.h文件并且填入以下内容
      #ifndef FREERTOSCONFIG_H
      #define FREERTOSCONFIG_H
      
      #include "stm32f1xx.h"
      
      /* Here is a good place to include header files that are required across
      your application. */
      
      extern uint32_t SystemCoreClock;
      
      #define vPortSVCHandler SVC_Handler
      #define xPortPendSVHandler PendSV_Handler
      #define xPortSysTickHandler SysTick_Handler
      #define configUSE_PREEMPTION                    1
      #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
      #define configUSE_TICKLESS_IDLE                 0
      #define configCPU_CLOCK_HZ                      ( SystemCoreClock )
      #define configTICK_RATE_HZ                      10000
      #define configMAX_PRIORITIES                    5
      #define configMINIMAL_STACK_SIZE                128
      #define configMAX_TASK_NAME_LEN                 16
      #define configUSE_16_BIT_TICKS                  0
      #define configIDLE_SHOULD_YIELD                 1
      #define configUSE_TASK_NOTIFICATIONS            1
      #define configTASK_NOTIFICATION_ARRAY_ENTRIES   3
      #define configUSE_MUTEXES                       1
      #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                  1
      #define configUSE_NEWLIB_REENTRANT              0
      #define configENABLE_BACKWARD_COMPATIBILITY     0
      #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
      #define configSTACK_DEPTH_TYPE                  uint16_t
      #define configMESSAGE_BUFFER_LENGTH_TYPE        size_t
      
      /* Memory allocation related definitions. */
      #define configSUPPORT_STATIC_ALLOCATION             0
      #define configSUPPORT_DYNAMIC_ALLOCATION            1
      #define configTOTAL_HEAP_SIZE                       7 * 1024
      #define configAPPLICATION_ALLOCATED_HEAP            4
      #define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP   0
      
      /* 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
      
      /* 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         1
      #define configMAX_SYSCALL_INTERRUPT_PRIORITY    2
      #define configMAX_API_CALL_INTERRUPT_PRIORITY   3
      
      /* 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
      
      /* 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_xTaskGetIdleTaskHandle          0
      #define INCLUDE_eTaskGetState                   0
      #define INCLUDE_xEventGroupSetBitFromISR        1
      #define INCLUDE_xTimerPendFunctionCall          0
      #define INCLUDE_xTaskAbortDelay                 0
      #define INCLUDE_xTaskGetHandle                  1
      #define INCLUDE_xTaskResumeFromISR              1
      
      /* A header file that defines trace macro can be included here. */
      
      #endif /* FREERTOSCONFIG_H */
      
      
    2. 在项目根目录下的CMakeLists.txt里面加入FreeRTOS的CMake设置

      # FreeRTOS settings
      set(FREERTOS_PORT "GCC_ARM_CM3")
      set(FREERTOS_CONFIG_FILE_DIRECTORY "${CMAKE_SOURCE_DIR}/Core/inc")
      add_subdirectory(FreeRTOS-Kernel)
      
    3. 为了能够让FreeRTOS的部分能感知到STM CMSIS的Driver,需要修改FreeRTOS根目录下的CMake文件

      1. 将原先的

        target_include_directories(freertos_kernel
            PUBLIC
                include
                ${FREERTOS_CONFIG_FILE_DIRECTORY}
                
        )
        

        修改为

        target_compile_definitions(freertos_kernel_port INTERFACE STM32F103x6)
        target_include_directories(freertos_kernel
            PUBLIC
                include
                ${FREERTOS_CONFIG_FILE_DIRECTORY}
                ../Drivers/CMSIS/Device/ST/STM32F1xx/Include
                ../Drivers/CMSIS/Include
        )
        
  5. 接下来就可以执行build并且flash到stm32里面,由于目前没有配置freeRTOS相关的系统操作,所以理论上硬件STM32的行为没有改变。

利用FreeRTOS新建LED灯闪烁项目

  1. 在Core/Inc下面新建文件fc_tasks.h

    #ifndef FCTASKS_H
    #define FCTASKS_H
    
    #include "FreeRTOS.h"
    #include "task.h"
    #include "stm32f1xx_hal.h"
    
    void task_led_blink();
    
    #endif /* FCTASKS_H */
    
    
  2. 在Core/Src下面新建文件fc_tassks.c

    #include "fctasks.h"
    
    void task_led_blink() {
        for( ;; )
        {
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
            vTaskDelay(pdMS_TO_TICKS(1000));
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
    
        /* Tasks must not attempt to return from their implementing
        function or otherwise exit.  In newer FreeRTOS port
        attempting to do so will result in an configASSERT() being
        called if it is defined.  If it is necessary for a task to
        exit then have the task call vTaskDelete( NULL ) to ensure
        its exit is clean. */
        vTaskDelete( NULL );
    }
    
  3. 在main.h里面添加#include "fctasks.h”。

  4. 在main.c里面的while循环前添加

    xTaskCreate(
      task_led_blink,
      "task_led_blink",
      configMINIMAL_STACK_SIZE,
      NULL,
      configMAX_PRIORITIES, 
      NULL
    );
    
    vTaskStartScheduler();
    
  5. 在项目CMakeLists.txt给最后的project target添加freeRTOS library支持

    # Add linked libraries
    target_link_libraries(${CMAKE_PROJECT_NAME}
        stm32cubemx
        freertos_kernel
        # Add user defined libraries
    )
    
  6. 之后进行编译,就会发现报错,报错主要集中在这几个:multiple definition of SVC_Handler, multiple definition of PendSV_Handler',multiple definition of SysTick_Handler'。

    1. multiple definition of SVC_Handler这个报错主要是因为在FreeRTOSConfig.h中我们定义了宏#define vPortSVCHandler SVC_Handler
      1. 在stm32f1xx_it.c中有对SVC_Handler做定义
      2. 在port.c中也对vPortSVCHandler有做定义,所以两者冲突
    2. 解决方法就是将stm32里面的SVC_Handler实现体注释掉。对其他两个错误也可采用相同的解决方案,具体可参见网站https://forums.freertos.org/t/svc-call-causing-hard-fault/6941/8
  7. 之后再次进行编译,便可以编译成功了。