新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > uC/OS-II在ARM系統(tǒng)上的移植與實(shí)現(xiàn)

uC/OS-II在ARM系統(tǒng)上的移植與實(shí)現(xiàn)

作者: 時(shí)間:2006-09-14 來(lái)源:網(wǎng)絡(luò) 收藏

摘要:使用公司提供的ADS 開(kāi)發(fā)工具,將uC/ OS - II 處理器上,并將結(jié)果應(yīng)用在跑馬燈和數(shù)碼管的上,運(yùn)行正常,表明成功.
關(guān)鍵詞:uC/ OS - II ;;移植

0  引言
在開(kāi)發(fā)嵌入式時(shí),一般選擇基于ARM 和uC/ OS - II 的嵌入式開(kāi)發(fā)平臺(tái),因?yàn)锳RM 微處理器具有處理速度快、超低功耗、價(jià)格低廉、應(yīng)用前景廣泛等優(yōu)點(diǎn)[1 ] . 將uC/ OS - II 移植到ARM 之后,可以充分結(jié)合兩者的優(yōu)勢(shì). 如果一個(gè)程序在一個(gè)環(huán)境里能工作,我們經(jīng)常希望能將它移植到另一個(gè)編譯、處理器或者操作系統(tǒng)上,這就是移植技術(shù).移植技術(shù)可以使一種特定的技術(shù)在更加廣泛的范圍使用,使軟件使用更加靈活,不局限于某一條件.uC/OS - II 是由Jean J . Labrosse 先生編寫(xiě)的完整的可移植、固化、裁剪的占先式實(shí)時(shí)多任務(wù)內(nèi)核.uC/ OS - II 的源代碼完全開(kāi)放,這是其他商業(yè)實(shí)時(shí)內(nèi)核無(wú)法比擬的[2 ] . 它是針對(duì)嵌入式應(yīng)用設(shè)計(jì)的,在設(shè)計(jì)之初就充分考慮了可移植性,它的大部分源代碼都是用高可移植性的ANSIC 編寫(xiě)的[3 ] . uC/ OS - II可以移植到從8 位到64 位的不同類型、不同規(guī)模的嵌入式系統(tǒng),并能在大部分的8 位、16 位、32 位、甚至64 位的微處理器和DSP 上運(yùn)行. 由于uC/ OS - II是一個(gè)實(shí)時(shí)操作系統(tǒng),所以如果將它嵌入到ARM處理器上,就能夠進(jìn)一步簡(jiǎn)化ARM系統(tǒng)的開(kāi)發(fā).

圖1  uC/ OS - II 文件體系結(jié)構(gòu)

1  uC/ OS - II 的移植
uC/OS - II 的文件系統(tǒng)結(jié)構(gòu)包括核心代碼部分、設(shè)置代碼部分、與處理器相關(guān)的移植代碼部分[4 ] . 結(jié)構(gòu)如圖1 所示.其中最上邊的軟件應(yīng)用層是uC/ OS - II 上的代碼. 核心代碼部分包括7 個(gè)源代碼文件和1 個(gè)頭文件. 功能分別是內(nèi)核管理、事件管理、消息隊(duì)列管理、存儲(chǔ)管理、消息管理、信號(hào)量處理、任務(wù)調(diào)度和定時(shí)管理. 設(shè)置代碼部分包括2 個(gè)頭文件,用來(lái)配置事件控制塊的數(shù)目以及是否包含消息管理相關(guān)代碼. 而與處理器相關(guān)的移植代碼部分則是進(jìn)行移植過(guò)程中需要更改的部分,包括1 個(gè)頭文件OS CPU. H ,1 個(gè)匯編文件OS CPU A. S 和1 個(gè)C 代碼文件.實(shí)際上將uC/ OS - II 移植到ARM 處理器上,需要完成的工作主要是以下三個(gè)與體系結(jié)構(gòu)相關(guān)的文件:OS CPU. H ,OS CPU. C 以及OS CPU A. S[5 ] .

1. 1  OS CPU. H 的移植
文件OS CPU. H 中包括了用# define 語(yǔ)句定義的與處理器相關(guān)的常數(shù)、宏以及類型. 移植時(shí)主要修改的內(nèi)容有:與編譯器相關(guān)的數(shù)據(jù)類型的設(shè)定;用#define 語(yǔ)句定義2 個(gè)宏開(kāi)關(guān)中斷;根據(jù)堆棧的方向定義OS STK GROWTH等.

