在整理 GCC Arm 工具鏈的Bluepill代碼示例, 常用外設都差不多了, 接下來是 FreeRTOS, 網上查到的基本上都是基於舊版本的集成, STM32 SPL版本3.5.0, FreeRTOS版本9.x或者10.x, 不如自己用新版本集成一下. 順便做個筆記. STM32F10x_Std... ...
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 <stm32f10x.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_rcc.h>
#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