標題: FreeRTOS移植到STM32F103步驟與注意事項 [打印本頁]

作者: zhongd    時間: 2018-1-29 01:49
標題: FreeRTOS移植到STM32F103步驟與注意事項
前言:
由于之前聽過太多人抱怨移植FreeRTOS到STM32有各種各樣的問題,小燈經(jīng)過一年多對FreeRTOS的研究并在公司產(chǎn)品中應(yīng)用,多少有些心得,接下來就由小燈以最新版的FreeRTOS為例一步一步移植到STM32F103上,并提醒大家某些需要注意的事項。本文檔為非正式技術(shù)文檔,故排版會有些凌亂,希望大家能提供寶貴意見以供小燈參考改進。
下面先以IAR移植為例,說明移植過程中的諸多注意事項,最后再以MDK移植時不再重復說明,所以還是建議大家先花些時間看IAR的移植過程,哪怕你不使用IAR,最好也注意下那一大堆注意事項!


一、從官網(wǎng)下載最新版的FreeRTOS源碼
下面的網(wǎng)址是官方最新源碼的下載地址:
https://sourceforge.net/projects/freertos/files/latest/download?source=files
目前官方提供的最新版本是v9.0.0, FreeRTOS源碼在解壓目錄下的路徑為
FreeRTOS_V9.0.0rc2FreeRTOSSource


FreeRTOS組織為了搶用戶也是拼了命的,不信你打開Demo文件夾看看,里面提供了FreeRTOS在各種單片機上已經(jīng)移植好的工程,如果建工程時遇到什么問題,可以參考下這些Demo。
不過小燈現(xiàn)在著重于自己動手移植FreeRTOS,考慮到原子哥@正點原子的用戶比較多,絕大多數(shù)習慣了使用MDK來開發(fā)STM32,因此小燈分別以IAR和MDK兩種使用比較廣泛的開發(fā)環(huán)境來移植FreeRTOS。說到IAR和MDK,不得不提的是小燈自從用了IAR之后就果斷放棄了MDK,相信很多人有這個經(jīng)歷,哈哈!

在開始移植FreeRTOS之前,先介紹下FreeRTOS的源碼:

FreeRTOS的源碼比較少,源文件也遠沒有UCOS多,不過麻雀雖小五臟俱全,F(xiàn)reeRTOS的短小精悍也是最令小燈著迷的,雖然缺少了很多組成部分,例如GUI、網(wǎng)絡(luò)協(xié)議棧、文件系統(tǒng)等,不過這些統(tǒng)統(tǒng)都不是問題,因為完全可以移植第三方的組件!
一不小心牛逼又吹大了,哈哈!回歸正題,F(xiàn)reeRTOS的源碼核心部分是tasks.c和list.c,其余的幾個文件功能都是可選的,例如軟件定時器、隊列、協(xié)程等等,小燈就不介紹了,有興趣的話可以到官網(wǎng)上看介紹。include文件夾里面的文件是操作系統(tǒng)相關(guān)的頭文件,而portable這個文件夾有些奇葩,先看看里面有啥:

這里的文件幾乎都是與平臺相關(guān)的,如果你要刪掉這里的文件時就必須小心了,因為不是所有文件都能刪除的。
注意文件夾MemMang,里面存放的是FreeRTOS自帶的內(nèi)存管理方案的源文件:

關(guān)于內(nèi)存管理方案的選擇,小燈以后再跟大家討論,現(xiàn)在只需要知道這些文件不能刪就好。

接下來看看IAR文件夾的內(nèi)容,里面都是跟單片機底層相關(guān)的,由于我們以STM32F103為例,因此只需要保留ARM_CM3文件夾即可,其余可選擇性刪除。ARM_CM3文件夾里只有幾個文件,這幾個文件是操作系統(tǒng)最最底層的部分:


接下來再看看Keil文件夾的內(nèi)容,里面只有一個文件,文件提示See-also-the-RVDS-directory,意思是讓我們參照RVDS目錄下的文件。其實我們以MDK建工程時,就是拿RVDS目錄下的文件來替代的,因此我們應(yīng)該把RVDS目錄下的文件拷貝到Keil目錄下,跟上面IAR文件夾一樣我們只拷貝ARM_CM3文件夾即可:


到這里我們可以把其他無用的文件統(tǒng)統(tǒng)刪掉了,portable目錄下只保留下面幾個文件夾的文件即可:

現(xiàn)在已經(jīng)把源碼整理好了,接下來就開始移植工作吧!


二、IAR下移植FreeRTOS
事先說明下,小燈使用的IAR版本是