在將uC/ OS - II 移植到ARM 處理器上時(shí),首先進(jìn)行基本配置和數(shù)據(jù)類型定義. 重新定義數(shù)據(jù)類型是為了增加代碼的可移植性,因?yàn)椴煌木幾g器所提供的同一數(shù)據(jù)類型的數(shù)據(jù)長(zhǎng)度并不相同,例如int型,在有的編譯器中是16 位,而在另外一些編譯器中則是32 位. 所以,為了便于移植,需要重新定義數(shù)據(jù)類型,如INT32U 代表無(wú)符號(hào)32 位整型. typedefunsigned int INT8U ,就是定義一個(gè)8 位的無(wú)符號(hào)整型數(shù)據(jù)類型. 其次就是對(duì)ARM 處理器相關(guān)宏進(jìn)行定義,如ARM處理器中的退出臨界區(qū)和進(jìn)入臨界區(qū)的宏定義,退出臨界區(qū)宏定義[5 ] : # define OS EXITCRITICAL () ARMDisable Int ( ) / / 關(guān)中斷,進(jìn)入臨界區(qū)宏定義# define OS ENTER CRITICAL ( ) AR2MEnableInt () / / 開(kāi)中斷. 最后就是堆棧增長(zhǎng)方向的設(shè)定. 當(dāng)進(jìn)行函數(shù)調(diào)用時(shí),入口參數(shù)和返回地址一般都會(huì)保存在當(dāng)前任務(wù)的堆棧中,編譯器的編譯選項(xiàng)和由此生成的堆棧指令就會(huì)決定堆棧的增長(zhǎng)方向[6 ] ,定義為# define OS STK GROWTH 1.


圖2  堆棧增長(zhǎng)方向
1. 2  OS CPU. C 的移植
OS CPU. C 的移植包括任務(wù)堆棧初始化和相應(yīng)函數(shù)的. 在這里,共有6 個(gè)函數(shù):OSTaskStkInit( ) , OSSTaskCreateHook ( ) , OSTaskDelHook ( ) , OS2TaskSwHook( ) ,OSTaskStatHook ( ) , OSTimeTickHook () . 其中后面的5 個(gè)HOOK函數(shù)又稱為鉤子函數(shù),主要是用來(lái)對(duì)uC/ OS - II 進(jìn)行功能擴(kuò)展. 這些函數(shù)為用戶定義函數(shù),由操作系統(tǒng)調(diào)用相應(yīng)的HOOK函數(shù)去執(zhí)行,在一般情況下,他們都沒(méi)有代碼,所以為空函數(shù)即可. 而函數(shù)OSTaskStkInit ( ) 對(duì)堆棧進(jìn)行初始化,在ARM 系統(tǒng)中,任務(wù)堆??臻g由高到低依次為PC ,LR ,R12 ,R11 , ,R1 ,R0 ,CPSR ,SPSR. 在進(jìn)行堆棧初始化以后,OSTaskStkInit ( ) 返回新的堆棧棧頂指針.

1. 3  OS CPU A. S 的移植
OS CPU A. S 文件的移植需要對(duì)處理器的寄存器進(jìn)行操作,所以必須用匯編語(yǔ)言來(lái)編寫(xiě). 這個(gè)文件的實(shí)現(xiàn)集中體現(xiàn)了所要移植到處理器的體系結(jié)構(gòu)和uC/ OS - II 的移植原理[6 ] . 它包括4 個(gè)子函數(shù):OSStartHighRdy() , OSCtxSw() , OSIntCtxSw() ,OSTick2ISR() . 其中難點(diǎn)在于OSIntCtxSw() 和OSTickISR() 函數(shù)的實(shí)現(xiàn),因?yàn)檫@兩個(gè)函數(shù)的實(shí)現(xiàn)與移植者的移植思路以及相關(guān)硬件定時(shí)器、中斷寄存器的設(shè)置有關(guān).在實(shí)際的移植工作中,這兩處也是比較容易出錯(cuò)的地方.

