uC/OS-II在ARM微處理器上的移植<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
引言:在開發嵌入式系統時,一般選擇基於ARM 和uC/OS-II 的嵌入式開發平臺,因爲ARM 微處理器具有處理速度快、超低功耗、價格低廉、應用前景廣泛等優點。uC/OS - II 是由Jean J . Labrosse 先生編寫的完整的可移植、固化、裁剪的佔先式實時多任務內核。uC/OS - II 結構簡單,容易移植,適於學習。
1.硬件平臺要求
要使uC/OS – II可以正常工作,處理器必須滿足如下工作要求:
1. 處理器的C編譯器能產生可重入代碼。
2. 在程序中可以打開或者關閉中斷。
3. 處理器支持中斷,並且能產生中斷(通常10HZ~100HZ之間)。
4. 處理器支持能夠容納一定數據的硬件堆棧。
5. 處理器有將堆棧指針和其他CPU寄存器存儲和讀出到堆棧的指令。
ARM的大多數處理器完全滿足上述要求。
下面是uC/OS的文件結構圖:
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
應用軟件 |
核心代碼 Os_core.c OS_FLAG.C Os_task.c OS_MUTEX.C Os_mem.c Os_q.c Os_sem.c Os_time.c Os_ii.c Os_ii.h Os_mbox.c
|
設置代碼 (應用相關) Os_cfg.h Includes.h |
移植代碼(處理器相關) OS_CPU.H , OS_CPU_A.ASM , OS_CPU.C |
2. 移植需要修改的部分
數據類型:BOOLEA, INT8U, INT8S, INT16U, INT16S, INT32U, INT32S, FP32, FP64, OS_STK, OS_CPU_SR, 這些都在OS_CPU.H中。
宏與宏定義:OS_STK_GROWTH,OS_ENTER_CRITICAL() 與OS_EXIT_CRITICAL() 它們都在OS_CPU.H中。
彙編函數:OSStartHighRdy(),OSCtxSw(),OSIntCtxSw(),OSTickISR(), 這三個在OS_CPU_A.ASM中,它們的修改相對比較複雜。
OS_CPU_C.C 中要修改的C語言函數:OSTaskStkInit(), OSInitHookBegin (void), OSInitHookEnd (void), OSTaskCreateHook (OS_TCB *ptcb), OSTaskDelHook (OS_TCB *ptcb), OSTaskStatHook (void), OSTaskSwHook (void), OSTCBInitHook (OS_TCB *ptcb), OSTimeTickHook (void), OSTaskIdleHook (void)。這10個函數都修改只有OSTaskStkInit()的修改比較複雜,其他的函數很多都是空的。
3. 與處理器和編譯器相關的代碼
1)與編譯器相關的數據類型,放在OS_CPU.H。
比如typedef unsigned char INT8U; // Unsigned 8 bit quantity
2) OS_ENTER_CRITICAL() 與OS_EXIT_CRITICAL()
#define OS_CRITICAL_METHOD 1//修改這一句就可以修改兩個以上兩個函數的定義?
3)OS_STK_GROWTH
定義堆棧的增長方向:#define OS_STK_GROWTH 1 //從下往上
同理#define OS_STK_GROWTH 0 //從上往下
4. OS_CPU_C. C及其6個用 C語言編寫的函數
1)OSTaskStkInint()用於任務棧的初始化,在創建任務和異常的時候都會被調用到,
2)OSTaskCreateHook (OS_TCB *ptcb)在創建任務和異常的時候都會被調用到,該函數調用時中斷是被禁止的,所以要縮短代碼,以縮短中斷的相應時間。當它被調用時,回收到指向已建立任務的OS_TCB指針。
3)OSTaskDelHook (OS_TCB *ptcb)收到被刪除任務的OS_TCB指針。
4)OSTaskSwHook ()任務切換是調用到,這個函數也要注意縮短響應時間。
5)OSTaskStatHook (void)每秒鐘都會被OSTasKStat()調用一次。用戶可用它來擴展統計功能。
6)OSTimeTickHook()在每個時鐘節拍都會被OSTaskTick()調用。實際上是在節拍被uC/OS-II真正處理,並通知用戶的移植實例或應用程序之前別調用的。
後5個可以不用加代碼只有OS_CFG.H中的OS_CPU_HOOKS_EN被置爲1時纔會產生這些函數的代碼。
5. 用彙編語言編寫的4個處理器相關的函數(OS_CPU_A.ASM)
OS_CPU_A. S 文件的移植需要對處理器的寄存器進行操作,所以必須用彙編語言來編寫。這個文件的實現集中體現了所要移植到處理器的體系結構和uC/OS-II 的移植原理。它包括4 個子函數:OSStartHighRdy() ,OSCtxSw() ,OSIntCtxSw() ,OSTick2ISR()。 其中難點在於OSIntCtxSw() 和OSTickISR() 函數的實現,因爲這兩個函數的實現與移植者的移植思路以及相關硬件定時器、中斷寄存器的設置有關。在實際的移植工作中,這兩處也是比較容易出錯的地方。
OSIntCtxSw( ) 函數由OSIntExit ( ) 函數調用,而OSIntExit () 函數又由OSTickISR() 調用。OSIntCtxSw()函數最重要的作用就是它完成在中斷ISR 中直接進行任務切換,從而提高了實時響應的速度。它發生的時機是在ISR 執行到OSIntExit ( ) 時,如果發現有高優先級的任務因爲等待time_tick 的到來獲得了執行。uC/OS-II 在ARM系統上的移植與實現的條件,就可以馬上被調度執行,而不用返回被中斷的那個任務之後再進行任務切換。實現OSIntCtxSw() 的方法大致也有兩種情況:一是通過調整SP 堆棧指針的方法,根據所用的編譯器對於函數嵌套的處理,通過精確計算出所需要調整的SP 位置來使得進入中斷時所作的保護現場的工作可以被重用。 二是設置需要切換標誌位的方法,在OSIntCtxSw( ) 裏面不發生切換,而是設置一個需要切換的標誌,等函數嵌套從進入OSIntExit ( ) = > OS ENTER CRITI2CAL() = > OSIntCtxSw( ) = > OS EXIT CRITICAL() = > OSIntExit ( ) 退出後,再根據標誌位來判斷是否需要進行中斷級的任務切換。
其次是對OSTickISR() 修改,OSTickISR() 首先在被中斷任務堆棧中保存CPU 寄存器的值,然後調用OSIntEnter () 。隨後調用OSTimeTick() ,檢查所有處於延時等待狀態的任務,判斷是否有延時結束就緒的任務。最後調用OSIntExit ( ) 。如果在中斷中(或其他嵌套的中斷) 有更高優先級的任務就緒,並且當前中斷爲中斷嵌套的最後一層,OSIntExit ( ) 將進行任務調度。如果進行了任務調度,OSIntExit () 將不再返回調用者,而是用新任務的堆棧中的寄存器數值恢復CPU 現場,然後實現任務切換。如果當前中斷不是中斷嵌套的最後一層,或中斷中沒有改變任務的就緒狀態,,OSIntExit ( ) 將返回調用者OSTickISR ( ) ,OSTickISR() 返回被中斷的任務。 最後就是退出臨界區和進入臨界區函數。 進入臨界區時,必須關閉中斷,用ARMDisableInt () 函數實現。在退出臨界區的時候恢復原來的中斷狀態,通過ARMEnableInt ( ) 函數來實現。 至於進行任務級上下文切換,則是由彙編子程序OSCtxSw 實現。
應用軟件 |
核心代碼 Os_core.c OS_FLAG.C Os_task.c OS_MUTEX.C Os_mem.c Os_q.c Os_sem.c Os_time.c Os_ii.c Os_ii.h Os_mbox.c
|
設置代碼 (應用相關) Os_cfg.h Includes.h |
移植代碼(處理器相關) OS_CPU.H , OS_CPU_A.ASM , OS_CPU.C |
[參考文章]
《嵌入式實時操作系統uC/OS-II》(第二版) Jean J.Labrosse著 邵貝貝 等譯
《uC/OS-II在ARM系統上的移植與實現》作者:李學橋、劉放美
《嵌入式系統設計與實例開發——基於ARM微處理器與uC/OS-II實時操作系統》(第二版) 王田苗 主編