關(guān)于IAR下如何創(chuàng)建STM32基礎(chǔ)工程,小燈就偷下懶不介紹了,這入門級的知識還是交給賣開發(fā)板的人來傳播吧,小燈就以自己平常用的簡單工程為例:

工程當中只有一個LED.c是小燈額外添加的,小燈一直停留在跑燈的水平,習慣用LED來觀察現(xiàn)象,希望各位大神莫怪。工程源碼結(jié)構(gòu)如下:

其中FreeRTOS文件夾下就是FreeRTOS的源碼:


接下來在工程里面添加FreeRTOS文件:

文件清單如下:
FreeRTOS        asks.c
FreeRTOSlist.c
FreeRTOSportableIARARM_CM3port.c
FreeRTOSportableIARARM_CM3portasm.s
FreeRTOSportableMemMangheap_4.c

這時有人可要問為何沒有把FreeRTOS的所有文件都添加進去,原因我上面提過了,F(xiàn)reeRTOS的核心部分是tasks.c和list.c,其余的幾個文件是可選部分,在此小燈就先不添加這些可選部分以簡化我們的工程。小燈建議大家使用內(nèi)存管理的方案四heap_4.c,因為該方案具有內(nèi)存塊碎片合并功能,比heap_2.c的最優(yōu)內(nèi)存塊分配方案要穩(wěn)定很多,這是小燈經(jīng)過很長時間測試對比出來的,公司的產(chǎn)品也是一直使用heap_4.c,穩(wěn)定性無懈可擊!

接下來非常重要的一步就是添加頭文件路徑:

頭文件路徑如下:
$PROJ_DIR$..SourceFreeRTOSinclude
$PROJ_DIR$..SourceFreeRTOSportableIARARM_CM3

好了這時我們可以嘗試編譯下整個工程了,編譯結(jié)果提示缺少了個頭文件:

FreeRTOS組織也真是奇葩,居然連這么重要的文件都不提供在源碼里面!!!前面提醒過大家,新建工程時碰到問題一定要參考官方提供的Demo,既然Demo是一堆成品的工程,那么里面絕對有我們所需的這個FreeRTOSConfig.h
我們就選擇打開DemoCORTEX_STM32F103_IAR下的這個工程吧,果不其然里面真的有我們需要的這個頭文件:


把這文件放哪里好呢,這是一直糾結(jié)小燈的問題,官方直接把這文件放在工程目錄下,但這么重要的配置文件這么隨便放似乎不太好吧。在小燈看來,這個文件的重要性和打開的概率絕不比FreeRTOS內(nèi)核文件低,所以還是把它放在源碼里面比較合理:

在C/C++ Compiler下添加頭文件路徑
$PROJ_DIR$..SourceFreeRTOS

還有一個地方一定要十分注意,因為操作系統(tǒng)的最最底層的幾個文件也需要用到FreeRTOSConfig.h頭文件,而底層文件是用匯編來寫的,因此必須在Assembler下添加FreeRTOSConfig.h頭文件路徑:


好了再編譯一次:

0個錯誤0個警告,程序員最歡喜的莫過于看見這個結(jié)果了,哈哈!

在編寫系統(tǒng)任務(wù)前,有必要對配置文件FreeRTOSConfig.h進行檢查。FreeRTOSConfig.h里面幾乎都是一些宏定義,關(guān)于這些宏定義的具體用法,可以在官網(wǎng)上查閱:http://www.freertos.org/a00110.html
小燈只以其中幾個比較重要的參數(shù)作特別說明,下面以小燈修改過的FreeRTOSConfig.h為例作為說明:

(1)定義系統(tǒng)底層相關(guān)的函數(shù)

其中SVC中斷時操作系統(tǒng)啟動時進入的中斷,而PendSV中斷手動切換任務(wù)時進入的中斷,SysTick中斷不用我多說了,@正點原子的基礎(chǔ)例程幾乎都使用這個定時器定時,在這里SysTick是作為操作系統(tǒng)的心臟。由于FreeRTOS對這幾個中斷的名稱做了自己的定義,因此必須要重定義這幾個函數(shù)才能正常進入中斷,但這么做又會跟ST提供的stm32f10x_it.c文件當中定義的中斷相沖突,因此必須將stm32f10x_it.c下對應(yīng)的幾個中斷服務(wù)函數(shù)屏蔽掉,否則編譯會提示函數(shù)重定義:

