FreeRTOS是如今在小型嵌入式領域應用比較廣泛的一種實時操作系統。它是一種開源且免費的操作系統,而且移植和使用都非常的簡單。在這里我們將學習並移植FreeRTOS。
1、必要的准備
工欲善其事,必先利其器,在開始學習和移植之前,相應的准備工作必不可少。所以在開始我們需要有必要的准備:
- 下載FreeRTOS源碼,可以從官網下載源碼,最新版本為V10.0.1,官網地址:https://www.freertos.org/a00104.html
- 下載學習資料,FreeRTOS官方提供入門手冊和參考手冊,可以在線查看,也可以下載pdf版本的電子書。下載網址:https://www.freertos.org/Documentation/RTOS_book.html
- 准備實驗平台,此次我們將在STM32F407平台上移植和測試FreeRTOS系統
下載的FreeRTOS源碼是一個自解壓的文件,解壓后包含的內容比較豐富,不過目錄結構很清晰,主要包含兩個子目錄:FreeRTOS和FreeRTOS-Plus。如下所示:
- FreeRTOS-Plus 包含FreeRTOS+組件和演示例程;
- FreeRTOS 包含FreeRTOS實時內核源文件和演示例程。

我們學習的FreeRTOS內核部分在FreeRTOS目錄之下,打開FreeRTOS文件夾它又被分成兩個主要的子目錄,如下所示:
- Demo 包含演示例程工程;
- License 包含授權文件
- Source 包含實時內核源文件。

RTOS代碼的核心包含在三個文件中:tasks.c、queue.c、list.c。這三個文件位於FreeRTOS/Source目錄。在該目錄下還包含三個可選的文件:timers.c、event_groups.c、croutine.c,分別實現軟件定時、事件組和協程功能。打開Source文件夾,FreeRTOS/Source目錄結構如下所示:

應用平台的不同,所以每個支持的處理器架構都有一段與處理器架構相關的RTOS代碼。這個是RTOS移植層,它位於FreeRTOS/Source/Portable/[相應編譯器]/[相應CPU架構]子目錄。
對於FreeRTOS,堆棧設計也屬於移植層。FreeRTOS/Source/portable/MemMang目錄下heap_x.c文件給出了多種堆棧方案,在后續的移植中,會詳細說明。
2、簡單的移植
前面我們簡要說明了移植的准備工作,接下來我們開始最主要的移植。本次移植我們將在IAR平台上進行,首先要創建一個IAR項目。我們在IAR下創建一個名為pfreertos的項目,並添加Application、Drivers和Middlewares幾個組。並在Application下添加EWARM和User組;在Drivers下添加CMSIS和STM32F4xx_HAL_Driver組;在Middlewares下添加FreeRTOS組,具體如下:

至於具體文件的物理路徑並沒有特別要求,但為了便於管理,我們強烈建議放到一起。並將相關的FreeRTOS源碼拷貝到該項目目錄下。
將\FreeRTOSv10.0.1\FreeRTOS\Source目錄下的源文件及include文件夾復制到新建項目的文件夾中。

將\FreeRTOSv10.0.1\FreeRTOS\Source\portable\IAR\ARM_CM4F目錄下的三個文件也復制到新建項目的文件夾。

將\FreeRTOSv10.0.1\FreeRTOS\Source\portable\MemMang目錄下的heap_4.c文件復制到新建項目的文件夾。

將\FreeRTOSv10.0.1\FreeRTOS\Demo\CORTEX_M4F_STM32F407ZG-SK目錄下的FreeRTOSConfig.h文件復制到新建項目的文件夾。

同時將這下文件添加到我們前面創建的pfreertos項目中,其它如ST驅動及用戶應用也添加到項目中。並將相關的引用目錄添加到項目屬性中。需要說一下的是在Assembler中的Preprocessor標簽下添加也需要添加FreeRTOSConfig.h的引用路徑,因為在匯編文件中有對FreeRTOSConfig.h文件的引用。

在FreeRTOSConfig.h 配置文件中,有如下3個宏定義:
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
需要在stm32f4xx_it.c文件中,將對應的三個空的函數定義注釋掉。至此,其實編譯就已不會有錯,移植工作已經完成。當然在有些其他的基礎庫也需要使用SysTick時,我們也可以在中斷中調用xPortSysTickHandler()函數來實現我們的需求。
3、移植測試
前面我們已經移植了FreeRTOS,接下來我們創建多個任務測試一下它。
在main.c文件中添加相應的代碼,聲明如下函數及代碼(我計划4個任務):
1 /*************************************************************************** 2 函數聲明 3 ***************************************************************************/ 4 static void vTask1(void *pvParameters); 5 static void vTask2(void *pvParameters); 6 static void vTask3(void *pvParameters); 7 static void vTask4(void *pvParameters); 8 static void AppTaskCreate (void); 9 10 /*************************************************************************** 11 變量聲明 12 ***************************************************************************/ 13 static TaskHandle_t xHandleTask1 = NULL; 14 static TaskHandle_t xHandleTask2 = NULL; 15 static TaskHandle_t xHandleTask3 = NULL; 16 static TaskHandle_t xHandleTask4 = NULL;
任務創建函數如下:
1 static void AppTaskCreate (void) 2 { 3 xTaskCreate( vTask1, "vTask1",512, NULL,1, &xHandleTask1); 4 xTaskCreate( vTask2, "vTask2",512, NULL,1, &xHandleTask2); 5 xTaskCreate( vTask3, "vTask3",512, NULL,1, &xHandleTask3); 6 xTaskCreate( vTask4, "vTask4",512, NULL,1, &xHandleTask4); 7 }
主函數如下:
1 int main(void) 2 { 3 /* 創建任務 */ 4 AppTaskCreate(); 5 /* 啟動任務調度,開始執行任務 */ 6 vTaskStartScheduler(); 7 }
編譯無錯誤4個任務同時運行。移植初步測試成功。
4、幾點說明
在FreeRTOS中定義了多種內存管理方式,對應的文件有5個,那么每個文件實現了什么?怎么選用呢?我們對於內存管理的幾個文件的大致內容描述如下:
- heap_1.c:這是所有實現中最簡單的一個。一旦分配內存之后,它甚至不允許釋放分配的內存。
- heap_2.c:和heap_1不同,這個方案使用一個最佳匹配算法,它允許釋放之前分配的內存塊。它不會把相鄰的空閑塊合成一個更大的塊,可能會造成內存碎片。
- heap_3.c:簡單的包裝了標准庫中的malloc()和free()函數,包裝后的malloc()和free()函數具備線程保護。
- heap_4.c:這個方案使用一個最佳匹配算法,但不像方案2那樣。它會將相鄰的空閑內存塊合並成一個更大的塊。
- heap_5.c:這個方案同樣實現了heap_4.c中的合並算法,並且允許堆棧跨越多個非連續的內存區。
在前面說過FreeRTOSConfig.h 配置文件中,有如下3個宏定義。該宏定義避免了修改啟動文件,但有一個地方需要注意一下。就是第3個宏定義“#define xPortSysTickHandler SysTick_Handler”。如果采用的是ST的標准庫沒有問題,但如果采用的是HAL庫,由於HAL庫需要SysTick中斷才能穩定運行,所以不能采用宏定義,而是在stm32f4xx_it.c文件中的SysTick中斷響應函數中調用xPortSysTickHandler函數。
歡迎關注:

