日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

UC/OS-II的詳細移植筆記 兩種處理器的移植比較(S1C33209&&S3C44BOX)

 xuhex 2012-02-18
UC/OS-II的詳細移植筆記 兩種處理器的移植比較(S1C33209&&S3C44BOX) [原創(chuàng) 2007-05-20 23:03:21]  
我頂 字號:

UC/OS-II的移植步驟分析

                                             zqcumt    07-4-15

關(guān)于UC/OS-II的移植網(wǎng)上介紹的已經(jīng)很多了,比較流行的幾款處理器(例如ARM)在網(wǎng)上都可以直接下載移植好的代碼。由于最近選修了一門嵌入式系統(tǒng)的課,用的處理器是EPSON公司的S1C33系列,做實驗的時候要進行操作系統(tǒng)的移植,這個周末花了一天半的時間學習了一下,因為畢業(yè)設(shè)計的時候做過ARM上的移植,于是將兩者比較了一下,給出一般的移植要點。由于將來實驗還要設(shè)計到GUI的移植以及文件系統(tǒng)的移植和網(wǎng)絡(luò)協(xié)議的移植,我會將自己的學習筆記都記錄下來。

大家下載到源碼后,針對Intel 80x86的代碼在uCOS-II\Ix86L目錄下。代碼是80x86實模式,且在編譯器大模式下編譯的。移植部分的代碼可在下述文件中找到:OS_CPU.H, OS_CPU_C.C, OS_CPU_A.ASM。大家可以參考這個例子,對它進行修改。

INCLUDES.H 是主頭文件,在所有后綴名為.C的文件的開始都包含INCLUDES.H文件。使用INCLUDES.H的好處是所有的.C文件都只包含一個頭文件,程序簡潔,可讀性強。缺點是.C文件可能會包含一些它并不需要的頭文件,額外的增加編譯時間。與優(yōu)點相比,多一些編譯時間還是可以接受的。用戶可以改寫INCLUDES.H文件,增加自己的頭文件,但必須加在文件末尾。

///////////////////////////////////////////////////////////////////////////////

一、(1)OS_CPU.H文件的移植 (針對S1C33209)

//////////////////////////////////////////////////////////////////////////

OS_CPU.H 文件中包含與處理器相關(guān)的常量,宏和結(jié)構(gòu)體的定義。

#ifdef  OS_CPU_GLOBALS

#define OS_CPU_EXT   //全局變量

#else

#define OS_CPU_EXT  extern

#endif

///////////////////////////////////////////////////////////////////////////////

由于不同的處理器有不同的字長,μC/OS-II的移植需要重新定義一系列的數(shù)據(jù)結(jié)構(gòu)。這部分是和處理器相關(guān)的.

typedef unsigned char  BOOLEAN;

typedef unsigned char  INT8U;

typedef signed   char  INT8S;

typedef unsigned short   INT16U;

typedef signed   short   INT16S;

typedef  unsigned int  INT32U;

typedef  signed   int  INT32S;

//因為沒有浮點運算所以刪掉

typedef unsigned int OS_STK;//定義 堆棧的 寬度為 16

typedef unsigned int   OS_CPU_SR;//定義 狀態(tài)寄存器的寬度為16

///////////////////////////////////////////////////////////////////////////////

下面的部分主要是為了和UC/OS 第一版的兼容

#define BYTE           INT8S          

#define UBYTE          INT8U  

#define WORD           INT16S 

#define UWORD          INT16U

#define LONG           INT32S

#define ULONG          INT32U

///////////////////////////////////////////////////////////////////////////////

與其他實時系統(tǒng)一樣,μC/OS-II在進入系統(tǒng)臨界代碼區(qū)之前要關(guān)閉中斷,等到退出臨界區(qū)后再打開。從而保護核心數(shù)據(jù)不被多任務(wù)環(huán)境下的其他任務(wù)或中斷破壞。Borland C/C++支持嵌入?yún)R編語句,所以加入關(guān)閉/打開中斷的語句是很方便的。μC/OS-II定義了兩個宏用來關(guān)閉/打開中斷:OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()。下面定義了三種方法,具體的可以查閱相關(guān)書籍.

//////////////////////////////////////////////////////////////

#define  OS_CRITICAL_METHOD    2 //使用第二種方法

///////////////////////////////////////////////////////////////////////////////

#if      OS_CRITICAL_METHOD == 1 //第一種方法,由于沒有用到,我們不用去修改,可以注釋掉

#define  OS_ENTER_CRITICAL()  asm  CLI

