固定任務(wù)間的切換

正式開(kāi)始編寫(xiě)操作系統(tǒng),雖然只是實(shí)現(xiàn)兩個(gè)固定任務(wù)間的切換,但是它改變了正常C程序的工作流程,完成了無(wú)操作系統(tǒng)到有操作系統(tǒng)的跨越。

程序切換原理

函數(shù)一運(yùn)行
   保存函數(shù)一寄存器組
   恢復(fù)函數(shù)二寄存器組
函數(shù)二運(yùn)行
   保存函數(shù)二寄存器組
   恢復(fù)函數(shù)一寄存器組
函數(shù)一運(yùn)行

上述過(guò)程就是人物切換過(guò)程,既上下文切換(context switch)。任務(wù)切換就是操作系統(tǒng)不停備份、恢復(fù)任務(wù)寄存器的過(guò)程。
不同的函數(shù)需要不同的棧來(lái)備份,不然函數(shù)數(shù)據(jù)就會(huì)互相破壞,在進(jìn)行函數(shù)切換的時(shí)候也要做棧的切換,這里只使用MSP,但是使MSP指向不同的棧空間實(shí)現(xiàn)對(duì)多個(gè)棧的處理。

程序切換運(yùn)行流程

1.定義TCB塊
TCB是task control block的簡(jiǎn)稱(chēng),意為任務(wù)控制塊,與任務(wù)的相關(guān)信息會(huì)保存在TCB里。
在這里TCB保存著任務(wù)的任務(wù)棧寄存器組。既TCB里保存著Stackreg

2.定義STACKREG結(jié)構(gòu)

typedef struct stackreg
{
    U32 stackR4;
    U32 stackR5;
    U32 stackR6;
    U32 stackR7;
    U32 stackR8;
    U32 stackR9;
    U32 stackR10;
    U32 stackR11;
    U32 stackR12;
    U32 stackSP;
    U32 stackLR;
    U32 stackXPSR;
}STACKREG;

保存R4-R12、SP、LR、XPSR。

3.初始化任務(wù)函數(shù)

L_TCB* LOS_TaskInit(VFUNC vfFuncPointer, U32* puiTaskStack)
{
    L_TCB* pstrTcb;              
    STACKREG* pstrStackReg;  

    pstrTcb=(L_TCB*)((U32)puiTaskStack - sizeof(L_TCB));   

    /*  */
    pstrStackReg = &pstrTcb->strStackReg;

    pstrStackReg->stackR4 = 0;                     /* R4 */
    pstrStackReg->stackR5 = 0;                     /* R5 */
    pstrStackReg->stackR6 = 0;                     /* R6 */
    pstrStackReg->stackR7 = 0;                     /* R7 */
    pstrStackReg->stackR8 = 0;                     /* R8 */
    pstrStackReg->stackR9 = 0;                     /* R9 */
    pstrStackReg->stackR10 = 0;                    /* R10 */
    pstrStackReg->stackR11 = 0;                    /* R11 */
    pstrStackReg->stackR12 = 0;                    /* R12 */
    pstrStackReg->stackSP = (U32)pstrTcb;          
    pstrStackReg->stackLR = (U32)vfFuncPointer;   
    pstrStackReg->stackXPSR = MODE_USR;            /* XPSR  */

    return pstrTcb;
}

整個(gè)函數(shù)的目的是改變puitaskstack指向地址里的值(TCB塊) ,開(kāi)辟pstrTcb指向puiTaskStack,pstrStackReg指向pstrTcb里的寄存器制字段,
將pstrStackReg里的所有寄存器初始化,SP存儲(chǔ)運(yùn)行時(shí)的棧地址既pstrTcb,LR保存程序的任務(wù)入口地址,XPSR存儲(chǔ)運(yùn)行狀態(tài)初始為空

4.任務(wù)開(kāi)始函數(shù)
此時(shí)測(cè)試函數(shù)已經(jīng)初始化兩個(gè)任務(wù)完畢,但是兩個(gè)任務(wù)不會(huì)互相切換。使
用該函數(shù)得到下一個(gè)運(yùn)行的函數(shù)的TCB從而跳轉(zhuǎn),開(kāi)始任務(wù)調(diào)度

void LOS_TaskStart(void)
{
    STACKREG* pstrNextTaskStackRegAddr;

    /* 即將運(yùn)行任務(wù)寄存器地址 */
    pstrNextTaskStackRegAddr = &gpstrTask1Tcb->strStackReg;

    /* 下次調(diào)度任務(wù)flag位*/
    curTask = 1;

    /* 切換到任務(wù)狀態(tài)*/
    LOS_SwitchToTask(pstrNextTaskStackRegAddr);
}

5.SwitchToTask

LOS_SwitchToTask       ;恢復(fù)并運(yùn)行任務(wù)的棧信息并運(yùn)行
    LDMIA  R0!, {R4 - R12}  ;
    LDMIA  R0, {R13}        ;
    ADD    R0, #8           ;
    LDMIA  R0, {R1}         ;
    MSR    XPSR, R1         ;
    SUB    R0, #4           ;
    LDMIA  R0, {PC}         ;

    ALIGN

    END

運(yùn)行該程序會(huì)跳轉(zhuǎn)到寄存器所代表的程序段,既前面函數(shù)傳入的task1的TCB中的寄存器段

6.Task1

void TEST_TestTask1(void)
{
    while(1)
    {
                printf("task1\n");
                Delay_ms(1000);
        LOS_TaskSwitch();
    }
}

在任務(wù)一中循環(huán)運(yùn)行打印函數(shù),打印后就進(jìn)行跳轉(zhuǎn)。

7.LOS_TaskSwitch

LOS_ContextSwitch
    STMIA  R0!, {R4 - R12} 
    STMIA  R0!, {R13}      
    STMIA  R0!, {R14}       
    MRS    R2, XPSR        
    STMIA  R0, {R2}         

    
    LDMIA  R1!, {R4 - R12}  
    LDMIA  R1, {R13}       
    ADD    R1, #8           
    LDMIA  R1, {R0}         
    MSR    XPSR, R0        
    SUB    R1, #4           
    LDMIA  R1, {PC}        

兩個(gè)任務(wù)用了兩個(gè)不同的棧來(lái)進(jìn)行保存。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容