在MOTOROLA A68K系列MCU上移植μC/OS-II
三、移植中的幾點注意事項
由于μC/OS-II運行的實時性,調試內核幾乎不可能。一旦移植過程中內核運行不穩(wěn)定,很難確定是什么地方的問題,更困難的是有些現(xiàn)象幾乎是不可重復的。這就需要詳細了解內核運行機理,認真分析,找出可能存在的問題。下面就來分析這些移植過程中的問題。
1.編譯器的優(yōu)化選項
在移植過程中,除了要熟悉μC/OS-II和目標芯片之外,熟悉使用的C編碼器也非常重要。通常C編譯器都會提供一些優(yōu)化代碼的選項,在移植μc/OS-II的過程中,這些選項往往會帶來麻煩。下面是移植中與HIWARE的C編譯器有關的例子。
通常在調用子程序或進入中斷時,C編譯器會自動保存CPU內部寄存器到堆棧中。例如,在進入中斷時編譯器會加入下面2條指令:
LINK #$0000,A6;
MOVEM.L D0/D1/D3/D4/D5/D6/D7/A0/A1/A2/A3/A4/A5,-(A7);
這2 條匯編指令的作用是將CPU的數(shù)據(jù)寄存器D0~D7、地址寄存器A0~A5保存到堆棧中,再將此時的堆棧指針A7也保存到堆棧中,并使用A6作為臨時的堆棧指針。這本是一個非常好的優(yōu)化選項,可以防止在中斷中偶然地更改了數(shù)據(jù)寄存器或地址寄存器;但在μC/OS-II中,這個機制將對OS_CPU_C.C 和OS_CPU_ASM.ASM中的幾個子程序和中斷服務例程產(chǎn)生致命的影響。
OS_CPU_C.C和OS_CPU_ASM.ASM中的子程序中斷引發(fā)任務調度,當前的任務被掛起。掛起任務是通過下面的語句來完成的:
MOVEM.L A0-A6/D0-D7,-(A7);
MOVE.L @OSTCBCur,A2;
MOVE.L (A2),A1;
MOVE.L A7,(A1);
保存任務的指針和所有數(shù)據(jù)地址寄存器的值,那么理想情況下,此時的任務堆棧應該是如圖1所示的情況(以OSCtxSw()函數(shù)為例,可以對應到OS_CPU_C.C和OS_CPU_ASM.ASM中的其他函數(shù)和中斷處理例程)。
那么恢復掛起的任務時,只要通過如下語句:
MOVE.L OSTCBHighRdy,A1;
MOVE.L @OSTCBCur,A2;
MOVE.L A1,(A2);
MOVE.L (A1),A7;
MOVEM.L (A7)+,A0-A6/D0-D7;
將保存在任務TCB中的任務堆棧指針恢復,再恢復數(shù)據(jù)地址寄存器,最后執(zhí)行OSCtxSw()的中斷返回,就可以順利地恢復被掛起的任務。
如果C編譯器在OSCtxSw()函數(shù)入口處插入了2條保存數(shù)據(jù)地址寄存器和堆棧指針的語句后,再執(zhí)行掛起任務的語句,任務的堆棧會變成圖2所示的情況。編譯器引起了堆棧的變化,如果所有的任務都是用這種方式掛起和恢復的,并不會產(chǎn)生致命的問題,因為編碼器退出OSCtxSw()函數(shù)時會插入如下語句恢復堆棧:
MOVEM.L (A7)+,D0-D7/A0-A5;
UNLK A6;
問題在于初始化任務的時候,每個任務實際上是按照圖1所示的堆棧結構被初始化的,那么,按照圖2的堆棧結構來恢復自然會導致堆棧崩潰。
解決這個問題的方法很多,可以改定任務初始化的代碼以適應C編譯器的這個“優(yōu)化”,也可以在進入OSCtxSw()函數(shù)時首先調用如下語句恢復堆棧,抵消C編碼器的影響:
MOVEM.L (A7)+,D0-D7/A0-A5;
UNLK A6;
而在退出OSCtxSw()函數(shù)前再調用如下語句模擬出更動的堆棧:
LINK #$0000,A6
MOVEM.L D0-D7/A0-A5,-(A7);
較好的方法當然是調整編譯器,取消這個優(yōu)化選項。如果無法調整編譯器,就只有用以上辦法來適應編譯器了。
2.開關中斷的方法
在μC/OS -II中,開關中斷是非常重要的,它可以保證關鍵代碼或訪問全局變量時不受中斷的意外影響。CPU32的中斷控制比較復雜,提供了7級具有不同級別的中斷;可以選擇關閉或打開某幾級中斷。但多級中斷會使得μC/OS-II的中斷處理變得復雜。在簡單的應用或初次嘗試移植μC/OS-II時,可以使用全開全關的方法。
評論