小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

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

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

大家下載到源碼后,針對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 文件中包含與處理器相關的常量,宏和結構體的定義。

#ifdef  OS_CPU_GLOBALS

#define OS_CPU_EXT   //全局變量

#else

#define OS_CPU_EXT  extern

#endif

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

由于不同的處理器有不同的字長,μC/OS-II的移植需要重新定義一系列的數據結構。這部分是和處理器相關的.

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

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

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

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

#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 //第二種方法,這個是我們用到的,要修改,一般用匯編寫,根據各個處理器的不同而不同,下面是S1C33系列的匯編

 

#define  OS_ENTER_CRITICAL() 

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

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

asm(" and %r4, %r5");//關中斷,保持狀態(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     //堆棧的增長方向,由高相低,這個也是和處理器相關的,有的處理器堆棧是由低向高變,只要定義為零即可

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

μC/OS-II, 就緒任務的堆棧初始化應該模擬一次中斷發(fā)生后的樣子,堆棧中應該按進棧次序設置好各個寄存器的內容。OS_TASK_SW()函數模擬一次中斷過程,在中斷返回的時候進行任務切換。中斷服務程序(ISR)(也稱為例外處理過程)的入口點必須指向匯編函數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"); / /使用零號中斷來進行任務切換

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

可以注釋掉,主要是用于在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
位無符號整數*/
typedef signed char INT8S; /*8
位有符號整數*/
typedef unsigned short INT16U; /*16
位有符號整數*/
typedef signed short INT16S; /*16
位無符號整數*/
typedef unsigned long INT32U; /*32
位無符號整數*/
typedef signed long INT32S; /*32
位有符號整數*/
typedef float FP32; /*
單精度浮點數*/
typedef double FP64; /*
雙精度浮點數*/
///////////////////////////////////////////////////////////////////////////
typedef unsigned int OS_STK;/*
堆棧入口寬度為16*/ARM處理器相關的代碼:

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

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

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

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

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

#define OS_TASK_SW          OSCtxSw

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

// Definitions specific to ARM/uHAL

#define SVC32MODE   0x13

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

#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 聲明這些函數,在后面都有所定義

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中的四個函數:

OSStartHighRdy()

OSCtxSw()

OSIntCtxSw()

OSTickISR()

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

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

 

OSStartHighRdy:

 xcall   OSTaskSwHook  //調用OSTaskSwHook ,此時OSRunningFALSE

ld.w    %r4, 0x1

xld.w    %r5, OSRunning

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

xld.w  %r5, [OSTCBHighRdy];

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

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

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

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

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

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

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

OSCtxSw:   

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

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

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

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

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

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,把任務優(yōu)先級也保存

xld.w    %r5, OSPrioCur ;

ld.b     [%r5], %r4

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

ld.w    %sp, %r4

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

ld.w    %sp, %r5  

popn    %r15   ;

reti  ; //運行新的任務

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

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

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,把任務優(yōu)先級也保存

xld.w   %r5, OSPrioCur  ;

ld.b    [%r5], %r4

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

ld.w    %sp, %r4

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

ld.w    %sp, %r5       

popn    %r15                              ;

reti     //Return to new task

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

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

void OSTickISR()

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

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

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

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

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

        if (OSIntNesting == 1) {

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

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

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

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

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

         }

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

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

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

//此函數返回OSTickISR,然后恢復寄存器

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

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

}

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

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

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

/* Prototype */

void init_timer(void);

void Start_Timer(void);

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

定時器2 的初始化,完成定時時間等一下設置,每隔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中的四個函數:

OSStartHighRdy()

OSCtxSw()

OSIntCtxSw()

OSTickISR()

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

關于ARM的程序就不用解釋那么清楚了,相信英文大家都能看懂,也可以參考上面的程序實現的功能都是相同的

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

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中恢復cpsr

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

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

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

        EXPORT OSCtxSw             //這個函數別的文件要用

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

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

        IMPORT  OSTCBCur           //當前任務的TCB的指針

        IMPORT  OSTaskSwHook       //調用用戶定義HOOK

        IMPORT  OSTCBHighRdy       //將要恢復執(zhí)行的任務的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       // 得到就緒任務中的最高優(yōu)先級的任務

       LDR  r5, [r5]

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

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}      //切換到新的任務

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

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

IMPORT OSTaskSwHook

OSIntCtxSw

        BL      OSTaskSwHook     //調用OSTaskSwHook函數

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

        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]           //得到新任務的堆棧指針

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

        MSR     cpsr_cxsf, r4

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

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

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

EXPORT OSTickISR

    IMPORT  OSIntEnter

    IMPORT  OSTimeTick

    IMPORT  tick_hook  

    IMPORT  OSIntExit

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

注意ARMIRQ中斷發(fā)生后的PC保存(處理器自動保存LR=PC+4),而不是前面的PCLR。另外,我們保存的是SVC模式下的現場,中斷后處理器進入IRQ模式,訪問不到SVC模式下的R13(sp),于是在IRQ模式下,只好先另存SPSRLR,然后盡快退回到SVC模式,這時的R13才是任務的堆棧指針。在此模式下再將SPSRLR保存到堆棧中,立即保存所有寄存器。任務是在SVC模式下運行。關于時鐘節(jié)拍怎么實現的(如果不是很懂就看下一篇文章關于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}                 //恢復r4中的內容

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

    MSR cpsr_cxsf , lr      // IRQ模式恢復到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保存到當前的任務中

    LDR     r4, [r4]

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

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

    BL OSTimeTick            //調用ostimetick()

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

    BL  OSIntExit        //決定是否進行任務調度

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

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

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

    MSR     cpsr_cxsf, r4

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

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

定義關中斷,主要是為了安全訪問臨界區(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中的六個函數:

OSTaskStkInit()

OSTaskCreateHook()

OSTaskDelHook()

OSTaskSwHook()

OSTaskStatHook()

OSTimeTickHook()

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

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

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

 

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

{

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

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

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

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

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

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

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

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

 

*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ā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多