一、獲取FreeRTOS源碼
進入FreeRTOS官網:https://www.freertos.org/a00104.html
點擊Download下載源碼文件。我下載的是“FreeRTOSv10.2.1_191129.exe”,其它版本也可以。
解壓後:
先不用看Labs和Plus兩個文件夾(後面熟悉了之後再看)。直接進入到FreeRTOS目錄:
Demo:一些演示工程。
License:許可。
Source:源碼目錄。我們所需要的文件都在這裏面。
進入到Source目錄:
如圖所示,就是FreeRTOS的源代碼了。將其移植到我們的系統中即可。
二、移植FreeRTOS
在我們的系統工程中創建一個目錄用於存放FreeRTOS源碼。
我創建目錄結構:OS\FreeRTOSv10.2.1\Source。
將以下文件都從剛下載的源碼包中拷貝過來。
Source\*.c (源碼c文件)
Source\include\*.h (源碼頭文件)
Source\portable\GCC\ARM_CM4F\port.c (這裏與硬件相關,請根據自己的硬件平臺選擇。我使用的STM32L4VGT6平臺,編譯器用的ARM GCC,所以選擇了GCC目錄下CM4)
Source\portable\GCC\ARM_CM4F\protmacro.h
Source\portable\MemMang\heap_3.c (具體選用哪個可參考https://www.freertos.org/a00111.html)
特別注意:在選擇port.c時,一定要選擇與硬件對應的目錄,否則即使編譯通過了,也可能會跑不起來。
文件移植完成後,可以嘗試編譯看看,不過編譯過程中可能會報一些錯誤。
常用錯誤是啓動文件中的中斷響應函數需要做一些修改。
三、修改啓動文件
啓動文件中會用到port.c中的三個中斷函數。
vPortSVCHandler
xPortPendSVHandler
xPortSysTickHandler
這裏爲了保持啓動文件的一致性,我們不修改啓動文件,來修改port.c中的函數名:
vPortSVCHandler 修改爲:SVC_Handler
xPortPendSVHandler 修改爲:PendSV_Handler
xPortSysTickHandler 修改爲:SysTick_Handler
這個函數在stm32l4xx_it.c也有定義,所以需要將其註釋掉。
四、修改系統時鐘頻率
根據實際情況修改系統時鐘頻率:configCPU_CLOCK_HZ。
我的系統中使用SystemCoreClock定義的系統頻率。
在FreeRTOSConfig.h中修改如下:
#if 1//def __ICCARM__
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( SystemCoreClock )
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
我這裏通過前面這些步驟的修改,代碼已經順利編譯通過。若還有遇到編譯問題,可逐一排除(不清楚的可百度解決^_^)。
五、寫測試代碼
本例測試GPIOB6以1秒的頻率閃爍。
#include "main.h"
// FreeRTOS head file, add here.
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "list.h"
#include "portable.h"
#include "FreeRTOSConfig.h"
void taskMain(void *pvParameters)
{
GPIO_InitTypeDef GPIO_InitStruct;
pvParameters = pvParameters;
//初始化硬件
HAL_Init();
//打開GPIOB的時鐘
__HAL_RCC_GPIOB_CLK_ENABLE();
//初始化GPIOB6爲輸出
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Pin = GPIO_PIN_6;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
while(1)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_6);
vTaskDelay(1000/portTICK_RATE_MS);
}
}
int main(void)
{
//創建任務taskMain
xTaskCreate( taskMain, "taskMain", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+2, NULL );
// 啓動任務調度
vTaskStartScheduler();
return 0;
}
比較幸運……
編譯後直接跑起來了……