STM32F10x SPL 集成 FreeRTOS
在整理 GCC Arm 工具链的Bluepill代码示例, 常用外设都差不多了, 接下来是 FreeRTOS, 网上查到的基本上都是基于旧版本的集成, STM32 SPL版本3.5.0, FreeRTOS版本9.x或者10.x, 不如自己用新版本集成一下. 顺便做个笔记.
转载请标明出处: https://www.cnblogs.com/milton/p/16740075.html
软件版本
STM32F10x_StdPeriph_Driver V3.6.2
ST的SPL算是教科书一般的嵌入式库, 当前市面上大部分32位MCU的库设计和命名, 都能看到SPL的影子, 有些甚至就是原盘照抄. 因为ST将中心放到了STM32Cube和HAL上, SPL基本上不再更新, 在时隔九年后的2021年才发布V3.6.2. 这部分基本稳定, 和V3.5.x相比变化很小. 所以大部分厂商也乐于用SPL作为原型开发他们的库函数, 不存在主干分叉的问题了.
ST官网上SPL的下载地址 https://www.st.com/en/embedded-software/stm32-standard-peripheral-libraries.html点击F1. 不知道ST是有意还是无意, 这个地址大部分时间是404状态. 如果无法下载, 可以使用这个备份下载地址(注:下载不需要积分)
FreeRTOS v202112.00
这个版本也发布了好一阵了, 一直没见新的版本, LTS是202012.05, 比这个还早一年, 先用这个吧.
在代码中可以看到 FreeRTOS v202112.00 对应的FreeRTOS Kernel版本是 V10.4.6
GCC Arm 11.2-2022.02
使用的 gcc-arm-11.2-2022.02-x86_64-arm-none-eabi, 次新的版本.
集成的要点
前提
已经有可以使用 GCC Arm 工具链编译的基于 SPL V3.6.2 的项目模板
需要复制的文件
从 https://www.freertos.org/下载 FreeRTOS 202112.00 , 文件比较大, 但是实际上需要的文件很少. 解开后到 FreeRTOS/Source 目录下, 复制以下的文件到项目目录下
- FreeRTOS/Source/include 整个目录, 这些是头文件
- FreeRTOS/Source 下的所有C文件
- FreeRTOS/Source/portable/GCC/ARM_CM3 目录, 这是针对 STM32F103 的适配文件
- FreeRTOS/Source/portable/MemMang 目录, 里面包含一些现成的内存管理实现
放到项目下, 目录结构是这样的
FreeRTOS ├── include │ ├── atomic.h │ ├── croutine.h │ ├── deprecated_definitions.h │ ├── event_groups.h │ ├── FreeRTOS.h │ ├── list.h │ ├── message_buffer.h │ ├── mpu_prototypes.h │ ├── mpu_wrappers.h │ ├── portable.h │ ├── projdefs.h │ ├── queue.h │ ├── semphr.h │ ├── stack_macros.h │ ├── StackMacros.h │ ├── stdint.readme │ ├── stream_buffer.h │ ├── task.h │ └── timers.h ├── portable │ ├── GCC │ │ └── ARM_CM3 │ │ ├── port.c │ │ └── portmacro.h │ └── MemMang │ ├── heap_1.c │ ├── heap_2.c │ ├── heap_3.c │ ├── heap_4.c │ └── heap_5.c ├── croutine.c ├── event_groups.c ├── list.c ├── queue.c ├── stream_buffer.c ├── tasks.c └── timers.c
需要准备的文件: FreeRTOSConfig.h
可以直接使用 FreeRTOS/Demo/CORTEX_STM32F103_Keil/ 这个例子的 FreeRTOSConfig.h, 如果要避免编译中的warning, 需要加一行
#define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 0
里面几个可调节的项
- configMINIMAL_STACK_SIZE 最小栈尺寸, 默认为128, 需要占用的内存为 128 * 4 = 512 bytes
- configTOTAL_HEAP_SIZE 声明的堆尺寸, 默认的
( ( size_t ) ( 17 * 1024 ) )
会恰好将STM32F103C8的20K内存用完
需要修改的代码: 中断处理
选项一: 替换 startup 中的中断处理函数
如果项目固定启用 FreeRTOS, 则直接在 startup 代码中修改, 对于代码中的函数名直接替换
- SVC_Handler -> vPortSVCHandler
- PendSV_Handler -> xPortPendSVHandler
- SysTick_Handler -> xPortSysTickHandler
选项二: 使用宏定义编译时替换
这个方式便于切换 FreeRTOS 和 Non-FreeRTOS 模式, 在 FreeRTOSConfig.h 中, 最后一个#endif
之前添加以下代码就可以了
/* Use MACRO to replace the handlers without changing startup file */ #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler #define xPortSysTickHandler SysTick_Handler
测试代码
以上步骤就已经完成了 FreeRTOS 的集成, 可以使用以下代码检测结果. 对于 Bluepill 板载 LED PC13 的亮灯测试.
需要注意的是, 如果使用了 FreeRTOS, 就不要再调用 SysTick_Config()
方法, 会和 FreeRTOS 冲突.
#include #include #include #include "FreeRTOS.h" #include "task.h" #include "queue.h" void vTaskFunction(void *pvParameters) { (void)(pvParameters); // Suppress "unused parameter" warning while (1) { GPIO_ResetBits(GPIOC, GPIO_Pin_13); vTaskDelay(500); GPIO_SetBits(GPIOC, GPIO_Pin_13); vTaskDelay(500); } } void LED_Config(void) { // GPIO structure for port initialization GPIO_InitTypeDef GPIO_InitStructure; // enable clock on APB2 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); /* configure port PC13 for driving an LED * Use GPIO_Pin_All if you want to drive the whole port */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // output push-pull mode GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // highest speed GPIO_Init(GPIOC, &GPIO_InitStructure); // initialize port } int main(void) { BaseType_t xReturned; /* * Don't use Delay_Init(), which conflict with FreeRTOS tick handling */ LED_Config(); xReturned = xTaskCreate( vTaskFunction, // Task function point "TaskLED", // Task name configMINIMAL_STACK_SIZE, // Use the minimum stack size, each take 4 bytes(32bit) NULL, // Parameters 2, // Priority NULL); // Task handler if (xReturned != pdPASS) { while (1); } /* Start the scheduler. */ vTaskStartScheduler(); /* Will only get here if there was not enough heap space to create the idle task. */ return 0; }
参考
- 快速上手 https://www.freertos.org/FreeRTOS-quick-start-guide.html
- 如何集成, 需要哪些文件 https://www.freertos.org/Creating-a-new-FreeRTOS-project.html
- FreeRTOS 作者 Richard Barry 的演讲,2013年 https://www.youtube.com/watch?v=1oagM_tEyeA