#define  OS_EXIT_CRITICAL()   asm  STI  

#endif

///////////////////////////////////////////////////////////////////////////////

#if      OS_CRITICAL_METHOD == 2 //第二種方法,這個是我們用到的,要修改,一般用匯編寫,根據(jù)各個處理器的不同而不同,下面是S1C33系列的匯編

 

#define  OS_ENTER_CRITICAL() 

asm(" ld.w %r4, %psr");

asm(" xld.w %r5, 0xffffffef");

asm(" and %r4, %r5");//關(guān)中斷,保持狀態(tài)寄存器的其它狀態(tài)不變

asm(" ld.w %psr, %r4"); 

             

#define  OS_EXIT_CRITICAL()

asm(" ld.w %r4, %psr");

asm(" or %r4, 0b10000");

asm(" ld.w %psr, %r4"); //開中斷,保持狀態(tài)寄存器的其它狀態(tài)不變

#endif

///////////////////////////////////////////////////////////////////////////////

#if     OS_CRITICAL_METHOD == 3  //第三種方法,由于沒有用到,我們不用去修改,可以直接注視掉

 

#define  OS_ENTER_CRITICAL()

  (cpu_sr = OSCPUSaveSR()) 

#define  OS_EXIT_CRITICAL()

  (OSCPURestoreSR(cpu_sr))   

#endif

///////////////////////////////////////////////////////////////////////////

#define  OS_STK_GROWTH        1     //堆棧的增長方向,由高相低,這個也是和處理器相關(guān)的,有的處理器堆棧是由低向高變,只要定義為零即可

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

μC/OS-II, 就緒任務(wù)的堆棧初始化應(yīng)該模擬一次中斷發(fā)生后的樣子,堆棧中應(yīng)該按進棧次序設(shè)置好各個寄存器的內(nèi)容。OS_TASK_SW()函數(shù)模擬一次中斷過程,在中斷返回的時候進行任務(wù)切換。中斷服務(wù)程序(ISR)(也稱為例外處理過程)的入口點必須指向匯編函數(shù)OSCtxSw(),參看文件OS_CPU_A.ASM.在中斷向量表vector.c的代碼中修改向量表如下

    (unsigned long)  OSCtxSw,               // 48   12  software exception 0

///////////////////////////////////////////////////////////////////////

#define  uCOS                 0                    

#define  OS_TASK_SW()   asm(" int 0"); / /使用零號中斷來進行任務(wù)切換

///////////////////////////////////////////////////////////////////////////////

可以注釋掉,主要是用于在PC機上模擬時鐘節(jié)拍

OS_CPU_EXT  INT8U  OSTickDOSCtr;  //全局變量

////////////////////////////////////////////////////////////////////////////

可以注釋掉

#if OS_CRITICAL_METHOD == 3                 

OS_CPU_SR  OSCPUSaveSR(void);

void       OSCPURestoreSR(OS_CPU_SR cpu_sr);

#endif

///////////////////////////////////////////////////////////////////////////////

(2)OS_CPU.H文件的移植 (針對ARM核的S3C44BOX )

///////////////////////////////////////////////////////////////////////////////
typedef unsigned char BOOLEAN;
typedef unsigned char INT8U; /*8
位無符號整數(shù)*/
typedef signed char INT8S; /*8
位有符號整數(shù)*/
typedef unsigned short INT16U; /*16
位有符號整數(shù)*/
typedef signed short INT16S; /*16
位無符號整數(shù)*/
typedef unsigned long INT32U; /*32
位無符號整數(shù)*/
typedef signed long INT32S; /*32
位有符號整數(shù)*/
typedef float FP32; /*
單精度浮點數(shù)*/
typedef double FP64; /*
雙精度浮點數(shù)*/
///////////////////////////////////////////////////////////////////////////
typedef unsigned int OS_STK;/*
堆棧入口寬度為16*/ARM處理器相關(guān)的代碼:

///////////////////////////////////////////////////////////////////////////////

具體的實現(xiàn)見第二步, OS_CPU_A.ASM中實現(xiàn)
#define OS_ENTER_CRITICAL () ARMDisableInt() /*
關(guān)中斷在OS_CPU.A.S中定義,可以參

     考下面的程序*/
#define OS_EXIT_CRITICAL () ARMEnableInt() /*
開啟中斷*/
#define OS_STK_GROWTH 1 /*
堆棧由高地址向低地址增長*/

///////////////////////////////////////////////////////////////////////////////