(2)修改系統(tǒng)可屏蔽的中斷優(yōu)先級閾值
FreeRTOS提供的可屏蔽中斷優(yōu)先級閾值是191,對應(yīng)的十六進制數(shù)是0xBF:
#define configMAX_SYSCALL_INTERRUPT_PRIORITY         191
由于STM32F103的優(yōu)先級分組只有4個位,而CM3的優(yōu)先級是以MSB對齊的,也就是說STM32F103的優(yōu)先級寄存器只有最高4位有效,低四位是無效的。當操作系統(tǒng)進入臨界區(qū)時,會把上面的可屏蔽中斷優(yōu)先級閾值寫入BASEPRI寄存器以屏蔽部分中斷:

因此當進入臨界區(qū)時,優(yōu)先級對應(yīng)0xB~0xF的中斷均被屏蔽,而優(yōu)先級處于0xB前面的中斷不受影響。這個跟CM0有區(qū)別,也是最值得注意的地方。
上述的基礎(chǔ)知識不是小燈要重點提的,對CM3的優(yōu)先級不熟悉的朋友建議查閱《Cortex-M3權(quán)威指南》,接下來才是小燈要重點提的。由于使用@正點原子的開發(fā)板的用戶比較多,很多人直接把FreeRTOS移植到原子哥的工程下,然后出現(xiàn)了各種各樣的詭異問題,一直無解。其中一個非常嚴重的問題就是小燈上面提及到的中斷屏蔽的問題,下面小燈就這個問題進行一個簡單的分析,先貼上@正點原子的部分代碼:

這是原子哥最常用的中斷優(yōu)先級分組方式,采用分組方式2,2位搶占優(yōu)先級2位亞優(yōu)先級。但是在移植FreeRTOS時必須要修改成優(yōu)先級分組方式4:

把STM32的優(yōu)先級分組的4個位均設(shè)成搶占優(yōu)先級,也就是說完全放棄亞優(yōu)先級。為何要這么設(shè)置?其實這得怪FreeRTOS機構(gòu)里面被驢踢過的逗逼,這些逗逼為了自己省事,直接默認不使用亞優(yōu)先級,下面讓大家見識下這群逗逼的解釋:

不過站在他們的角度來思考,其實我們也應(yīng)該給他們那么一丁點兒理解,畢竟他們采取了一個比較簡單的方法來獲取不同廠商的單片機的有效優(yōu)先級位數(shù),算法是通過對優(yōu)先級寄存器組的某一個寄存器寫入0xFF,然后再讀出來看實際上有多少位寫入成功,然后根據(jù)實際的有效位數(shù)來重設(shè)優(yōu)先級分組寄存器的分組方式(上面提到的分組方式4)。有興趣的可以研究下他們的算法,代碼截圖在下面:


不知不覺越扯越遠了,回歸正題,到底為何要重設(shè)可屏蔽的中斷優(yōu)先級閾值,我們重新把思路理一下。根據(jù)STM32的中斷優(yōu)先級的設(shè)計,只有高4位有效,還有FreeRTOS默認將4個優(yōu)先級位均劃分為搶占優(yōu)先級。由于FreeRTOS官方提供的中斷優(yōu)先級閾值是191(對應(yīng)實際的0xB),也就是11~15的優(yōu)先級均可被操作系統(tǒng)屏蔽。但我們實際使用時設(shè)置的中斷優(yōu)先級一般不會使用到11打后的,例如@正點原子的基礎(chǔ)例程里面使用最多的1~3,所以我們必須要修改這個值,否則我們要重新修改所有底層驅(qū)動的優(yōu)先級。
那么怎么修改比較合理?這個就得看實際應(yīng)用需要了,其實使用宏configMAX_SYSCALL_INTERRUPT_PRIORITY來屏蔽部分中斷是比較合理的,相對于CM3,CM0沒有中斷優(yōu)先級閾值寄存器,只能簡單粗暴的開啟全局中斷和關(guān)閉全局中斷。操作系統(tǒng)在執(zhí)行十分重要的工作時一般不能打斷這個工作,尤其是這時在中斷里面調(diào)用了操作系統(tǒng)的API函數(shù),這都會嚴重影響系統(tǒng)的穩(wěn)定性。小燈對configMAX_SYSCALL_INTERRUPT_PRIORITY的理解是,這個數(shù)值打后的所有中斷均劃入操作系統(tǒng)管理,而這個數(shù)值打前的中斷則歸由用戶自己管理,但用戶必須十分小心地處理這些中斷,用戶可以使用這些中斷來處理一些跟操作系統(tǒng)無關(guān)的工作。這純屬個人理解,如有錯誤之處還請大家指出,小燈會盡快修改!

分析完configMAX_SYSCALL_INTERRUPT_PRIORITY的作用后,下面小燈提供一個參考值:

