第一節:FreeRTOS (MDK)系統移植 (詳細)
移植總結:
第一步準備素材:如何在官網上下載原始檔
第二步移植程式碼:包括兩步:①從原始碼中提需需要的檔案②將程式碼新增到工程中
第三步修改程式碼:最關鍵的一步使程式碼能夠執行起來。
移植例程程式碼DEMO https://download.csdn.net/download/zennaiheqiao/10661276
第一步:準備素材(原始碼的下載):
(1)首先在FreeRTOS的網站官方可以下載到最新版的FreeRTOS的包。
(2)解壓下載的檔案(瞭解檔案大概內容)
1,下載包根目錄下包含兩個子目錄:FreeRTOS的和FreeRTOS的-PLUS其中,FreeRTOS的加資料夾中包含一些FreeRTOS的+元件和演示例程(元件大都收費),我們不對這個資料夾下的內容多做了解,重點說一下FreeRTOS資料夾.freeRTOS和freeRTOS都是放置原始碼的,加上只是配置更強大了。包含了CLI FAT Trace一些擴充套件例程
2,FreeRTOS資料夾介紹下包含三個子目錄:Demo,License,Source。
其中,演示包含演示例程的工程檔案,原始碼包含實時作業系統原始碼檔案。
其中Demo資料夾包含了各類處理器的Demo程式。其中包括407和103的程式,FreeRTOSConfig.h檔案就是裡面複製出來的。
Source原始碼:包括include和porttable。(包括是一些標頭檔案,porttable是操作硬體的一些封裝。)
(3)提取源中的原始檔(移植用)
FreeRTOS的實時作業系統核心僅包含三個必要檔案,此外還有三個可選檔案.RTOS核心程式碼位於三個原始檔中,分別是tasks.c,queue.c和list.c.這三個檔案位於FreeRTOS作業系統/源目錄下,在同一目錄下還有3個可選的檔案,叫做timers.c,event_groups.c和croutine.c,分別用於軟體定時器,事件組和協程。
Keil資料夾是必須的,但是開啟後發現需要去拷貝RVDS的檔案,“參見-RVDS目錄”,即檔案複用
MemMang是資料夾跟記憶體相關的。
對於支援的處理器架構,RTOS需要一些與處理器架構相關的程式碼。可以稱之為RTOS硬體介面層,它們位於FreeRTOS/Source/Portable/[相應編譯器]/[相應處理器架構]資料夾下。我們這次要移植到Cortex-M3微控制,使用Keil MDK編譯器,所以需要的RTOS硬體介面程式碼位於:FreeRTOS\Source\portable\RVDS\ARM_CM3資料夾下。
MemMang裡面有5中記憶體的管理方式,都可以用各有優缺點後面會研究,選第四種使用。
堆疊分配也是屬於硬體介面層(移植層),在FreeRTOS/Source/portable/MemMang資料夾下具有各種型別的堆疊分配方案。這裡我們使用heap_1.c提供的堆疊分配方案。關於FreeRTOS的記憶體管理,後續《FreeRTOS記憶體管理》一文中會詳細介紹FreeRTOS記憶體管理的特性和用法,《FreeRTOS記憶體管理分析》一文會從原始碼級別分析FreeRTOS記憶體管理的具體實現,這裡不用多糾結,
問價準備齊了。準備幹活FreeRTOS
第二步:移植程式碼
準備移植的檔案
新建一個FreeRTOS資料夾,將Source 資料夾內容全copy過來
portable刪除無關的檔案,資料準備完全。
工程新增移植檔案
在工程中新增如下檔案。並設定路徑。
編譯後
去官方的STM32F103中COPY一個FreeRTOSConfig.h
再次編譯,無錯誤。
修改程式碼
①新建一個FreeRTOS資料夾,將Source 資料夾內容全copy過來
②掛接中斷
注意工程內不能有 SysTick,PendSV 和 SVC 三個系統中斷的使用,因為 FreeRTOS 系統要使用這三個中斷
有的話遮蔽就好了
在Cortex-M3硬體下,FreeRTOS使用SysTick作為系統節拍時鐘,使用SVC和PendSVC進行上下文切換。異常中斷服務程式碼位於…\FreeRTOS\Source\portable\IAR\ARM_CM3\port.c檔案中,FreeRTOS已經為各種構架的CPU寫好了這些程式碼,可以直接拿來用,需要做的是將這些異常中斷的入口地址掛接到啟動程式碼中。在 FreeRTOSConfig.h 新增如下定義:
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#define xPortSysTickHandler SysTick_Handler
編譯後無錯誤。
新增任務:
需要包含標頭檔案 "FreeRTOS.h""task.h" "timers.h" "croutine.h"
/* 包含標頭檔案 ----------------------------------------------------------------*/
#include "stm32f10x.h"
#include "bsp/usart/bsp_debug_usart.h"
#include "includes.h"
/* 私有型別定義 --------------------------------------------------------------*/
/* 私有巨集定義 ----------------------------------------------------------------*/
/* 私有變數 ------------------------------------------------------------------*/
/* 擴充套件變數 ------------------------------------------------------------------*/
/* 私有函式原形 --------------------------------------------------------------*/
/* 函式體 --------------------------------------------------------------------*/
/**
* 函式功能: 主函式.
* 輸入引數: 無
* 返 回 值: 無
* 說 明: 無
*/
//任務優先順序
#define START_TASK_PRIO 1
//任務堆疊大小
#define START_STK_SIZE 128
//任務控制代碼
TaskHandle_t StartTask_Handler;
//任務函式
void start_task(void *pvParameters);
//任務優先順序
#define LED0_TASK_PRIO 2
//任務堆疊大小
#define LED0_STK_SIZE 50
//任務控制代碼
TaskHandle_t LED0Task_Handler;
//任務函式
void led0_task(void *pvParameters);
//任務優先順序
#define LED1_TASK_PRIO 3
//任務堆疊大小
#define LED1_STK_SIZE 50
//任務控制代碼
TaskHandle_t LED1Task_Handler;
//任務函式
void led1_task(void *pvParameters);
int main(void)
{
char str[20];
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設定系統中斷優先順序分組4
DEBUG_USART_Init(); /* 除錯串列埠初始化配置,115200-N-8-1.使能串列埠傳送和接受 */
printf("FreeRTOS DEMO !");
//建立開始任務
xTaskCreate((TaskFunction_t )start_task, //任務函式
(const char* )"start_task", //任務名稱
(uint16_t )START_STK_SIZE, //任務堆疊大小
(void* )NULL, //傳遞給任務函式的引數
(UBaseType_t )START_TASK_PRIO, //任務優先順序
(TaskHandle_t* )&StartTask_Handler); //任務控制代碼
vTaskStartScheduler(); //開啟任務排程
}
//開始任務任務函式
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //進入臨界區
//建立LED0任務
xTaskCreate((TaskFunction_t )led0_task,
(const char* )"led0_task",
(uint16_t )LED0_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED0_TASK_PRIO,
(TaskHandle_t* )&LED0Task_Handler);
//建立LED1任務
xTaskCreate((TaskFunction_t )led1_task,
(const char* )"led1_task",
(uint16_t )LED1_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED1_TASK_PRIO,
(TaskHandle_t* )&LED1Task_Handler);
vTaskDelete(StartTask_Handler); //刪除開始任務
taskEXIT_CRITICAL(); //退出臨界區
}
//LED0任務函式
void led0_task(void *pvParameters)
{
while(1)
{
printf(" Task 1 \r\n");
vTaskDelay(500);
}
}
//LED1任務函式
void led1_task(void *pvParameters)
{
while(1)
{
printf(" Task 2_1 \r\n");
vTaskDelay(200);
printf(" Task 2_2 \r\n");
vTaskDelay(800);
}
}
/******************* (C) COPYRIGHT 2015-2020 硬石嵌入式開發團隊 *****END OF FILE****/
總結:FreeRTOS 移植難度不大
①下載原始碼是在官網上下載的最新版本,移植時候沒有版本限制。
②移植原始碼後,工程少一個FreeRTOSConfig.h檔案這個直接在 DEMO例程裡面複製.
③掛接中斷,程式中有掛接中斷這個環節,這個需要注意。然後新增程式就可以運行了。
後續要搞懂的問題是如何修改嘀嗒定時器,和一些內部執行 的機制。
https://blog.csdn.net/zhzht19861011/article/details/50072033
關於配置節拍
這裡我們使用SysTick定時器作為系統的節拍時鐘,設定每隔10ms產生一次節拍中斷。由於FreeRTOS對移植做了非常多的工作,以至於我們只需要在FreeRTOSConfig.h中配置好以下兩個巨集定義即可:
- configCPU_CLOCK_HZ (/*你的硬體平臺CPU系統時鐘,Fcclk*/)
- configTICK_RATE_HZ ((portTickType)100)
第一個巨集定義CPU系統時鐘,也就是CPU執行時的頻率。第二個巨集定義FreeRTOS的時間片頻率,這裡定義為100,表明RTOS一秒鐘可以切換100次任務,也就是每個時間片為10ms。
在prot.c中,函式vPortSetupTimerInterrupt()設定節拍時鐘該函式根據上面的兩個巨集定義的引數,計算系統定時器定時器的重灌載數值暫存器,然後設定系統定時器定時器的控制及狀態暫存器,設定如下:使用核心時鐘源,使能中斷,使能系統定時器定時器。另外,函式vPortSetupTimerInterrupt()由函式vTaskStartScheduler()呼叫,這個函式用於啟動排程器。