定義宏OS_TASK_SW(),這個宏實際上被定義為os_CPU_a.s中的函數(shù)OSCtxSw()。由此可以了解OSCtxSw()的任務(wù):保存當前任務(wù)上下文,裝入新任務(wù)上下文。這里并沒有用到模擬軟中斷

#define OS_TASK_SW          OSCtxSw

///////////////////////////////////////////////////////////////////////////////

// Definitions specific to ARM/uHAL

#define SVC32MODE   0x13

//定義空閑任務(wù)堆棧的大小,可以不用定義這部分

#define SEMIHOSTED_STACK_NEEDS 1024

// idle task stack size (words)

#ifdef SEMIHOSTED

#define OS_IDLE_STK_SIZE        (32+SEMIHOSTED_STACK_NEEDS)

#else

#define OS_IDLE_STK_SIZE        32

#endif

 

// defined in os_cpu_a.s 聲明這些函數(shù),在后面都有所定義

extern void OSCtxSw(void);           // task switch routine

extern void OSIntCtxSw(void);           // interrupt context switch

extern void ARMDisableInt(void);        // disable global interrupts

extern void ARMEnableInt(void);         // enable global interrupts

extern void OSTickISR(void);        // timer interrupt routine

///////////////////////////////////////////////////////////////////////////////

二、(1)OS_CPU.A.S文件的移植 (針對S1C33209)

///////////////////////////////////////////////////////////////////////////////

μC/OS-II 的移植需要用戶改寫OS_CPU_A.ASM中的四個函數(shù):

OSStartHighRdy()

OSCtxSw()

OSIntCtxSw()

OSTickISR()

////////////////////////////////////////////////////////////////

該函數(shù)由SStart()函數(shù)調(diào)用,功能是運行優(yōu)先級最高的就緒任務(wù),在調(diào)用OSStart()之前,用戶必須先調(diào)用OSInit(),并且已經(jīng)至少創(chuàng)建了一個任務(wù)(請參考OSTaskCreate()OSTaskCreateExt()函數(shù))。OSStartHighRdy()默認指針OSTCBHighRdy指向優(yōu)先級最高就緒任務(wù)的任務(wù)控制塊(OS_TCB)(在這之前OSTCBHighRdy已由OSStart()設(shè)置好了)。OSTCBHighRdy->OSTCBStkPtr指向的是任務(wù)堆棧的頂端

 

OSStartHighRdy:

 xcall   OSTaskSwHook  //調(diào)用OSTaskSwHook ,此時OSRunningFALSE

ld.w    %r4, 0x1

xld.w    %r5, OSRunning

xld.b   [%r5], %r4  //使OSRunning的狀態(tài)為TRUE ,以后調(diào)用OSTaskSwHook時會先保存寄存器再恢復(fù)

xld.w  %r5, [OSTCBHighRdy];

ld.w   %sp, %r5;//得到最高優(yōu)先級任務(wù)的堆棧指針

xld.w  %r4, [%sp+0x0];

ld.w   %sp, %r4;//偏移量為0

popn   %r15     //恢復(fù)r15-r0,這個是S1C33209的匯編語句

reti;      //返回,此命名執(zhí)行時,處理器會自動恢復(fù)PC和狀態(tài)寄存器的值,至此新任務(wù)

///////////////////////////////////////////////////////////////////////////////

OSCtxSw()是一個任務(wù)級的任務(wù)切換函數(shù)(在任務(wù)中調(diào)用,區(qū)別于在中斷程序中調(diào)用的OSIntCtxSw())。它通過執(zhí)行一條軟中斷的指令來實現(xiàn)任務(wù)切換。軟中斷向量指向OSCtxSw()。在μC/OS-II中,如果任務(wù)調(diào)用了某個函數(shù),而該函數(shù)的執(zhí)行結(jié)果可能造成系統(tǒng)任務(wù)重新調(diào)度(例如試圖喚醒了一個優(yōu)先級更高的任務(wù)),則在函數(shù)的末尾會調(diào)用OSSched(),如果OSSched()判斷需要進行任務(wù)調(diào)度,會找到該任務(wù)控制塊OS_TCB的地址,并將該地址拷貝到OSTCBHighRdy,然后通過宏OS_TASK_SW()執(zhí)行軟中斷進行任務(wù)切換。。注意到在此過程中,變量OSTCBCur始終包含一個指向當前運行任務(wù)OS_TCB的指針。大部分解釋同上,只是多了寄存器的保存這一段。

OSCtxSw:   

xcall   OSTaskSwHook //中斷時,PC和寄存器的值S1C33209處理器已經(jīng)自動保存了