由于優(yōu)先級寄存器是高四位有效,因此上述的屏蔽閾值實際上是0x1,也就是說優(yōu)先級在1~15之間的中斷均可被操作系統(tǒng)屏蔽,而優(yōu)先級0歸由用戶自己控制。值得注意的是configMAX_SYSCALL_INTERRUPT_PRIORITY的高四位絕對不能設(shè)為0,下面小燈給出0x0F的仿真結(jié)果:

當configMAX_SYSCALL_INTERRUPT_PRIORITY設(shè)為0x0F時系統(tǒng)在進入臨界區(qū)時BASEPRI寄存器的值一直為0,沒有更新。下面給出0x1F時的仿真結(jié)果:


當configMAX_SYSCALL_INTERRUPT_PRIORITY設(shè)為0x1F時系統(tǒng)在進入臨界區(qū)時BASEPRI寄存器的值更新為0x10,中斷優(yōu)先級閾值寄存器起作用了!原因在上面也解釋過了,因為STM32F103的優(yōu)先級寄存器是高四位有效的,對應(yīng)的BASEPRI也是高四位能夠?qū)懭攵退奈粺o法寫入,而BASEPRI有一個特點——對它寫0會取消屏蔽所有中斷(相當于禁用了該寄存器),因此BASEPRI的高四位一定不能設(shè)為0,否則不會屏蔽任何中斷,這點注意下就好了。
(3)添加參數(shù)檢測功能

該參數(shù)檢測功能是官方提供的一個參考,很多人為了省事不使用參數(shù)檢測,但小燈勸誡各位千萬不能干這蠢事!說了半天想必大家也累了,那么接下來就開始我們跑燈之旅吧!

下面就以LED創(chuàng)建兩個閃爍任務(wù):


至于LED底層驅(qū)動代碼在工程里面提供了,在這不詳細解釋,讀者可自行修改。在main函數(shù)里首先設(shè)置中斷優(yōu)先級分組方式4,然后創(chuàng)建2個LED任務(wù),堆棧深度40個字(160字節(jié))即可,然后啟動任務(wù)調(diào)度器,整個操作系統(tǒng)就能夠跑起來了。

重新編譯下工程,這時會提示有錯誤:



接下來我們需要屏蔽這些編譯錯誤:

在C/C++ Compiler的Diagostics里面添加Pa082,Pe191,Pe167
重新編譯一次:

編譯通過,下載到板子上后就能夠看到2個LED按照一定的頻率閃爍了!


三、MDK下移植FreeRTOS
由于在上面IAR移植過程中已經(jīng)把需要注意的事項詳細,再次就不累述了,只給出移植過程。小燈使用的MDK版本是:

至于MDK工程的新建,請參照@正點原子的教程資料,小燈就不搶原子哥風頭了,哈哈!

工程沿襲了小燈一貫的簡約作風:


(1)添加FreeRTOS源文件:

源文件清單路徑如下:
FreeRTOS        asks.c
FreeRTOSlist.c
FreeRTOSportableKeilARM_CM3port.c
FreeRTOSportableMemMangheap_4.c
注意這里的FreeRTOSConfig.h的來源小燈在上面IAR移植里面已經(jīng)詳細說明了,而且對FreeRTOSConfig.h里面的內(nèi)容做了大篇幅的分析,讀者請自行翻查,在此不再累述。

(2)添加頭文件路徑:


(3)修改stm32f10x_it.c文件:

至于為了要修改該文件,小燈在上面IAR移植里面已經(jīng)詳細說明了,讀者請自行翻查,在此不再累述。

(4)創(chuàng)建兩個LED閃爍任務(wù):


代碼的解釋在IAR移植里面已經(jīng)詳細說明了,讀者請自行翻查,在此不再累述。

(5)編譯工程:

在MDK移植FreeRTOS相對來說順利很多,因為不會出現(xiàn)一大堆警告和錯誤。接下來下載到板子,效果跟IAR移植后一樣,2個LED按照預(yù)定的頻率閃爍!


總結(jié):
FreeRTOS的移植難度并不大,只是有些地方需要注意,否則出問題了也完全找不出問題出在哪里。由于小燈習慣了使用IAR,習慣使用MDK的用戶如果看IAR的移植步驟可能會很不習慣,但兩者移植過程相仿,讀者只需要注意對應(yīng)的事項就好。鑒于小燈水平有限,文檔難免會有出錯的地方,小燈也很希望各位能指出錯誤之處或提供寶貴意見,小燈會及時修改,不勝感激!


FreeRTOS的官方網(wǎng)址為:http://www.freertos.org


下載:
FreeRTOS工程.rar (631.66 KB, 下載次數(shù): 31)
FreeRTOS移植到STM32F103步驟與注意事項.pdf (682.14 KB, 下載次數(shù): 26)







歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1