OSIntCtxSw( ) 函數(shù)由OSIntExit ( ) 函數(shù)調(diào)用,而OSIntExit () 函數(shù)又由OSTickISR() 調(diào)用. OSIntCtxSw()函數(shù)最重要的作用就是它完成在中斷ISR 中直接進(jìn)行任務(wù)切換,從而提高了實(shí)時(shí)響應(yīng)的速度. 它發(fā)生的時(shí)機(jī)是在ISR 執(zhí)行到OSIntExit ( ) 時(shí),如果發(fā)現(xiàn)有高優(yōu)先級(jí)的任務(wù)因?yàn)榈却齮ime tick 的到來(lái)獲得了執(zhí)行 7 2 第4 期李學(xué)橋等:uC/ OS - II 在ARM系統(tǒng)上的移植與實(shí)現(xiàn)的條件,就可以馬上被調(diào)度執(zhí)行,而不用返回被中斷的那個(gè)任務(wù)之后再進(jìn)行任務(wù)切換. 實(shí)現(xiàn)OSIntCtxSw() 的方法大致也有兩種情況[7 ] :一是通過(guò)調(diào)整SP 堆棧指針的方法,根據(jù)所用的編譯器對(duì)于函數(shù)嵌套的處理,通過(guò)精確計(jì)算出所需要調(diào)整的SP 位置來(lái)使得進(jìn)入中斷時(shí)所作的保護(hù)現(xiàn)場(chǎng)的工作可以被重用. 二是設(shè)置需要切換標(biāo)志位的方法,在OSIntCtxSw( ) 里面不發(fā)生切換,而是設(shè)置一個(gè)需要切換的標(biāo)志,等函數(shù)嵌套從進(jìn)入OSIntExit ( ) = > OS ENTER CRITI2CAL() = > OSIntCtxSw( ) = > OS EXIT CRITICAL() = > OSIntExit ( ) 退出后,再根據(jù)標(biāo)志位來(lái)判斷是否需要進(jìn)行中斷級(jí)的任務(wù)切換.

其次是對(duì)OSTickISR() 修改.OSTickISR() 首先在被中斷任務(wù)堆棧中保存CPU 寄存器的值,然后調(diào)用OSIntEnter () . 隨后調(diào)用OSTimeTick() ,檢查所有處于延時(shí)等待狀態(tài)的任務(wù),判斷是否有延時(shí)結(jié)束就緒的任務(wù). 最后調(diào)用OSIntExit ( ) . 如果在中斷中(或其他嵌套的中斷) 有更高優(yōu)先級(jí)的任務(wù)就緒,并且當(dāng)前中斷為中斷嵌套的最后一層,OSIntExit ( ) 將進(jìn)行任務(wù)調(diào)度. 如果進(jìn)行了任務(wù)調(diào)度,OSIntExit () 將不再返回調(diào)用者,而是用新任務(wù)的堆棧中的寄存器數(shù)值恢復(fù)CPU 現(xiàn)場(chǎng),然后實(shí)現(xiàn)任務(wù)切換. 如果當(dāng)前中斷不是中斷嵌套的最后一層,或中斷中沒(méi)有改變?nèi)蝿?wù)的就緒狀態(tài), OSIntExit ( ) 將返回調(diào)用者OSTickISR ( ) ,OSTickISR() 返回被中斷的任務(wù). 最后就是退出臨界區(qū)和進(jìn)入臨界區(qū)函數(shù). 進(jìn)入臨界區(qū)時(shí),必須關(guān)閉中斷,用ARMDisableInt () 函數(shù)實(shí)現(xiàn). 在退出臨界區(qū)的時(shí)候恢復(fù)原來(lái)的中斷狀態(tài),通過(guò)ARMEnableInt ( ) 函數(shù)來(lái)實(shí)現(xiàn)[7 ] . 至于進(jìn)行任務(wù)級(jí)上下文切換,則是由匯編子程序OSCtxSw 實(shí)現(xiàn).