pushn   %r15;// Save current task's context

xld.w   %r4, [OSTCBCur];//指向當前的運行任務(wù)

ld.w    %r5, %sp; Save the SP to R5

ld.w    %sp, %r4;// 保存當前任務(wù)的堆棧指針

ld.w    [%sp+0x0], %r5  ; //Save the SP to OSTCBCur

xld.w   %r4, [OSTCBHighRdy] ; //OSTCBCur = OSTCBHighRdy

xld.w   %r5, OSTCBCur;

ld.w    [%r5], %r4 ;

xld.w    %r4, [OSPrioHighRdy]; //OSPrioCur = OSPrioHighRdy,把任務(wù)優(yōu)先級也保存

xld.w    %r5, OSPrioCur ;

ld.b     [%r5], %r4

xld.w   %r4, [OSTCBCur];//載入新的任務(wù)

ld.w    %sp, %r4

ld.w    %r5, [%sp+0x0];//恢復(fù)新任務(wù)的堆棧

ld.w    %sp, %r5  

popn    %r15   ;

reti  ; //運行新的任務(wù)

///////////////////////////////////////////////////////////////////////////////

μC/OS-II中,由于中斷的產(chǎn)生可能會引起任務(wù)切換,在中斷服務(wù)程序的最后會調(diào)用OSIntExit()函數(shù)檢查任務(wù)就緒狀態(tài),如果需要進行任務(wù)切換,將調(diào)用OSIntCtxSw()。所以OSIntCtxSw()又稱為中斷級的任務(wù)切換函數(shù)。由于在調(diào)用OSIntCtxSw()之前已經(jīng)發(fā)生了中斷,OSIntCtxSw()將默認CPU寄存器已經(jīng)保存在被中斷任務(wù)的堆棧中了。因此在中斷服務(wù)程序中要保存寄存器,PC和狀態(tài)寄存器的值已經(jīng)被處理器自動保存。OSIntCtxSw()大部分程序和OSCtxSw()相同只是不用保存寄存器,它也可直接用OSCtxSw()來實現(xiàn)

OSIntCtxSw:

xcall  OSTaskSwHook   ; //Call user defined task switch hook

xld.w   %r4, [OSTCBHighRdy]   ;// OSTCBCur = OSTCBHighRdy

xld.w   %r5, OSTCBCur ;

ld.w    [%r5], %r4  ;

xld.w   %r4, [OSPrioHighRdy] ; //OSPrioCur = OSPrioHighRdy,把任務(wù)優(yōu)先級也保存

xld.w   %r5, OSPrioCur  ;

ld.b    [%r5], %r4

xld.w   %r4, [OSTCBCur]  //載入新的任務(wù)

ld.w    %sp, %r4

ld.w    %r5, [%sp+0x0]

ld.w    %sp, %r5       

popn    %r15                              ;

reti     //Return to new task

///////////////////////////////////////////////////////////////////////////////

μC/OS-II中的其他中斷服務(wù)程序一樣,OSTickISR()首先在被中斷任務(wù)堆棧中保存CPU寄存器的值,然后調(diào)用OSIntEnter()。μC/OS-II要求在中斷服務(wù)程序開頭調(diào)用OSIntEnter(),其作用是將記錄中斷嵌套層數(shù)的全局變量OSIntNesting1。如果不調(diào)用OSIntEnter(),直接將OSIntNesting1也是允許的。OSTickISR()調(diào)用OSTimeTick(),檢查所有處于延時等待狀態(tài)的任務(wù),判斷是否有延時結(jié)束就緒的任務(wù)。OSTickISR()的最后調(diào)用OSIntExit(),如果在中斷中(或其他嵌套的中斷)有更高優(yōu)先級的任務(wù)就緒,并且當前中斷為中斷嵌套的最后一層。OSIntExit()將進行任務(wù)調(diào)度。注意如果進行了任務(wù)調(diào)度,OSIntExit()將不再返回調(diào)用者,而是用新任務(wù)的堆棧中的寄存器數(shù)值恢復(fù)CPU現(xiàn)場,然后用IRET實現(xiàn)任務(wù)切換。如果當前中斷不是中斷嵌套的最后一層,或中斷中沒有改變?nèi)蝿?wù)的就緒狀態(tài),OSIntExit()將返回調(diào)用者OSTickISR(),最后OSTickISR()返回被中斷的任務(wù)。如果編譯器支持C語言和匯編的混合編程,則這段代碼可以放到OS_CPU_C.C中,針對S1C33209的移植這部分放在OS_CPU_C.C中。為了連續(xù)性就在這里順便寫吧。

