ucOS學(xué)習(xí)筆記(4)——一步一步移植ucOS到STM32
1.到micrium官網(wǎng)下載最新的 OS在stm32上的移植資料。下載地址為:http://micrium.com/download/Micrium-ARM-OS-II-Cortex-M3.exe
2.平臺(tái)搭建:
a.將1下載得到的文件解壓得到micrium文件夾,并在MicriumSoftware OS-II下用UV4創(chuàng)建一個(gè) OS工程,配置CPU為STM32F101C8
b.建立如圖1所示的工程目錄結(jié)構(gòu)。其中APP層用于放置應(yīng)用程序, OS用于放置所有 OS與處理器無(wú)關(guān)的源碼,PORT用于放置移植 OS需要改動(dòng)的文件,而BSP則用于放置系統(tǒng)的驅(qū)動(dòng)程序,LIB為系統(tǒng)調(diào)用的庫(kù)支持。該目錄組織依據(jù)來(lái)源于micrium公布的 OS移植文檔,圖2是該移植文檔的系統(tǒng)軟件結(jié)構(gòu)圖供參考。
圖1 OS的目錄結(jié)構(gòu)
圖2 OS系統(tǒng)軟件結(jié)構(gòu)
c.工程建立完畢以后將MicriumSoftware OS-IISource目錄下的所有文件(包括h文件)添加到 OS組,將MicriumSoftware OS-IIPortsARM-Cortex-M3GenericRealView目錄下的所有文件添加到PORT組
d.完成以上工作后進(jìn)行一次編譯,我們可以發(fā)現(xiàn)出現(xiàn)錯(cuò)誤提示
.Sourceos_core.c(26): error: #5: cannot open source input file " os_ii.h": No s h file or directory
該問題是包含文件路徑引起的, os_ii.h文件實(shí)際上存在于MicriumSoftware OS-IISource目錄下。因此我們需要在工程設(shè)置中的C/C++選項(xiàng)卡手動(dòng)增加頭文件路徑,針對(duì)以上錯(cuò)誤我們應(yīng)該增加的頭文件路徑未.Source
e.再次編譯發(fā)生錯(cuò)誤
.Source os_ii.h(44): error: #5: cannot open source input file "app_cfg.h": No s h file or directory
這個(gè)問題應(yīng)該不是原生 OS導(dǎo)致的,是micrium移植系統(tǒng)的時(shí)候修改了源文件,在其中增加了一些配置選項(xiàng),這個(gè)配置選項(xiàng)保存在app_cfg.h中,但是micrium發(fā)布移植文件包的時(shí)候該文件又沒有包含在內(nèi),因此需要我們自己寫一個(gè)配置文件。本文為了方便就不細(xì)致研究文件內(nèi)容,直接從micrium的開發(fā)板STM3210B-EVAL源碼包中拷貝該文件放置于工程目錄下的APP文件夾中,并設(shè)置相應(yīng)的包含路徑。
f.再次編譯發(fā)生錯(cuò)誤
.Source os_ii.h(45): error: #5: cannot open source input file "os_cfg.h": No s h file or directory
在micrium的移植文件包中也沒有這個(gè)文件,但是在目錄MicriumSoftware OS-IISource下存在一個(gè)文件名為os_cfg_r.h的文件,將該文件名后的r去掉解決。
g.再次編譯發(fā)生錯(cuò)誤
.Source os_ii.h(46): error: #5: cannot open source input file "os_cpu.h": No s h file or directory
該文件實(shí)際上存在于MicriumSoftware OS-IIPortsARM-Cortex-M3GenericRealView目錄下,因此可以通過(guò)修改文件包含路徑解決。
h.再次編譯發(fā)生錯(cuò)誤
.OUTPUT OSII.sct(7): error: L6236E: No section matches selector - no section to be FIRST/LAST.
點(diǎn)擊該錯(cuò)誤提示出現(xiàn)以下內(nèi)容:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00010000 { ; load region size_region
ER_IROM1 0x08000000 0x00010000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00002800 { ; RW data
.ANY (+RW +ZI)
}
}
實(shí)際上這個(gè)錯(cuò)誤發(fā)生在連接階段,從點(diǎn)擊錯(cuò)誤得到的信息看表示連接的時(shí)候找不到一個(gè)標(biāo)號(hào)為RESET的段,而keil默認(rèn)連接是從RESET段開始的,因此出現(xiàn)了這個(gè)錯(cuò)誤。對(duì)于這個(gè)錯(cuò)誤的解決方法我們可以通過(guò)e的方式,將開發(fā)板軟件包內(nèi)的init.s文件拷貝到APP目錄,并添加到工程中,同時(shí)把init.s文件中第一個(gè)段改名由INIT為RESET解決。
i.再次編譯發(fā)現(xiàn)在連接的時(shí)候很多以hook結(jié)尾的代碼找不到實(shí)體,但是有聲明。錯(cuò)誤示例如下:
.OUTPUT OSII.axf: Error: L6218E: Undefined symbol App_TCBInitHook (referred from os_cpu_c.o).
這些函數(shù)實(shí)際上都是 OS為了方便用戶監(jiān)視系統(tǒng)運(yùn)行過(guò)程而保留的鉤子函數(shù), OS內(nèi)部的函數(shù)名實(shí)際上是OSTCBInitHook,micrium在移植過(guò)程中為了層次清晰,在 OS鉤子函數(shù)內(nèi)部增加了相應(yīng)的APP***HOOK調(diào)用,同時(shí)通過(guò)功能開關(guān)OS_APP_HOOKS_EN來(lái)控制是否啟用這些功能。我們當(dāng)前的代碼除了 OS系統(tǒng)代碼,其他什么應(yīng)用代碼都還沒有,因此編譯會(huì)出錯(cuò)。這種情況下我們需要暫時(shí)關(guān)閉這個(gè)功能將在OS_CFG.h中的OS_APP_HOOKS_EN配置為0。
j.再次編譯發(fā)現(xiàn)系統(tǒng)提示沒有main函數(shù),增加一個(gè)main.c文件解決。
k.再次編譯發(fā)生錯(cuò)誤:
.OUTPUT OSII.axf: Error: L6218E: Undefined symbol OS_CPU_SysTickClkFreq (referred from os_cpu_c.o).
這個(gè)錯(cuò)誤時(shí)系統(tǒng)找不到OS_CPU_SysTickClkFreq這個(gè)函數(shù)實(shí)體。查閱相關(guān)資料發(fā)現(xiàn)micrium增加這個(gè)函數(shù)的目的是獲取系統(tǒng)當(dāng)前的時(shí)鐘頻率,于是我們?cè)诠こ讨械腂SP組增加一個(gè)bsp.c文件,同時(shí)實(shí)現(xiàn)這個(gè)OS_CPU_SysTickClkFreq函數(shù)即可。未測(cè)試需要,本函數(shù)簡(jiǎn)單寫為
INT32U OS_CPU_SysTickClkFreq(void)
{
return 8000000;
}
l.再次編譯已經(jīng)沒有錯(cuò)誤發(fā)生,只有一個(gè)警告信息
.OUTPUT OSII.axf: Warning: L6305W: Image does not have an entry point. (Not specified or not set d to multiple choices.)
通過(guò)查閱資料,大致意思就是說(shuō)keil不知道整個(gè)代碼的入口在哪兒,根據(jù)init.s中的代碼
ENTRY
ResetHndlr
;******************************************************************************
; SETUP STACK POINTERS
;******************************************************************************
;******************************************************************************
; MOVE TO MAIN
;******************************************************************************
ldr r0, =__main
bx r0 ; Save this in register for possible long jump ;
ALIGN
END
可以看到我們的入口在標(biāo)號(hào)為ResetHndlr的地方,因此我們通過(guò)指定入口解決該問題。指定入口的方法是在編譯器選項(xiàng)的linker頁(yè)增加命令
--entry ResetHndlr
至此第一步編譯算是完成了。
d.完成以上工作后進(jìn)行一次編譯,我們可以發(fā)現(xiàn)出現(xiàn)錯(cuò)誤提示
.Sourceos_core.c(26): error: #5: cannot open source input file " os_ii.h": No s h file or directory
該問題是包含文件路徑引起的, os_ii.h文件實(shí)際上存在于MicriumSoftware OS-IISource目錄下。因此我們需要在工程設(shè)置中的C/C++選項(xiàng)卡手動(dòng)增加頭文件路徑,針對(duì)以上錯(cuò)誤我們應(yīng)該增加的頭文件路徑未.Source
e.再次編譯發(fā)生錯(cuò)誤
.Source os_ii.h(44): error: #5: cannot open source input file "app_cfg.h": No s h file or directory
這個(gè)問題應(yīng)該不是原生 OS導(dǎo)致的,是micrium移植系統(tǒng)的時(shí)候修改了源文件,在其中增加了一些配置選項(xiàng),這個(gè)配置選項(xiàng)保存在app_cfg.h中,但是micrium發(fā)布移植文件包的時(shí)候該文件又沒有包含在內(nèi),因此需要我們自己寫一個(gè)配置文件。本文為了方便就不細(xì)致研究文件內(nèi)容,直接從micrium的開發(fā)板STM3210B-EVAL源碼包中拷貝該文件放置于工程目錄下的APP文件夾中,并設(shè)置相應(yīng)的包含路徑。
f.再次編譯發(fā)生錯(cuò)誤
.Source os_ii.h(45): error: #5: cannot open source input file "os_cfg.h": No s h file or directory
在micrium的移植文件包中也沒有這個(gè)文件,但是在目錄MicriumSoftware OS-IISource下存在一個(gè)文件名為os_cfg_r.h的文件,將該文件名后的r去掉解決。
g.再次編譯發(fā)生錯(cuò)誤
.Source os_ii.h(46): error: #5: cannot open source input file "os_cpu.h": No s h file or directory
該文件實(shí)際上存在于MicriumSoftware OS-IIPortsARM-Cortex-M3GenericRealView目錄下,因此可以通過(guò)修改文件包含路徑解決。
h.再次編譯發(fā)生錯(cuò)誤
.OUTPUT OSII.sct(7): error: L6236E: No section matches selector - no section to be FIRST/LAST.
點(diǎn)擊該錯(cuò)誤提示出現(xiàn)以下內(nèi)容:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00010000 { ; load region size_region
ER_IROM1 0x08000000 0x00010000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00002800 { ; RW data
.ANY (+RW +ZI)
}
}
實(shí)際上這個(gè)錯(cuò)誤發(fā)生在連接階段,從點(diǎn)擊錯(cuò)誤得到的信息看表示連接的時(shí)候找不到一個(gè)標(biāo)號(hào)為RESET的段,而keil默認(rèn)連接是從RESET段開始的,因此出現(xiàn)了這個(gè)錯(cuò)誤。對(duì)于這個(gè)錯(cuò)誤的解決方法我們可以通過(guò)e的方式,將開發(fā)板軟件包內(nèi)的init.s文件拷貝到APP目錄,并添加到工程中,同時(shí)把init.s文件中第一個(gè)段改名由INIT為RESET解決。
i.再次編譯發(fā)現(xiàn)在連接的時(shí)候很多以hook結(jié)尾的代碼找不到實(shí)體,但是有聲明。錯(cuò)誤示例如下:
.OUTPUT OSII.axf: Error: L6218E: Undefined symbol App_TCBInitHook (referred from os_cpu_c.o).
這些函數(shù)實(shí)際上都是 OS為了方便用戶監(jiān)視系統(tǒng)運(yùn)行過(guò)程而保留的鉤子函數(shù), OS內(nèi)部的函數(shù)名實(shí)際上是OSTCBInitHook,micrium在移植過(guò)程中為了層次清晰,在 OS鉤子函數(shù)內(nèi)部增加了相應(yīng)的APP***HOOK調(diào)用,同時(shí)通過(guò)功能開關(guān)OS_APP_HOOKS_EN來(lái)控制是否啟用這些功能。我們當(dāng)前的代碼除了 OS系統(tǒng)代碼,其他什么應(yīng)用代碼都還沒有,因此編譯會(huì)出錯(cuò)。這種情況下我們需要暫時(shí)關(guān)閉這個(gè)功能將在OS_CFG.h中的OS_APP_HOOKS_EN配置為0。
j.再次編譯發(fā)現(xiàn)系統(tǒng)提示沒有main函數(shù),增加一個(gè)main.c文件解決。
k.再次編譯發(fā)生錯(cuò)誤:
.OUTPUT OSII.axf: Error: L6218E: Undefined symbol OS_CPU_SysTickClkFreq (referred from os_cpu_c.o).
這個(gè)錯(cuò)誤時(shí)系統(tǒng)找不到OS_CPU_SysTickClkFreq這個(gè)函數(shù)實(shí)體。查閱相關(guān)資料發(fā)現(xiàn)micrium增加這個(gè)函數(shù)的目的是獲取系統(tǒng)當(dāng)前的時(shí)鐘頻率,于是我們?cè)诠こ讨械腂SP組增加一個(gè)bsp.c文件,同時(shí)實(shí)現(xiàn)這個(gè)OS_CPU_SysTickClkFreq函數(shù)即可。未測(cè)試需要,本函數(shù)簡(jiǎn)單寫為
INT32U OS_CPU_SysTickClkFreq(void)
{
return 8000000;
}
l.再次編譯已經(jīng)沒有錯(cuò)誤發(fā)生,只有一個(gè)警告信息
.OUTPUT OSII.axf: Warning: L6305W: Image does not have an entry point. (Not specified or not set d to multiple choices.)
通過(guò)查閱資料,大致意思就是說(shuō)keil不知道整個(gè)代碼的入口在哪兒,根據(jù)init.s中的代碼
ENTRY
ResetHndlr
;******************************************************************************
; SETUP STACK POINTERS
;******************************************************************************
;******************************************************************************
; MOVE TO MAIN
;******************************************************************************
ldr r0, =__main
bx r0 ; Save this in register for possible long jump ;
ALIGN
END
可以看到我們的入口在標(biāo)號(hào)為ResetHndlr的地方,因此我們通過(guò)指定入口解決該問題。指定入口的方法是在編譯器選項(xiàng)的linker頁(yè)增加命令
--entry ResetHndlr
至此第一步編譯算是完成了。
評(píng)論