2  在ARM系統(tǒng)上的實(shí)現(xiàn)
以跑馬燈和數(shù)碼管為例,說(shuō)明uC/ OS - II 的移植過(guò)程:跑馬燈是4 個(gè)小燈輪流變明變暗,很方便看出效果. 跑馬燈在日常中使用很多,比如狀態(tài)欄跑馬燈、文字跑馬燈、圖片跑馬燈、單片機(jī)跑馬燈等[8 ] . 本文采用的是單片機(jī)跑馬燈. 實(shí)現(xiàn)單片機(jī)跑馬燈的程序中,只有地址口為低電平(接地) 時(shí),發(fā)光管才會(huì)亮. 所以只要循環(huán)控制地址口的各個(gè)引腳的電平高低變化就可使LED 循環(huán)點(diǎn)亮:首先是全不亮,接著第1 個(gè)燈亮,第2 個(gè)燈亮,第3 個(gè)燈亮,第4 個(gè)燈亮,第5 個(gè)燈亮,最后所有的燈一起亮.
筆者使用6 個(gè)共陽(yáng)極LED 數(shù)碼管來(lái)實(shí)現(xiàn)在7 段數(shù)碼管上循環(huán)顯示0~9 ,A~F 字符. 每個(gè)顯示位的段選線與一個(gè)8 位并行口線對(duì)應(yīng)相連,只要在顯示位上的段選線上保持段碼電平不變,則該位就能保持相應(yīng)的顯示字符. 這里的8 位并行口可以直接采用并行I/ O 口,也可以采用串入/ 并出的移位寄存器或是其他具有三態(tài)功能的鎖存器等. 當(dāng)采用動(dòng)態(tài)顯示接口時(shí),在多位LED 顯示時(shí),為了簡(jiǎn)化電路,降低成本,將所有位的段選線并聯(lián)在一起,由一個(gè)8 位I/ O口控制. 而共陰(或共陽(yáng)) 極公共端分別由相應(yīng)的I/ O 線控制,實(shí)現(xiàn)各位的分時(shí)選通. 由于各個(gè)數(shù)碼管是共用同一個(gè)段碼輸出口分時(shí)輪流通電的,從而大大簡(jiǎn)化了硬件線路,降低了成本.

對(duì)于數(shù)碼管的實(shí)現(xiàn)分為3 個(gè)步驟:
1) 制作LED 字符與碼段對(duì)應(yīng)表

  2) 掃描控制
3 ( (U8 3 ) 0x02000006) = 0x3E; / 3 使能第一個(gè)數(shù)碼管
3 /
3) 段碼輸出
( (U8 3 ) 0x02000004) = seg7table[0 ] ;

根據(jù)上面的LED 字符與碼段對(duì)應(yīng)表,控制相應(yīng)的數(shù)字進(jìn)行輸出. 數(shù)碼管掃描控制地址為0x02000006 ,8 位訪問(wèn),比如Bit0 控制數(shù)碼管0 ,并且低電平有效,Bit5 控制數(shù)碼管5 ,低電平有效,數(shù)碼管顯示試驗(yàn)系統(tǒng)中采用的是動(dòng)態(tài)顯示接口,其中數(shù)碼管掃描控制地址為0x02000006 ,位0 ―5 分別對(duì)應(yīng)一個(gè)數(shù)碼管,將其中每位清0 來(lái)選擇相應(yīng)的數(shù)碼管;地址0x02000004 為數(shù)碼管的數(shù)據(jù)寄存器,控制數(shù)碼管的段碼輸出.