void OSTickISR()

{   asm( " pushn %r15");//保存中斷的任務(wù)的寄存器

///////////////////////////////////////////////////////////////////////////////

在這個移植中以8位定時器TIME2 作為時鐘節(jié)拍,2MS發(fā)生一次中斷,在中斷向量表vector.c 中在timer2的入口地址處放入(unsigned long)OSTickISR,   發(fā)生中斷后程學將會跳到此程序處執(zhí)行。

*(volatile unsigned char*)0x40285 |= 0x04;   // 清除timer2的中斷標志位

    OSIntEnter();//處理中斷嵌套曾數(shù)的增加也可以直接 給OSIntNesting加一

        if (OSIntNesting == 1) {

      asm(" ld.w %r4, %sp");//如果嵌套層數(shù)為1 則在當前的任務(wù)控制塊中保存堆棧指針

            asm(" xld.w %r10, [OSTCBCur]");

            asm(" ld.w %sp, %r10");

            asm(" ld.w [%sp+0x0], %r4");

            asm(" ld.w %sp, %r4");

         }

    OSTimeTick();    // 給等待延遲時間的任務(wù)的參數(shù)減1

OSIntExit(); //調(diào)用這個函數(shù),如果ISR使更高優(yōu)先級的任務(wù)進入就緒態(tài)或者ISR脫離

             // 了中斷嵌套,則此函數(shù)不會返回,而是由進行中斷級任務(wù)切換,否

//此函數(shù)返回OSTickISR,然后恢復(fù)寄存器

    asm(" popn %r15");//恢復(fù)寄存器

    asm(" reti");//返回中斷的任務(wù)繼續(xù)運行

}

///////////////////////////////////////////////////////////////////////////////

為了更清楚一點這里面的過程,順便付上這里用到TIMER2 的程序,最好有個感性的認識

這部分程序應(yīng)該在驅(qū)動程序里或者放在初始化程序里。始終節(jié)拍中斷的啟動(定時器2的啟動)應(yīng)該放在OSStart()運行之后,但是OSStart()不會返回,所以應(yīng)該放在OSStart()之前建立的任務(wù)中的優(yōu)先級最高的任務(wù)中啟動,如果放在 OSInit()OSStart() 之間啟動,程序容易崩潰。

/* Prototype */

void init_timer(void);

void Start_Timer(void);

/////////////////////////////////////////////////////////////////////////////

定時器2 的初始化,完成定時時間等一下設(shè)置,每隔2ms發(fā)生一次的中斷

void init_timer(void)

{

*(volatile unsigned char *)0x4014E |= 0x0F;

*(volatile unsigned char *)0x40169 = 0x92;/

*(volatile unsigned char *)0x40168 |= 0x02;

*(volatile unsigned char *)0x40285 &= 0xFB;

*(volatile unsigned char *)0x40275 |= 0x04;

}

///////////////////////////////////////////////////////////////////////////////

啟動定時器2

void Start_Timer(void)

{

    *(volatile unsigned char*)0x40168 |= 0x01;

}

//////////////////////////////////////////////////////////////////////////////

(2)OS_CPU.A.S文件的移植 (針對ARM核的S3C44BOX )

/////////////////////////////////////////////////////////////////////////////

μC/OS-II 的移植需要用戶改寫OS_CPU_A.ASM中的四個函數(shù):

OSStartHighRdy()

OSCtxSw()

OSIntCtxSw()

OSTickISR()

同時對于ARM的開關(guān)中斷(ARMEnableInt,ARMDisableInt的定義也是放在這個文件下的

關(guān)于ARM的程序就不用解釋那么清楚了,相信英文大家都能看懂,也可以參考上面的程序?qū)崿F(xiàn)的功能都是相同的

///////////////////////////////////////////////////////////////////////////////

EXPORT OSStartHighRdy

    IMPORT  OSTaskSwHook

    IMPORT  OSTCBHighRdy

    IMPORT  OSRunning

OSStartHighRdy

        BL OSTaskSwHook       //Call user-defined hook function

 

        LDR     r4,=OSRunning     // Indicate that multitasking has started

        MOV     r5, #1                  

        STRB    r5, [r4]        // OSRunning = true

 

        LDR     r4, =OSTCBHighRdy      // Get highest priority task TCB address

        LDR     r4, [r4]               // get stack pointer

        LDR     sp, [r4]              // switch to the new stack

