μC/OS-II 移植筆記 2(FreeScale 68HCS12 核單片機)
首先是函數(shù)和全局變量的聲明。
本文引用地址:http://www.ex-cimer.com/article/201611/318814.htm- ;***************************************************************************
- ;PUBLICDECLARATIONS
- ;***************************************************************************
- xdefOSCPUSaveSR
- xdefOSCPURestoreSR
- xdefOSStartHighRdy
- xdefOSCtxSw
- xdefOSIntCtxSw
- xdefOSTickISR
- ;***************************************************************************
- ;EXTERNALDECLARATIONS
- ;***************************************************************************
- xrefOSIntExit
- xrefOSIntNesting
- xrefOSPrioCur
- xrefOSPrioHighRdy
- xrefOSRunning
- xrefOSTaskSwHook
- xrefOSTCBCur
- xrefOSTCBHighRdy
- xrefOSTimeTick
然后是臨界區(qū)的相關代碼。
- OSCPUSaveSR:
- tfrccr,b;Itsassumedthat8-bitreturnvalueisinregisterB
- sei;Disableinterrupts
- rts;ReturntocallerwithBcontainingthepreviousCCR
- OSCPURestoreSR:
- tfrb,ccr;BcontainstheCCRvaluetorestore,movetoCCR
- rts
下面的代碼是重點部分,首先是 OSStartHighRdy 函數(shù),雖然這個函數(shù)只在 OSStart 函數(shù)中被調用一次,在之后的程序生命周期中就再也用不到了,但這次調用至關重要,決定了用戶任務是否能被調度起來。因此代碼中給出的注釋盡可能的詳細,我想看過注釋后就不需要我解釋什么了。
- ;***********************************************************************
- ;STARTHIGHESTPRIORITYTASKREADY-TO-RUN
- ;
- ;Description:ThisfunctioniscalledbyOSStart()tostart
- ;thehighestprioritytaskthatwascreatedbyyour
- ;applicationbeforecallingOSStart().
- ;
- ;Arguments:none
- ;
- ;Note(s):1)Thestackframeisassumedtolookasfollows:
- ;
- ;OSTCBHighRdy->OSTCBStkPtr+0CCR
- ;+1B
- ;+2A
- ;+3X(H)
- ;+4X(L)
- ;+5Y(H)
- ;+6Y(L)
- ;+7PC(H)
- ;+8PC(L)
- ;
- ;2)OSStartHighRdy()MUST:
- ;a)CallOSTaskSwHook()then,
- ;b)SetOSRunningtoTRUE,
- ;c)Switchtothehighestprioritytaskbyloading
- ;thestackpointerofthehighestprioritytask
- ;intotheSPregisterandexecutean
- ;RTIinstruction.
- ;************************************************************************
- OSStartHighRdy:
- jsrOSTaskSwHook;4~,調用OSTaskSwHook
- ldab#$01;2~,OSRunning=1
- stabOSRunning;4~
- ldxOSTCBHighRdy;3~,將OSTCBHighRdy的地址放到寄存器X
- lds0,x;3~,將OSTCBHighRdy->OSTCBStkPtr放到SP
- nop
- rti;4~,Runtask
其實上面的代碼也可以放到OS_CPU_C.C 中,下面是個示例:
- #pragmaCODE_SEGNON_BANKED
- #pragmaTRAP_PROCSAVE_NO_REGS
- voidOSStartHighRdy(void)
- {
- __asmjsrOSTaskSwHook;//OSTaskSwHook();
- __asmldab#$01;
- __asmstabOSRunning;//OSRunning=TRUE;
- __asm
- {
- ldxOSTCBHighRdy
- lds0,x
- nop
- }
- }
上面代碼中 #pragma TRAP_PROC SAVE_NO_REGS 表示這是個中斷處理函數(shù),編譯器不為之保存任何寄存器內容。 雖然 OSStartHighRdy 并不是個真正的中斷處理函數(shù),但它模擬卻模擬了中斷處理函數(shù)的行為,函數(shù)結束時調用 rti 而不是 rts 命令。
下面是任務切換的代碼,注釋已經(jīng)足夠的詳細了,如果有不明白的地方建議將 Jean J.Labrosse 的書再仔細讀讀。
- OSCtxSw:
- ldyOSTCBCur;3~,OSTCBCur->OSTCBStkPtr=StackPointer
- sts0,y
- OSIntCtxSw:
- jsrOSTaskSwHook;4~,Callusertaskswitchhook
- ldxOSTCBHighRdy;3~,OSTCBCur=OSTCBHighRdy
- stxOSTCBCur
- ldabOSPrioHighRdy;3~,OSPrioCur=OSPrioHighRdy
- stabOSPrioCur
- lds0,x;3~,LoadSPinto68HC12
- nop
- rti;8~,Runtask
可以看到,上面兩個函數(shù)公用了大部分的函數(shù)體。上面的代碼也可以直接寫到 OS_CPU_C.C 中,不過寫成 C 函數(shù)后就不能公用函數(shù)體了。
最后一部分是時鐘中斷程序,我使用RTI中斷作為周期性時鐘源。
- OSTickISR:
- incOSIntNesting;4~,NotifyuC/OS-IIaboutISR
- ldabOSIntNesting;4~,if(OSIntNesting==1){
- cmpb#$01
- bneOSTickISR1
- ldyOSTCBCur;OSTCBCur->OSTCBStkPtr=StackPointer
- sts0,y;}
- OSTickISR1:
- BSET$37,#128;CRGFLG_RTIF=1,這句是反匯編出來的,應該沒錯
- jsrOSTimeTick
- jsrOSIntExit;6~+,NotifyuC/OS-IIaboutendofISR
- rti;12~,Returnfrominterrupt,nohigherprioritytasksready.
中斷程序的大部分代碼都比較簡答,只有下面這句我下了番功夫才寫出來:
BSET $37, #128
與這行代碼功能相同的 C 代碼是:CRGFLG_RTIF = 1
我將 C代碼直接生成匯編代碼的結果是:BSET _CRGFLG,#128
可是直接拿到匯編文件中卻無法編譯,提示說 _CRGFLG 沒有定義。一番查找才確定了_CRGFLG = 0x37。
2.3 OS_CPU_C.C
由于大部分的移植代碼都放到了匯編文件中,OS_CPU_C.C 中的工作就很少了。OS_CPU_C.C 最重要的工作是 OSTaskStkInit 函數(shù),并且網(wǎng)上流傳的大多數(shù) 68HC12 內核的移植代碼的這部分都或多或少的有問題。下面先給出我的代碼:
- OS_STK*OSTaskStkInit(void(*task)(void*pd),void*p_arg,OS_STK*ptos,INT16Uopt)
- {
- INT16U*wstk;
- INT8U*bstk;
- (void)opt;/*optisnotused,preventwarning*/
- ptos--;/*需要這么調整一下棧頂?shù)刂?,否則存的第一個int16的低Byte會溢出堆棧*/
- wstk=(INT16U*)ptos;/*Loadstackpointer*/
- *wstk--=(INT16U)task;/*Returnaddress.Format:PCH:PCL*/
- *wstk--=(INT16U)task;/*Returnaddress.Format:PCH:PCL*/
- *wstk--=(INT16U)0x2222;/*YRegister*/
- *wstk--=(INT16U)0x1111;/*XRegister*/
- *wstk=(INT16U)p_arg;/*Simulatecalltofunctionwithargument(InDRegister)*/
- bstk=(INT8U*)wstk;/*ConvertWORDptrtoBYTEptrtosetCCR*/
- bstk--;
- *bstk=(0xC0);/*CCRRegister(DisableSTOPinstructionandXIRQ)*/
- return((OS_STK*)bstk);/*Returnpointertonewtop-of-stack*/
- }
其中有幾點需要特別注意:
(1)68HC12 內核與 68HC11 內核一個大的區(qū)別就是 SP 指向的是實棧頂。老的68HC11的移植代碼都是 *--wstk = XXXX。移植到68HC12 內核就要改為*wstk-- = XXXX。否則會浪費掉堆棧的前兩個字節(jié)。
(2)先要執(zhí)行 ptos--;否則第一個雙字節(jié)會有一半溢出堆??臻g。
(3)任務的參數(shù)傳遞是通過寄存器 D 的,而不是堆棧。網(wǎng)上代碼多數(shù)是:
- *wstk--=(INT16U)p_arg;
- *wstk--=(INT16U)task;
這樣參數(shù)是傳遞不進來的,只有像我的代碼中這樣寫才是正確的。
(4)代碼中 *wstk-- = (INT16U)task; 重復了兩遍,千萬別以為這是我的筆誤。堆棧中先存的(INT16U)task實際上是 task 函數(shù)的返回地址。雖然 μC/OS-II 要求任務不能返回,但是作為 C 語言的調用約定,在調用一個 C 函數(shù)之前要將 C 函數(shù)的返回地址先入棧。因此我將 task 的地址重復了兩次,實際上第一的地址是什么都不重要,因為程序運行中覺得不會用到。甚至不要這行也行,還能節(jié)省堆棧中兩個字節(jié)的空間。不過我還是選擇了保留這行,使其看起來更加符合 C 語言的調用規(guī)范。
除此之外,OS_CPU_C.C 還包括一系列的 Hook 函數(shù):
- #ifOS_CPU_HOOKS_EN>0&&OS_VERSION>203
- voidOSInitHookBegin(void)
- {
- #ifOS_TMR_EN>0
- OSTmrCtr=0;
- #endif
- }
- voidOSInitHookEnd(void)
- {
- }
- #endif
- #ifOS_CPU_HOOKS_EN>0
- voidOSTaskCreateHook(OS_TCB*ptcb)
- {
- #ifOS_APP_HOOKS_EN>0
- App_TaskCreateHook(ptcb);
- #else
- (void)ptcb;
- #endif
- }
- voidOSTaskDelHook(OS_TCB*ptcb)
- {
- #ifOS_APP_HOOKS_EN>0
- App_TaskDelHook(ptcb);
- #else
- (void)ptcb;
- #endif
- }
- voidOSTaskStatHook(void)
- {
- #ifOS_APP_HOOKS_EN>0
- App_TaskStatHook();
- #endif
- }
- voidOSTaskSwHook(void)
- {
- #ifOS_APP_HOOKS_EN>0
- App_TaskSwHook();
- #endif
- }
- #endif
- #ifOS_CPU_HOOKS_EN>0&&OS_VERSION>=251
- voidOSTaskIdleHook(void)
- {
- #ifOS_APP_HOOKS_EN>0
- App_TaskIdleHook();
- #endif
- }
- #endif
- #ifOS_CPU_HOOKS_EN>0&&OS_VERSION>203
- voidOSTCBInitHook(OS_TCB*ptcb)
- {
- #ifOS_APP_HOOKS_EN>0
- App_TCBInitHook(ptcb);
- #else
- (void)ptcb;/*Preventcompilerwarning*/
- #endif
- }
- #endif
- #ifOS_CPU_HOOKS_EN>0
- voidOSTimeTickHook(void)
- {
- #ifOS_APP_HOOKS_EN>0
- App_TimeTickHook();
- #endif
- #ifOS_TMR_EN>0
- OSTmrCtr++;
- if(OSTmrCtr>=(OS_TICKS_PER_SEC/OS_TMR_CFG_TICKS_PER_SEC))
- {
- OSTmrCtr=0;
- OSTmrSignal();
- }
- #endif
- }
- #endif
代碼中 OS_APP_HOOKS_EN 和 OS_TMR_EN 在v2.52 版本中還沒出現(xiàn),我在這里這樣寫是為了移植到后面版本時更輕松。
至此,移植代碼就基本完成了。不過這樣還不能運行,因為兩個中斷處理函數(shù)(OSCtxSw和OSTickISR)還沒有和對應的中斷產(chǎn)生關聯(lián)。將這二者關聯(lián)起來的方法有幾種,比如直接在 PRM 文件中制定,我用了種比較笨的辦法,從網(wǎng)上找了個 vector.c 文件,雖然看起來不是很優(yōu)雅,但確實是正確的代碼。
- /*******************************************************************
- *
- *FreescaleMC9S12DP256ISRVectorDefinitions
- *
- *FileName:vectors.c
- *Version:1.0
- *Date:Jun/22/2004
- *Programmer:EricShufro
- ********************************************************************/
- /********************************************************************
- *EXTERNALISRFUNCTIONPROTOTYPES
- *********************************************************************/
- externvoidnear_Startup(void);/*StartupRoutine.*/
- externvoidnearOSTickISR(void);/*OSTimeTickRoutine.*/
- externvoidnearOSCtxSw(void);/*OSContectSwitchRoutine.*/
- externvoidnearSCI1_ISR(void);/*SCI1Routine.*/
- externvoidnearSCI0_ISR(void);/*SCI0Routine.*/
- /*
- ************************************************************************
- *DUMMYINTERRUPTSERVICEROUTINES
- *
- *Description:Whenaspuriousinterruptoccurs,theprocessorwill
- *jumptothededicateddefaulthandlerandstaythere
- *sothatthesourceinterruptmaybeidentifiedand
- *debugged.
- *
- *Notes:DoNotModify
- ************************************************************************
- */
- #pragmaCODE_SEG__NEAR_SEGNON_BANKED
- __interruptvoidsoftware_trap64(void){for(;;);}
- __interruptvoidsoftware_trap63(void){for(;;);}
- __interruptvoidsoftware_trap62(void){for(;;);}
- __interruptvoidsoftware_trap61(void){for(;;);}
- __interruptvoidsoftware_trap60(void){for(;;);}
- __interruptvoidsoftware_trap59(void){for(;;);}
- __interruptvoidsoftware_trap58(void){for(;;);}
- __interruptvoidsoftware_trap57(void){for(;;);}
- __interruptvoidsoftware_trap56(void){for(;;);}
- __interruptvoidsoftware_trap55(void){for(;;);}
- __interruptvoidsoftware_trap54(void){for(;;);}
- __interruptvoidsoftware_trap53(void){for(;;);}
- __interruptvoidsoftware_trap52(void){for(;;);}
- __interruptvoidsoftware_trap51(void){for(;;);}
- __interruptvoidsoftware_trap50(void){for(;;);}
- __interruptvoidsoftware_trap49(void){for(;;);}
- __interruptvoidsoftware_trap48(void){for(;;);}
- __interruptvoidsoftware_trap47(void){for(;;);}
- __interruptvoidsoftware_trap46(void){for(;;);}
- __interruptvoidsoftware_trap45(void){for(;;);}
- __interruptvoidsoftware_trap44(void){for(;;);}
- __interruptvoidsoftware_trap43(void){for(;;);}
- __interruptvoidsoftware_trap42(void){for(;;);}
- __interruptvoidsoftware_trap41(void){for(;;);}
- __interruptvoidsoftware_trap40(void){for(;;);}
- __interruptvoidsoftware_trap39(void){for(;;);}
- __interruptvoidsoftware_trap38(void){for(;;);}
- __interruptvoidsoftware_trap37(void){for(;;);}
- __interruptvoidsoftware_trap36(void){for(;;);}
- __interruptvoidsoftware_trap35(void){for(;;);}
- __interruptvoidsoftware_trap34(void){for(;;);}
- __interruptvoidsoftware_trap33(void){for(;;);}
- __interruptvoidsoftware_trap32(void){for(;;);}
- __interruptvoidsoftware_trap31(void){for(;;);}
- __interruptvoidsoftware_trap30(void){for(;;);}
- __interruptvoidsoftware_trap29(void){for(;;);}
- __interruptvoidsoftware_trap28(void){for(;;);}
- __interruptvoidsoftware_trap27(void){for(;;);}
- __interruptvoidsoftware_trap26(void){for(;;);}
- __interruptvoidsoftware_trap25(void){for(;;);}
- __interruptvoidsoftware_trap24(void){for(;;);}
- __interruptvoidsoftware_trap23(void){for(;;);}
- __interruptvoidsoftware_trap22(void){for(;;);}
- __interruptvoidsoftware_trap21(void){for(;;);}
- __interruptvoidsoftware_trap20(void){for(;;);}
- __interruptvoidsoftware_trap19(void){for(;;);}
- __interruptvoidsoftware_trap18(void){for(;;);}
- __interruptvoidsoftware_trap17(void){for(;;);}
- __interruptvoidsoftware_trap16(void){for(;;);}
- __interruptvoidsoftware_trap15(void){for(;;);}
- __interruptvoidsoftware_trap14(void){for(;;);}
- __interruptvoidsoftware_trap13(void){for(;;);}
- __interruptvoidsoftware_trap12(void){for(;;);}
- __interruptvoidsoftware_trap11(void){for(;;);}
- __interruptvoidsoftware_trap10(void){for(;;);}
- __interruptvoidsoftware_trap09(void){for(;;);}
- __interruptvoidsoftware_trap08(void){for(;;);}
- __interruptvoidsoftware_trap07(void){for(;;);}
- __interruptvoidsoftware_trap06(void){for(;;);}
- __interruptvoidsoftware_trap05(void){for(;;);}
- __interruptvoidsoftware_trap04(void){for(;;);}
- __interruptvoidsoftware_trap03(void){for(;;);}
- __interruptvoidsoftware_trap02(void){for(;;);}
- __interruptvoidsoftware_trap01(void){for(;;);}
- #pragmaCODE_SEGDEFAULT
- /***********************************************************************
- *INTERRUPTVECTORS
- ***********************************************************************/
- typedefvoid(*neartIsrFunc)(void);
- consttIsrFunc_vect[]@0xFF80={/*Interrupttable*/
- software_trap63,/*63RESERVED*/
- software_trap62,/*62RESERVED*/
- software_trap61,/*61RESERVED*/
- software_trap60,/*60RESERVED*/
- software_trap59,/*59RESERVED*/
- software_trap58,/*58RESERVED*/
- software_trap57,/*57PWMEmergencyShutdown*/
- software_trap56,/*56PortPInterrupt*/
- software_trap55,/*55CAN4transmit*/
- software_trap54,/*54CAN4receive*/
- software_trap53,/*53CAN4errors*/
- software_trap52,/*52CAN4wake-up*/
- software_trap51,/*51CAN3transmit*/
- software_trap50,/*50CAN3receive*/
- software_trap49,/*49CAN3errors*/
- software_trap48,/*48CAN3wake-up*/
- software_trap47,/*47CAN2transmit*/
- software_trap46,/*46CAN2receive*/
- software_trap45,/*45CAN2errors*/
- software_trap44,/*44CAN2wake-up*/
- software_trap43,/*43CAN1transmit*/
- software_trap42,/*42CAN1receive*/
- software_trap41,/*41CAN1errors*/
- software_trap40,/*40CAN1wake-up*/
- software_trap39,/*39CAN0transmit*/
- software_trap38,/*38CAN0receive*/
- software_trap37,/*37CAN0errors*/
- software_trap36,/*36CAN0wake-up*/
- software_trap35,/*35FLASH*/
- software_trap34,/*34EEPROM*/
- software_trap33,/*33SPI2*/
- software_trap32,/*32SPI1*/
- software_trap31,/*31IICBus*/
- software_trap30,/*30BDLC*/
- software_trap29,/*29CRGSelfClockMode*/
- software_trap28,/*28CRGPLLlock*/
- software_trap27,/*27PulseAccumulatorBOverflow*/
- software_trap26,/*26ModulusDownCounterunderflow*/
- software_trap25,/*25PortH*/
- software_trap24,/*24PortJ*/
- software_trap23,/*23ATD1*/
- software_trap22,/*22ATD0*/
- SCI1_ISR,/*21SC11*/
- SCI0_ISR,/*20SCI0*/
- software_trap19,/*19SPI0*/
- software_trap18,/*18Pulseaccumulatorinputedge*/
- software_trap17,/*17PulseaccumulatorAoverflow*/
- software_trap16,/*16EnhancedCaptureTimerOverflow*/
- software_trap15,/*15EnhancedCaptureTimerchannel7*/
- software_trap14,/*14EnhancedCaptureTimerchannel6*/
- software_trap13,/*13EnhancedCaptureTimerchannel5*/
- software_trap12,/*12EnhancedCaptureTimerchannel4*/
- software_trap11,/*11EnhancedCaptureTimerchannel3*/
- software_trap10,/*10EnhancedCaptureTimerchannel2*/
- software_trap09,/*09EnhancedCaptureTimerchannel1*/
- software_trap08,/*08EnhancedCaptureTimerchannel0*/
- OSTickISR,/*07RealTimeInterrupt*/
- software_trap06,/*06IRQ*/
- software_trap05,/*05XIRQ*/
- OSCtxSw,/*04SWI-BreakpointonHCS12SerialMon.*/
- software_trap03,/*03Unimplementedinstructiontrap*/
- software_trap02,/*02COPfailurereset*/
- software_trap01//,/*01Clockmonitorfailreset*/
- //_Startup/*00Resetvector*/
- };
后記:
當我完成全部移植工作并測試通過后,我又重新審視了一遍整個移植過程,發(fā)現(xiàn)走了許多彎路。這些彎路基本都是因為我對C編譯器的特性,尤其是內聯(lián)匯編的處理不熟悉造成的。比如中斷處理函數(shù),其實可以直接寫到 OS_CPU_C.C 中。就可以省略了 vector.c 文件了。其實我一開始也是這樣做的,但是最初的中斷處理函數(shù)混合了C 語句和匯編語句,產(chǎn)生了各種莫名奇妙的錯誤。比如下面的RTI中斷處理函數(shù)代碼:
- interruptVectorNumber_VrtivoidOSTickISR(void)
- {
- OSIntNesting++;//4~,NotifyuC/OS-IIaboutISR
- if(OSIntNesting==1)
- {
- __asm
- {
- ldxOSTCBCur//3~,OSTCBCur->OSTCBStkPtr=StackPointer
- sts0,x//3~,}
- }
- }
- CRGFLG_RTIF=1;//clearinterruptflag.
- OSTimeTick();//6~+,CalluC/OS-IIstickupdatingfunction
- OSIntExit();//6~+,NotifyuC/OS-IIaboutendofISR
- }
對比后來的匯編代碼,其實已經(jīng)離成功很近了,只要將其中的C 語句全部用匯編寫成來大功告成了:
- interruptVectorNumber_VrtivoidOSTickISR(void)
- {
- __asm
- {
- incOSIntNesting
- ldabOSIntNesting
- cmpb#$01
- bneOSTickISR1
- ldxOSTCBCur
- sts0,x
- OSTickISR1:
- BSET_CRGFLG,#128
- jsrOSTimeTick
- jsrOSIntExit
- }
- }
其他的代碼也一樣,都這樣改寫后就完全不需要 vector.c 文件了。但這里還是將這些本可以省略掉的代碼保留下來了,是想記錄下一條真實的探索路程。
評論