FreeRTOS学习记录(安富莱FreeRTOS教程摘录)
FreeRTOS學習資料:
安富萊論壇FreeRTOS教程
FreeRTOS源碼下載鏈接
第1章 為什么選用FreeRTOS
1.1 FreeRTOS優勢
FreeRTOS優勢 最大的優勢就是開源免費,商業使用的話不需要用戶公開源代碼,也不存在任何版權問題,是當前小型嵌入式操作系統市場使用率最高的。 去年的全球嵌入式市場分析報告中,FreeRTOS 占據了 20%。
1.2 移植的難易程度
FreeRTOS 的移植比較簡單,只需要用戶添加需要的源碼文件,不需要做任何的底層工作,再添加三
個宏定義即可,詳情可以看第 5 章 FreeRTOS 操作系統移植。
1.3 上手難易程度
作為開源免費的 RTOS,官方配套的手冊在 RTOS 的基礎知識說明、API 函數說明及其舉例方面做的
都非常好,用戶上手比較容易。隨著后面章節的學習,大家會體會到這一點。
第2章 嵌入式實時操作系統介紹
2.1 嵌入式系統定義
一般定義
以應用為中心、以計算機技術為基礎、軟件硬件可裁剪、功能、可靠性、成本、體積、功耗嚴格要求
的專用計算機系統。
2.2 實時和分時操作系統區別
按對外部事件的響應能力來分類,嵌入式操作系統有分時操作系統和實時操作系統。
- 如果操作系統能使計算機系統及時的響應外部事件請求,并能控制所有實時設備和實時任務協調運行,且能在一個規定的時間內完成對事件的處理,那么這種系統就稱為實時操作系統(RTOS)。
- 按時間的正確程度來分,實時操作系統又分為硬件的實時操作系統和軟件的實時操作系統。系統必須在極其嚴格的時間內完成的任務叫做硬件的實時操作系統,如果不是很嚴格的話就是軟件的實時操作系統。
- 分時操作系統就是按時間片輪轉完成各個任務。
第7章 FreeRTOSConfig 配置文件詳解
- 7.2.7 configMINIMAL_STACK_SIZE
此參數用于定義空閑任務的??臻g大小,單位字,即 4 字節。 - 7.2.8 configTOTAL_HEAP_SIZE
定義堆大小,FreeRTOS 內核,用戶動態內存申請,任務棧,任務創建,信號量創建,消息隊列創建等都需要用這個空間。
第10章 FreeRTOS 任務管理
10.1 單任務系統
學習多任務系統之前,我們先來回顧下單任務系統的編程框架,即裸機時的編程框架。裸機編程主要是采用超級循環(super-loops)系統,又稱前后臺系統。應用程序是一個無限的循環,循環中調用相應的函數完成相應的操作,這部分可以看做后臺行為;中斷服務程序處理異步事件,這部分可以看做是前臺行為。后臺也可以叫做任務級,前臺也叫作中斷級。
對于前后臺系統的編程思路主要有以下兩種方式:
10.1.1 查詢方式
10.1.2 中斷方式
對于查詢方式無法有效執行緊急任務的情況,采用中斷方式就有效地解決了這個問題,下面是中斷方式簡單的流程圖
采用中斷和查詢結合的方式可以解決大部分裸機應用,但隨著工程的復雜,裸機方式的缺點就暴露出來了:
1)必須在中斷(ISR)內處理時間關鍵運算:
- ISR 函數變得非常復雜,并且需要很長執行時間。
- ISR 嵌套可能產生不可預測的執行時間和堆棧需求。
2)超級循環和 ISR 之間的數據交換是通過全局共享變量進行的:
- 應用程序的程序員必須確保數據一致性。
3)超級循環可以與系統計時器輕松同步,但:
- 如果系統需要多種不同的周期時間,則會很難實現。
- 超過超級循環周期的耗時函數需要做拆分。
- 增加軟件開銷,應用程序難以理解。
4)超級循環使得應用程序變得非常復雜,因此難以擴展:
- 一個簡單的更改就可能產生不可預測的副作用,對這種副作用進行分析非常耗時。
- 超級循環概念的這些缺點可以通過使用實時操作系統 (RTOS) 來解決。
10.2 多任務系統
針對這些情況,使用多任務系統就可以解決這些問題了。下面是一個多任務系統的流程圖:
多任務系統或者說 RTOS 的實現,重點就在這個調度器上,而調度器的作用就是使用相關的調度算法來決定當前需要執行的任務。如上圖所示的那樣,創建了任務并完成 OS 初始化后,就可以通過調度器來決定任務 A,任務 B 和任務 C 的運行,從而實現多任務系統。另外需要初學者注意的是,這里所說的多任務系統同一時刻只能有一個任務可以運行,只是通過調度器的決策,看起來像所有任務同時運行一樣。
FreeRTOS 就是一款支持多任務運行的實時操作系統,具有時間片,搶占式和合作式三種調度方法。
通過 FreeRTOS 實時操作系統可以將程序函數分成獨立的任務,并為其提供合理的調度方式。
10.3 FreeRTOS 的任務棧設置
不管是裸機編程還是 RTOS 編程,棧的分配大小都非常重要。局部變量,函數調用時的現場保護和返回地址,函數的形參,進入中斷函數前和中斷嵌套等都需要??臻g,棧空間定義小了會造成系統崩潰。
不同于裸機編程,在 RTOS 下,每個任務都有自己的棧空間。對于 FreeRTOS 來說,任務??臻g是在任務創建的時候從FreeRTOSConfig.h 文件中定義的 heap 空間中申請的#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) )
具體每個任務的棧大小是在創建 FreeRTOS 的任務時進行設置的
10.4 FreeRTOS 的系統棧設置
任務棧不使用任務的??臻g,哪里使用這里的??臻g呢?答案就在中斷函數和中斷嵌套。
- 由于 Cortex-M3 和 M4 內核具有雙堆棧指針,MSP 主堆棧指針和 PSP 進程堆棧指針,或者叫 PSP任務堆棧指針也是可以的。在 FreeRTOS 操作系統中**,主堆棧指針 MSP 是給系統??臻g使用的,進程堆棧指針 PSP 是給任務棧使用的**。也就是說,在 FreeRTOS 任務中,所有棧空間的使用都是通過
PSP 指針進行指向的。一旦進入了中斷函數以及可能發生的中斷嵌套都是用的 MSP 指針。這個知識點要記住它,當前可以不知道這是為什么,但是一定要記住。 - 實際應用中系統棧空間分配多大,主要是看可能發生的中斷嵌套層數,下面我們就按照最壞執行情況進行考慮,所有的寄存器都需要入棧,此時分為兩種情況:
64 字節
對于 Cortex-M3 內核和未使用 FPU(浮點運算單元)功能的 Cortex-M4 內核在發生中斷時需要將 16 個通用寄存器全部入棧,每個寄存器占用 4 個字節,也就是 16*4 = 64 字節的空間。
可能發生幾次中斷嵌套就是要 64 乘以幾即可。當然,這種是最壞執行情況,也就是所有的寄存器都入棧。
(注:任務執行的過程中發生中斷的話,有 8 個寄存器是自動入棧的,這個棧是任務棧,進入中斷以后其余寄存器入棧以及發生中斷嵌套都是用的系統棧)
200 字節
對于具有 FPU(浮點運算單元)功能的 Cortex-M4 內核,如果在任務中進行了浮點運算,那么在發生中斷的時候除了 16 個通用寄存器需要入棧,還有 34 個浮點寄存器也是要入棧的,也就是(16+34)*4 = 200 字節的空間。當然,這種是最壞執行情況,也就是所有的寄存器都入棧。
(注:任務執行的過程中發送中斷的話,有 8 個通用寄存器和 18 個浮點寄存器是自動入棧的,這個棧是任務棧,進入中斷以后其余通用寄存器和浮點寄存器入棧以及發生中斷嵌套都是用的系統棧
10.5FreeRTOS 的任務狀態
FreeRTOS 的運行支持以下四種狀態:
? Running—運行態
當任務處于實際運行狀態被稱之為運行態,即 CPU 的使用權被這個任務占用。
? Ready—就緒態
處于就緒態的任務是指那些能夠運行(沒有被阻塞和掛起),但是當前沒有運行的任務,因為同優先
級或更高優先級的任務正在運行。
? Blocked—阻塞態
由于等待信號量,消息隊列,事件標志組等而處于的狀態被稱之為阻塞態,另外任務調用延遲函數也
會處于阻塞態。
? Suspended—掛起態
類似阻塞態,通過調用函數 vTaskSuspend()對指定任務進行掛起,掛起后這個任務將不被執行,只
有調用函數 xTaskResume()才可以將這個任務從掛起態恢復。
10.6FreeRTOS 啟動
使用如下函數即可啟動 FreeRTOS:
? vTaskStartScheduler()
10.7FreeRTOS 的任務創建
使用如下函數可以實現 FreeRTOS 的任務創建:
? xTaskCreate()
10.8FreeRTOS 的任務刪除
使用如下函數可以實現 FreeRTOS 的任務刪除:
? vTaskDelete()
10.9FreeRTOS 的任務掛起
使用如下函數可以實現 FreeRTOS 的任務掛起:
? xTaskSuspend()
10.10 FreeRTOS 的任務恢復
使用如下函數可以實現 FreeRTOS 的任務恢復:
? xTaskResume()
10.11 FreeRTOS 的任務恢復(中斷方式)
使用如下函數可以實現 FreeRTOS 的任務恢復(中斷方式):
? xTaskResumeFromISR()
10.12 FreeRTOS 的空閑任務
幾乎所有的小型 RTOS 中都會有一個空閑任務,空閑任務屬于系統任務,是必須要執行的,用戶程
序不能將其關閉。不光小型系統中有空閑任務,大型的系統里面也有的,比如 WIN7
第11章 FreeRTOS 任務棧大小確定及其溢出檢測
11.1任務棧大小的確定
在基于 RTOS 的應用設計中,每個任務都需要自己的??臻g,應用不同,每個任務需要的棧大小也是
不同的。將如下的幾個選項簡單的累加就可以得到一個粗略的棧大小:
- 函數局部變量。
- **函數形參,一般情況下函數的形參是直接使用的 CPU 寄存器,不需要使用??臻g,但是這個函數中如果還嵌套了一個函數的話,這個存儲了函數形參的 CPU 寄存器內容是要入棧的。**所以建議大家也把這部分算在棧大小中。
- 函數返回地址,針對 M3 和 M4 內核的 MCU,一般函數的返回地址是專門保存到 LR(Link Register)寄存器里面的,如果這個函數里面還調用了一個函數的話,這個存儲了函數返回地址的 LR 寄存器內容是要入棧的。所以建議大家也把這部分算在棧大小中。
- 函數內部的狀態保存操作也需要額外的??臻g。
- M3 內核的 MCU 有 8 個寄存器是自動入棧的,這個棧是任務棧,進入中斷以后其余寄存器入棧以及發生中斷嵌套都是用的系統棧。
- M4 內核的 MCU 有 8 個通用寄存器和 18 個浮點寄存器是自動入棧的,這個棧是任務棧,進入中斷以后其余通用寄存器和浮點寄存器入棧以及發生中斷嵌套都是用的系統棧。
- 進入中斷以后使用的局部變量以及可能發生的中斷嵌套都是用的系統棧,這點要注意。
函數棧大小確定
函數的棧大小計算起來是比較麻煩的,那么有沒有簡單的辦法來計算呢?有的,一般 IDE 開發環境都有這樣的功能,比如 MDK 會生成一個 htm 文件,通過這個文件用戶可以知道每個被調用函數的最大棧需求以及各個函數之間的調用關系。但是 MDK 無法確定通過函數指針實現函數調用時的棧需求。另外,發生中斷或中斷嵌套時的現場保護需要的棧空間也不會統計。
11.2什么是棧溢出
略
11.3FreeRTOS 的棧溢出檢測機制
FreeRTOS 提供了兩種棧溢出檢測機制,這兩種檢測都是在任務切換時才會進行:
- 方法一
在任務切換時檢測任務棧指針是否過界了,如果過界了,在任務切換的時候會觸發棧溢出鉤子函數。
void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ); - 方法二
任務創建的時候將任務棧所有數據初始化為 0xa5,任務切換時進行任務棧檢測的時候會檢測末尾的 16 個字節是否都是 0xa5,通過這種方式來檢測任務棧是否溢出了。
使用方法二需要用戶在 FreeRTOSConfig.h 文件中配置如下宏定義:
#define configCHECK_FOR_STACK_OVERFLOW 2
第12章 FreeRTOS 中斷優先級配置(重要)
12.1NVIC 基礎知識
NVIC 的全稱是 Nested vectored interrupt controller,即嵌套向量中斷控制器。
對于 M3 和 M4 內核的 MCU,每個中斷的優先級都是用寄存器中的 8 位來設置的。8 位的話就可以設置 2^8 = 256 級中斷,實際中用不了這么多,所以芯片廠商根據自己生產的芯片做出了調整。比如 ST的 STM32F1xx 和 F4xx 只使用了這個 8 位中的高四位[7:4],低四位取零,這樣 2^4=16,只能表示 16級中斷嵌套。
12.2使用 FreeRTOS 時如何配置外設 NVIC
強烈推薦用戶將 Cortex-M3 內核的 STM32F103 和 Cortex-M4 內核的 STM32F407 以及STM32F429 的 NVIC 優先級分組設置為 4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);這樣中斷優先級的管理將非常方便。這個也是官方強烈建議的。此函數在 bsp_Init 中第一個被調用
第13章 FreeRTOS 任務優先級修改及其分配方案
13.3中斷優先級和任務優先級區別
部分初學者也容易在這兩個概念上面出現問題。簡單的說,這兩個之間沒有任何關系,不管中斷的優先級是多少,中斷的優先級永遠高于任何任務的優先級,即任務在執行的過程中,中斷來了就開始執行中斷服務程序。
另外對于 STM32F103,F407 和 F429 來說,中斷優先級的數值越小,優先級越高。而 FreeRTOS的任務優先級是,任務優先級數值越小,任務優先級越低。
第14章 任務調度—搶占式,時間片和合作式
14.2FreeRTOS 支持的調度方式
FreeRTOS 操作系統支持三種調度方式:搶占式調度,時間片調度和合作式調度。實際應用主要是搶占式調度和時間片調度,合作式調度用到的很少。
- 搶占式調度
每個任務都有不同的優先級,任務會一直運行直到被高優先級任務搶占或者遇到阻塞式的 API 函數,比如 vTaskDelay。 - 時間片調度
每個任務都有相同的優先級,任務會運行固定的時間片個數或者遇到阻塞式的 API 函數,比如vTaskDelay,才會執行同優先級任務之間的任務切換。
第15章 FreeRTOS 臨界段和開關中斷
15.1臨界段
代碼的臨界段也稱為臨界區,一旦這部分代碼開始執行,則不允許任何中斷打斷。為確保臨界段代碼的執行不被中斷,在進入臨界段之前須關中斷,而臨界段代碼執行完畢后,要立即開中斷。
FreeRTOS 源碼中就有多處臨界段的處理,跟 FreeRTOS 一樣,uCOS-II 和 uCOS-III 源碼中都是有臨界段的,而 RTX 的源碼中不存在臨界段。另外,除了 FreeRTOS 操作系統源碼所帶的臨界段以外,用戶寫應用的時候也有臨界段的問題,比如以下兩種:
- 讀取或者修改變量(特別是用于任務間通信的全局變量)的代碼,一般來說這是最常見的臨界代碼。
- 調用公共函數的代碼,特別是不可重入的函數,如果多個任務都訪問這個函數,結果是可想而知的。
總之,對于臨界段要做到執行時間越短越好,否則會影響系統的實時性。
* 一個可重入的函數簡單來說就是可以被中斷的函數,也就是說,可以在這個函數執行的任何時刻中斷它,轉入OS調度下去執行另外一段代碼,而返回控制時不會出現什么錯誤;而不可重入的函數由于使用了一些系統資源,比如全局變量區,中斷向量表等,所以它如果被中斷的話,可能會出現問題,這類函數是不能運行在多任務環境下的。
FreeRTOS 任務代碼中臨界段的進入和退出主要是通過操作寄存器 basepri 實現的。進入臨界段前操作寄存器 basepri 關閉了所有小于等于宏定義 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY所定義的中斷優先級,這樣
**臨界段代碼就不會被中斷干擾到,而且實現任務切換功能的 PendSV 中斷和滴答定時器中斷是最低優先級中斷,所以此任務在執行臨界段代碼期間是不會被其它高優先級任務打斷的。**退出臨界段時重新操作 basepri 寄存器,即打開被關閉的中斷(這里我們不考慮不受 FreeRTOS 管理的更高優先級中斷)。FreeRTOS 進入和退出臨界段的函數如下:
上面這兩個函數是供用戶調用的,其中函數 taskENTER_CRITICAL 是進入臨界段,函數taskEXIT_CRITICAL 是退出臨界段。進一步跟蹤宏定義的實現如下:
#define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical()第16章 FreeRTOS 調度鎖,任務鎖和中斷鎖
16.1調度鎖
調度鎖就是 RTOS 提供的調度器開關函數,如果某個任務調用了調度鎖開關函數,處于調度鎖開和調度鎖關之間的代碼在執行期間是不會被高優先級的任務搶占的,即任務調度被禁止。這一點要跟臨界段的作用區分開,調度鎖只是禁止了任務調度,并沒有關閉任何中斷,中斷還是正常執行的。而臨界段進行了開關中斷操作。
16.2中斷鎖
中斷鎖就是 RTOS 提供的開關中斷函數,FreeRTOS 沒有專門的中斷鎖函數,使用 15.3 小節里面介紹的中斷服務程序臨界段處理函數就可以實現同樣效果。
16.3任務鎖
簡單的說,為了防止當前任務的執行被其它高優先級的任務打斷而提供的鎖機制就是任務鎖。FreeRTOS 也沒有專門的任務鎖函數,但是使用 FreeRTOS 現有的功能有兩種實現方法:
- 通過給調度器加鎖實現
- 通過關閉任務切換中斷 PendSV 和系統時鐘節拍中斷 Systick
第17章 FreeRTOS 系統時鐘節拍和時間管理
17.1FreeRTOS 的時鐘節拍
任何操作系統都需要提供一個時鐘節拍,以供系統處理諸如延時、超時等與時間相關的事件。
時鐘節拍是特定的周期性中斷,這個中斷可以看做是系統心跳。中斷之間的時間間隔取決于不同的應
用,一般是 1ms – 100ms。時鐘的節拍中斷使得內核可以將任務延遲若干個時鐘節拍,以及當任務等待事件發生時,提供等待超時等依據。時鐘節拍率越快,系統的額外開銷就越大。
對于 Cortex-M3 內核的 STM32F103 和 Cortex-M4 內核的 STM32F407 以及 F429,教程配套的例
子都是用滴答定時器來實現系統時鐘節拍的。
滴答定時器 Systick
SysTick 定時器被捆綁在 NVIC 中,用于產生 SysTick 異常(異常號:15),滴答定時器是一個 24 位
的遞減計數器,支持中斷。使用比較簡單,專門用于給操作系統提供時鐘節拍。
FreeRTOS 的系統時鐘節拍可以在配置文件 FreeRTOSConfig.h 里面設置:
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
如上所示的宏定義配置表示系統時鐘節拍是 1KHz,即 1ms。
17.2.1時間延遲
FreeRTOS 中的時間延遲函數主要有以下兩個作用:
- 為周期性執行的任務提供延遲。
- 對于搶占式調度器,讓高優先級任務可以通過時間延遲函數釋放 CPU 使用權,從而讓低優先級任務
可以得到執行。
17.2.2FreeRTOS 的時間相關函數
FreeRTOS 時間相關的函數主要有以下 4 個:
- vTaskDelay () //函數 vTaskDelay 用于任務的延遲。
- vTaskDelayUntil () //函數 vTaskDelayUntil 用于周期性延遲。
- xTaskGetTickCount() //函數 xTaskGetTickCount 用于獲取系統當前運行的時鐘節拍數。
- xTaskGetTickCountFromISR() //函數 xTaskGetTickCountFromISR 用于獲取系統當前運行的時鐘節拍數。此函數用于在中斷服務程序里面調用,如果在任務里面調用的話,需要使用函數xTaskGetTickCount,這兩個函數切不可混用。
第18章 FreeRTOS 事件標志組
18.1事件標志組
18.1.1為什么要使用事件標志
事件標志組是實現多任務同步的有效機制之一。也許有不理解的初學者會問采用事件標志組多麻煩,
搞個全局變量不是更簡單?其實不然,在裸機編程時,使用全局變量的確比較方便,但是在加上 RTOS 后就是另一種情況了。使用全局變量相比事件標志組主要有如下三個問題:
- 使用事件標志組可以讓 RTOS 內核有效地管理任務,而全局變量是無法做到的,任務的超時等機制需要用戶自己去實現。
- 使用了全局變量就要防止多任務的訪問沖突,而使用事件標志組則處理好了這個問題,用戶無需擔心。
- 使用事件標志組可以有效地解決中斷服務程序和任務之間的同步問題。
總結
以上是生活随笔為你收集整理的FreeRTOS学习记录(安富莱FreeRTOS教程摘录)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c 程序设计语言简单列子,C语言程序设计
- 下一篇: FreeRTOS使用教程(配合CubeM