LDMFD   sp!, {r4}         ;// CPSR特殊,只能用MRSMSR在寄存器間操作

        MSR     cpsr_cxsf, r4            //r4中恢復(fù)cpsr

///////////////////////////////////////////////////////////////////////////////SVC模式下ARM處理器不會自動保存PC的所以需要自己保存和恢復(fù)

        LDMFD   sp!, {r0-r12,lr,pc}      ; pop new task s r0-r12,lr & pc

///////////////////////////////////////////////////////////////////////////////

        EXPORT OSCtxSw             //這個函數(shù)別的文件要用

        IMPORT  OSPrioCur           //這是在別的文件定義的變量,當前任務(wù)優(yōu)先級

        IMPORT  OSPrioHighRdy      //將要恢復(fù)執(zhí)行的任務(wù)的優(yōu)先級

        IMPORT  OSTCBCur           //當前任務(wù)的TCB的指針

        IMPORT  OSTaskSwHook       //調(diào)用用戶定義HOOK

        IMPORT  OSTCBHighRdy       //將要恢復(fù)執(zhí)行的任務(wù)的TCB指針

 OSCtxSw

        STMFD sp!, {lr}      // push pc (lr is actually be pushed in place of PC) 因為是從OS_Sched() BL到這里的

        STMFD   sp!, {r0-r12,lr}       // push lr & register file

        MRS     r4, cpsr               // CPSR特殊只能用MRSMSR在寄存器間操作

        STMFD   sp!, {r4}             // push current psr      

        LDR     r4, =OSTCBCur          // Get current task TCB address

        LDR     r5, [r4]

        STR     sp, [r5]                // store sp in preempted tasks s TCB

/////////////////////////////////////////////////////////////////////////////

    以下程序段和OSIntCtxSw相同,可以共用一段   

BL    OSTaskSwHook               // call Task Switch Hook

       LDR r5, =OSTCBHighRdy       // 得到就緒任務(wù)中的最高優(yōu)先級的任務(wù)

       LDR  r5, [r5]

       STR   r5, [r4]         //使當前任務(wù)指針指向最高優(yōu)先級的任務(wù)

OSTCBCur = OSTCBHighRdy

       LDR r6, =OSPrioHighRdy      

       LDRB     r6, [r6]

       LDR r4, =OSPrioCur          

       STRB     r6, [r4]                //保存優(yōu)先級到當前的優(yōu)先級

       LDR sp, [r5]                //get new task s stack pointer

       LDMFD    sp!, {r4}                //pop new task cpsr

       MSR cpsr_cxsf, r4

LDMFD     sp!, {r0-r12,lr,pc}      //切換到新的任務(wù)

 ///////////////////////////////////////////////////////////////////////////////

關(guān)于OSIntCtxSw()就是上面那下半截。這是因為:ARM硬件的中斷時并不自動壓棧任何寄存器,所以免去了恢復(fù)堆棧指針的麻煩;另外,我們最好在進入ISR保存當前任務(wù)現(xiàn)場時一同保存好TCB中的堆棧指針,而不是在OSIntCtxSw()中保存。具體的解釋也可以參考上面這里只是用的寄存器不同而已。

IMPORT OSTaskSwHook

OSIntCtxSw

        BL      OSTaskSwHook     //調(diào)用OSTaskSwHook函數(shù)

        LDR     r4, =OSTCBHighRdy  //得到當前最高優(yōu)先級就緒的任務(wù)

        LDR     r4, [r4]

        LDR     r5, =OSTCBCur

        STR     r4, [r5]            // OSTCBCur = OSTCBHighRdy

        LDR     r6, =OSPrioHighRdy

        LDRB    r6, [r6]

        LDR     r5, =OSPrioCur

        STRB    r6, [r5]                // OSPrioCur = OSPrioHighRdy

        LDR     sp, [r4]           //得到新任務(wù)的堆棧指針

        LDMFD   sp!, {r4}           // pop new task cpsr

        MSR     cpsr_cxsf, r4

LDMFD   sp!, {r0-r12,lr,pc}      //切換到新的任務(wù)

///////////////////////////////////////////////////////////////////////////////

這是 UCOS-II 搶占式調(diào)度ISR的一個標本。當一個優(yōu)先級高的任務(wù)放棄CPU使用權(quán),例如要休眠 10 個 Tick,系統(tǒng)調(diào)度一個低優(yōu)先級的任務(wù)執(zhí)行之。OSTickISR()為休眠的任務(wù)計時,每次執(zhí)行,就把休眠任務(wù)剩余的睡覺時間減去一個Tick數(shù)。如果發(fā)現(xiàn)一個任務(wù)睡夠了,就順便恢復(fù)它為READY態(tài)。做完該做的一切,一個對OSIntExit()的調(diào)用,使調(diào)度發(fā)生了。