3  多任務(wù)應(yīng)用程序
uC/OS - II 的移植及跑馬燈和數(shù)碼管的實(shí)現(xiàn)如下[9 ] :首先是C 語(yǔ)言入口函數(shù)Main (所有C 程序的入口) . 它里面包括調(diào)用函數(shù)ARMTargetInit () 初始化ARM處理器,調(diào)用OSInit ( ) 進(jìn)行uC/ OS - II 操作系統(tǒng)初始化,然后調(diào)用OSTaskCreate ( ) 函數(shù)創(chuàng)建任務(wù)TaskLED 和TaskSEG,最后調(diào)用ARMTargetStart () 函數(shù)啟動(dòng)時(shí)鐘節(jié)拍中斷,并且調(diào)用OSStart ( ) 啟動(dòng)系統(tǒng)任務(wù)調(diào)度,由于在程序當(dāng)中使用for ( ; ;) ,這是一個(gè)永無(wú)止境的回路,所以裝置可以一直進(jìn)行下去,直到關(guān)閉裝置.
  void Main(void)
  {ARMTargetInit () ;
  uHALr printf (″uC/ OS - II # n″) ;
  OSInit () ;
  Sem1 = OSSemCreate(0) ;
  Sem2 = OSSemCreate(1) ;
  OSTaskCreate(TaskLED , (void 3 ) IdLED , (OS STK 3 )
StackLED[ STACKSIZE - 1 ] , 5) ;
  OSTaskCreate(TaskSEG, (void 3 ) IdSEG, (OS STK 3 )
StackSEG[ STACKSIZE - 1 ] , 6) ;
  ARMTargetStart () ;OSStart () ;
  return ;}

4  結(jié)語(yǔ)
使用創(chuàng)建好的模板Temp 新建一個(gè)工程Temp ,并將模板中的Core 和Assemble 文件夾中的文件加入到工程Temp 中. 1) 新建一個(gè)文件Temp. c ,并將其添加到Temp 工程的App 文件夾中. 2) 打開(kāi)Temp. c文件,添加兩個(gè)任務(wù),它們的任務(wù)處理函數(shù)分別為T(mén)askLED() 和TaskSEG() . 3) 在TaskLED( ) 函數(shù)中每隔50 個(gè)時(shí)鐘節(jié)拍使所有跑馬燈閃爍一次(即按順序亮,然后全亮,最后全滅,順序循環(huán)) . 4) 在TaskSEG() 函數(shù)中每隔50 個(gè)時(shí)鐘節(jié)拍切換一次數(shù)碼管顯示(循環(huán)從0~F 顯示) . 5) 編譯工程Temp ,如果出錯(cuò),則進(jìn)行修改后再編譯. 6) 將Temp 下載并運(yùn)行,看結(jié)果. 正確的結(jié)果是將每隔1/ 2 s 切換一次數(shù)碼管顯示,每隔1/ 2 s使所有跑馬燈閃爍一次. 經(jīng)持續(xù)了2 h試驗(yàn),沒(méi)有出現(xiàn)錯(cuò)誤,跑馬燈和數(shù)碼管正常運(yùn)轉(zhuǎn),結(jié)果證明移植成功.

參考文獻(xiàn):
[1 ]  雷必成, 吳高標(biāo), 吳永良. 嵌入式實(shí)時(shí)操作系統(tǒng)uC/ OS
- II 的移植探討[J ] . 自動(dòng)化技術(shù)與應(yīng)用,2003 , (5) :1 ―3.
[2 ]  邵貝貝. 嵌入式實(shí)時(shí)操作系統(tǒng)uC/ OS - II[M] . 第2 版.
北京:北京航空航天大學(xué)出版社,2003. 2 ―30.
[3 ]  葉豐橋,黃海. uC/ OS - II 在51XA 上的移植應(yīng)用[J ] .
工業(yè)控制計(jì)算機(jī),2002 , (10) :1 ―2.
[4 ]  田澤. 嵌入式開(kāi)發(fā)與應(yīng)用實(shí)驗(yàn)教程[M] . 北京: 北京航
空航天大學(xué)出版社,2004. 264 ―270.
[5 ]  陳賾. ARM嵌入式技術(shù)實(shí)踐教程[M] . 北京:北京航空
航天大學(xué)出版社,2005. 189 ―203.
[6 ]  王田苗. 嵌入式系統(tǒng)設(shè)計(jì)與實(shí)例開(kāi)發(fā)[M] . 北京: 清華
大學(xué)出版社,2003. 62 ―89.
[7 ]  朱華軍. uC/ OS - II 操作系統(tǒng)在ARM處理器上的技巧
[J ] . 計(jì)算機(jī)工程,2004 , (S1) :2 ―3.
[8 ]  蘇中義,楊宇. 嵌入式系統(tǒng)[J ] . 嵌入系統(tǒng),2004 , (3) :11
[9 ]  曾鳴. uC/ OS - II 實(shí)時(shí)操作系統(tǒng)在嵌入式平臺(tái)上進(jìn)行
移植的一般方法和技巧[ J ] . 今日電子, 2004 , (11) :2 ―3.



評(píng)論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