EXPORT OSTickISR

    IMPORT  OSIntEnter

    IMPORT  OSTimeTick

    IMPORT  tick_hook  

    IMPORT  OSIntExit

///////////////////////////////////////////////////////////////////////////////

注意ARMIRQ中斷發(fā)生后的PC保存(處理器自動保存LR=PC+4),而不是前面的PCLR。另外,我們保存的是SVC模式下的現(xiàn)場,中斷后處理器進入IRQ模式,訪問不到SVC模式下的R13(sp),于是在IRQ模式下,只好先另存SPSRLR,然后盡快退回到SVC模式,這時的R13才是任務(wù)的堆棧指針。在此模式下再將SPSRLR保存到堆棧中,立即保存所有寄存器。任務(wù)是在SVC模式下運行。關(guān)于時鐘節(jié)拍怎么實現(xiàn)的(如果不是很懂就看下一篇文章關(guān)于ARM中斷處理的詳細分析)。

LINK_SAVE   DCD     0    //申請一個字單元用0來初始化這個字

PSR_SAVE    DCD     0    //地址為LINK_SAVE+4

OSTickISR

    STMFD   sp!, {r4}              //這里的spIRQ 模式下的,將r4壓入堆棧

///////////////////////////////////////////////////////////////////////////

另存IRQ模式下的SPSRLR,以便在SVC模式下也能訪問,相當于一個中介作用

    LDR     r4, =LINK_SAVE

    STR     lr, [r4]                //LINK_SAVE = lr,保存lr,lrIRQ模式下

    MRS     lr, spsr                //lr=spsr

    STR     lr, [r4, #4]            // PSR_SAVE = spsr_irq,保存spsr

////////////////////////////////////////////////////////////////////////////

    LDMFD   sp!, {r4}                 //恢復(fù)r4中的內(nèi)容

    ORR     lr, lr, #0x80   // Mask irq for context switching before

    MSR cpsr_cxsf , lr      // IRQ模式恢復(fù)到SVC模式

////////////////////////////////////////////////////////////////////////////

    SUB     sp, sp, #4          // Space forPC保留位置

    STMFD   sp!, {r0-r12, lr}   //保存寄存器和lr

    LDR     r4, =LINK_SAVE     //r4= lr_irq

    LDR     lr, [r4, #0]        //lr=lr_irq

    SUB     lr, lr, #4              // PC = LINK_SAVE - 4,這個一定要正確

///////////////////////////////////////////////////////////////////////////////

  PC= LR4存回到堆棧中,剛才跳過了PC 4字節(jié)的空間 (R1R12再加lr共占了14個字)

    STR     lr, [sp, #(14*4)]   //sp=sp+14*4, 因為堆棧是從高地址向低地址遞減

                                    PC=LR -4

    LDR     r4, [r4, #4]            // r4 = PSR_SAVE,

    STMFD   sp!, {r4}              // save CPSR of the task

    LDR     r4, =OSTCBCur   //sp保存到當前的任務(wù)中

    LDR     r4, [r4]

    STR     sp, [r4]                // OSTCBCur -> stkptr = sp 

         BL    OSIntEnter  //處理中斷嵌套曾數(shù)的增加也可以直接 給OSIntNesting加一

    BL OSTimeTick            //調(diào)用ostimetick()

    BL  tick_hook       // 我們在Tick_hook()里清除S3C44B0xTick_Int_Pend                        函數(shù)在main.c里,是另加的

    BL  OSIntExit        //決定是否進行任務(wù)調(diào)度

/////////////////////////////////////////////////////////////////////////////

 如果返回則繼續(xù)運行此任務(wù)

    LDMFD   sp!, {r4}             //pop new task cpsr

    MSR     cpsr_cxsf, r4

    LDMFD   sp!, {r0-r12,lr,pc}     // pop new task r0-r12,lr & pc

///////////////////////////////////////////////////////////////////////////////

定義關(guān)中斷,主要是為了安全訪問臨界區(qū)的資源

 EXPORT     ARMDisableInt

ARMDisableInt

    MRS r0, cpsr

    STMFD   sp!, {r0}         // push current PSR

    ORR r0, r0, #0xC0

    MSR cpsr_c, r0      //disable IRQ Int s

    MOV pc, lr        //返回

///////////////////////////////////////////////////////////////////////////////

定義開中斷

    EXPORT ARMEnableInt

ARMEnableInt

    LDMFD   sp!, {r0}           // pop current PSR

    MSR cpsr_c, r0             //restore original cpsr 

    MOV pc, lr       //返回

///////////////////////////////////////////////////////////////////////////////

三、(1)OS_CPU.C.C文件的移植 (針對S1C33209)

///////////////////////////////////////////////////////////////////////////////

μC/OS-II 的移植需要用戶改寫OS_CPU_C.C中的六個函數(shù):

OSTaskStkInit()

OSTaskCreateHook()

OSTaskDelHook()

OSTaskSwHook()

OSTaskStatHook()

OSTimeTickHook()

實際需要修改的只有OSTaskStkInit()函數(shù),其他五個函數(shù)需要聲明,但不一定有實際內(nèi)容。這五個函數(shù)都是用戶定義的,所以OS_CPU_C.C中沒有給出代碼。如果用戶需要使用這些函數(shù),請將文件OS_CFG.H中的#define constant OS_CPU_HOOKS_EN設(shè)為1,設(shè)為0表示不使用這些函數(shù)。

///////////////////////////////////////////////////////////////////////////////

這個函數(shù)是很重要的 ,該函數(shù)由OSTaskCreate()OSTaskCreateExt()調(diào)用,用來初始化任務(wù)的堆棧。初始狀態(tài)的堆棧模擬發(fā)生一次中斷后的堆棧結(jié)構(gòu)。當調(diào)用OSTaskCreate()OSTaskCreateExt()創(chuàng)建一個新任務(wù)時,需要傳遞的參數(shù)是:任務(wù)代碼的起使地址,參數(shù)指針(pdata),任務(wù)堆棧頂端的地址,任務(wù)的優(yōu)先級。OSTaskCreateExt()還需要一些其他參數(shù),但與OSTask­StkInit()沒有關(guān)系。OSTaskStkInit()只需要以上提到的3個參數(shù)(task, pdata,ptos)。在這個堆棧初始化函數(shù)中要清楚堆棧中都要保存哪些東西,要留多大的空間,這些都很重要,否則會發(fā)生很嚴重的錯誤。

 

OS_STK  *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)

{

    INT32U *stk;   //定義一個指針

    opt    = opt;    /* 這個參數(shù)沒有用,但是為了防止編譯錯誤*/

stk    = (INT32U*)ptos;                 //載入堆棧指針

///////////////////////////////////////////////////////////////////////////

S1c33處理器是在入棧時,先變化sp,再向當前的sp指向的地址寫入數(shù)據(jù)。出棧時是先彈出數(shù)據(jù),再變化sp

*stk-- = (INT32U)task;           //存放PC的地址,s1c33209 的處理器會自動保存

////////////////////////////////////////////////////////////////////////////

存放狀態(tài)寄存器,同樣也會被自動保存,設(shè)置為中斷開啟 參考其PSR每位的作用。如果選擇任務(wù)啟動后允許中斷發(fā)生,則所有的任務(wù)運行期間中斷都允許;同樣,如果選擇任務(wù)啟動后禁止中斷,則所有的任務(wù)都禁止中斷發(fā)生,而不能有所選擇。知道為什么嗎?因為啟動的時候,OSStart()調(diào)用的是 OSStartHighRdy,即從堆棧中恢復(fù)PCSPR以及寄存器中的內(nèi)容,因此第一次堆棧中的放的值決定了spr,其它寄存器的值到?jīng)]有什么關(guān)系。

 

*stk-- = (INT32U)0x00000010;    

*stk-- = (INT32U)0;   //R15中的值

*stk-- = (INT32U)0;   //--R14

*stk-- = (INT32U)0;   //--R13

    *stk-- = (INT32U)0;   //--R12

    *stk-- = (INT32U)0;   //--R11

    *stk-- = (INT32U)0;   //--R10

    *stk-- = (INT32U)0;   //--R9

*stk-- = (INT32U)0;   //--R8

*stk-- = (INT32U)0;   //--R7

*stk-- = (INT32U)0;   //--R6

*stk-- = (INT32U)0;   //--R5

*stk-- = (INT32U)0;   //--R4

*stk-- = (INT32U)0;   //--R3

*stk-- = (INT32U)0;   //--R2

*stk-- = (INT32U)0;   //--R1

    *stk   = (INT32U)0;   //--R0   

    return ((OS_STK *)stk);       //返回堆棧指針所指向的地址,恢復(fù)寄存器時候要用

}

///////////////////////////////////////////////////////////////////////////////

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多