日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

uCOS-II中的OS_CPU.h,OS_CPU_A.s,OS_CPU.c

發布時間:2023/12/15 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 uCOS-II中的OS_CPU.h,OS_CPU_A.s,OS_CPU.c 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

μC/OS-Ⅱ的移植集中在OS_CPU.h,OS_CPU_A.s,OS_CPU.c這三個文件上,下面分別詳細介紹三個文件中的函數和需要修改或者編寫的代碼。


1. OS_CPU.h的移植

該文件定義了和處理器及編譯器相關的定義及一些全局函數聲明。由于ARM7 處理器字長為32位,半字長為16位,字節為8位,因此在OS_CPU.h文件修改與編譯器相關的定義如下:

typedef unsigned char BOOLEAN;

typedef unsigned char INT8U;

typedef signed char INT8S;

typedef unsigned short INT16U;

typedef signed short INT16S;

typedef unsigned long INT32U;

typedef signed long INT32S;

typedef float FP32;

typedef double FP64;

typedef unsigned long OS_STK;

?

#define OS_CRITICAL_METHOD 2

#define OS_ENTER_CRITICAL() ARMDisableInt()

#define OS_EXIT_CRITICAL() ARMEnableInt()

#define OS_STK_GROWTH 1

#define OS_TASK_SW OSCtxSw

?

extern void OSCtxSw(void);

extern void OSIntCtxSw(void);

extern void ARMDisableInt(void);

extern void ARMEnableInt(void);

extern void OSTickISR(void);

2. OS_CPU_C.C文件

移植OS_CPU_C.C文件時,需要編寫的是任務堆棧初始化函數OSTaskStkInit和時鐘節拍中斷服務鉤子函數OSTimeTickHook。

在μC/OS-II中,每一個任務都有自己的任務堆棧,當發生任務切換或者中斷時,其CPU使用權被剝脫,為了任務能被再次運行,那么這個被打斷的任務所用到的處理器的寄存器內容均應得到保存,按照ARM7 處理器的壓棧和入棧指令的特點,設計任務堆棧如下圖2:


CPSR


R0

R1

……

R12

LR(R14)

PC(R15)


圖2 任務堆棧的結構

根據任務堆棧結構示意圖,OS_STK函數編寫如下:

#define SVCMODE 0x13

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

OS_STK *stk;

opt = opt;

stk = (OS_STK) ptos;

*--stk = (OS_STK) task;

*--stk = (OS_STK) task;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = (INT32U) pdata;

*--stk = (SVC32MODE|0x40);

return ((OS_STK *)stk);

}

說明:用戶創建任務時,OSTaskCreat()會調用OSTaskStkInit函數初始化該任務的堆棧,并把返回的堆棧指針保存到該任務的TCB結構中的最前面的參數OSTCBStkPtr中,當該任務要被恢復時,任務切換函數從其TCB塊中取得其任務堆棧指針,依次將堆棧內容彈到處理器對應的 CPSR、r0,r1,…,r12,lr,pc的寄存器中,完成現場的恢復和程序指針PC的返回。

另一個需要編寫的函數是OSTimeTickHook,該函數被時鐘節拍中斷服務函數OSTickISR中的OSTimeTick函數調用,用來清除時鐘節拍中斷發生設備的請求。本移植方案使用S3C44B0X處理器的RTC模塊的tick中斷作為時鐘節拍中斷,該函數編寫如下:

void OSTimeTickHook(void){

rI_ISPC =((INT32U)0x01) << 20;

}

注意:用戶也可不修改此函數,但是必須在OSTickISR中執行清除發生節拍中斷的設備的中斷請求標志,為便于說明,本文將利用內核提供給用戶的OSTimeTickHook函數來完成清中斷的任務。

另外幾個hook函數不必去改它們。至此,OS_CPU.C編寫完成。

3. OS_CPU_A.S文件的移植

該文件是移植過程中唯一需要用匯編語言來實現的文件,也是移植的重點和難點所在。在這個文件里,需要編寫的函數有OSStartHighRdy,OSCtxSW,OSIntCtxSW,OSTickISR,ARMDisableInt,ARMEnableInt幾個。

下面先結合us/os的任務切換的過程分析一下這幾個函數的作用。

1)OSStartHighRdy()函數

當程序執行內核的OSStart函數時,表示多任務系統開始啟動, OSStart函數將調用OSStartHighRdy函數從最高優先級任務的TCB塊中獲得該任務的堆棧指針,通過該指針,依次從該任務的任務堆棧中恢復CPU的現場。由于任務在堆棧初始化時,已經設定了彈出到程序指針寄存器PC的是該任務函數的入口地址,因此,OSStartHighRdy函數只需依次彈出任務棧內容到處理起寄存器,該任務便將得以運行。

2)OSCtxSw()函數

該函數是任務級的上下文切換函數,當任務被阻塞而主動請求CPU開始任務調度時執行,其過程是將當前任務的的CPU現場保存到該任務堆棧中去,然后從 OSTCBHighRdy中獲得更高優先級任務的堆棧指針,再從該指針指向的堆棧中恢復此任務的CPU現場,使之繼續執行,從而完成一次任務級別的切換。表2為OSCtxSw函數的偽代碼。

void OSCtxSw(void) {

保存處理器寄存器;

OSTCBCur->OSTCBStkPtr = sp;

OSTCBCur = OSTCBHighRdy;

SP = OSTCBHighRdy->OSTCBStkPtr;

恢復該任務的現場();

執行中斷返回指令;

}

表2 OSCtxSw函數的偽代碼

3) OSIntCtxSw() 函數

該函數用于中斷級的上下文切換。由于CPU響應時鐘節拍中斷后,處理器從svc進入了irq模式,并進入時鐘節拍中斷服務函數OSTickISR, OSTickISR函數發現若有高優先級任務需要運行,則系統不返回中斷前的任務,而直接調度就緒的高優先級任務使之盡快得到執行,以保證實時性能。但是由于OSTickISR函數一開始已經保存過任務中斷前的CPU現場,因此OSIntCtxSW()不需要再進行類似的操作。當OSTickISR調用 OSIntExit函數找出需要運行的更高優先級任務后,OSIntExit會將該任務的TCB指針放在OSTCBHighRdy中,然后 OSIntExit在最后調用OSIntCtxSW函數來從OSTCBHighRdy中獲取堆棧指針然后恢復該高優先級任務的現場,使得其繼續執行,并不再返回時鐘節拍中斷服務程序。顯然,OSIntCtxSW函數的過程和OSCtxSW函數的后半部分操作相同,因此,OSCtxSW可以借用 OSIntCtxSW的代碼。

4) OSTickISR()函數

在 CPU響應時鐘節拍中斷后,程序指針PC發生跳轉后進入該函數,由于OSTickISR調用OSTimeTick函數使得所有的延時節拍不為0的任務延時節拍數減1,并調用OSIntExit函數來找出就緒的高優先級任務,若需要切換,則最后由OSIntCtxSw來完成新任務的調度,否則仍然返回到被時鐘節拍中斷的任務。OSTickISR函數的偽碼和注釋見表3。

5) ARMDisableInt和ARMEnableInt函數

ARMDisableInt 是用來暫時禁止FIQ及IRQ中斷的函數,ARMEnableInt則是恢復ARMDisableInt執行前的中斷使能狀態,二者成對使用,用來保護臨界段代碼不被中斷破壞。本移植使用方式2,即在進入臨界段代碼前關中斷,完成后恢復先前的中斷使能狀態。

void OSTickISR(void) {

保存處理器寄存器;

調用OSIntEnter();

給產生中斷的設備清中斷;

調用OSTimeTick();

調用OSIntExit();

恢復處理器寄存器;

執行中斷返回指令;

}

表3 OSTickTime函數的偽碼

下面給出OS_CPU_A.S的全部內容和注釋。


; *****OS_CPU_A.S文件匯編代碼開始*****

AREA |subr|, CODE, READONLY ;聲明為代碼段


;***** OSStartHighRdy代碼開始*****

???? EXPORT OSStartHighRdy ;關鍵詞EXPORT表示聲明此函數被其他文件使用,下同

???? IMPORT OSTaskSwHook ;關鍵詞IMPORT聲明此函數/參量在其他文件中定義,下同

???? IMPORT OSTCBHighRdy

???? IMPORT OSRunning

OSStartHighRdy ; 使就緒表中任務最高的優先級的任務開始運行

???????? BL OSTaskSwHook ; 調用用戶的Hook函數,空函數

???????? LDR r4,=OSRunning ; 將OSRunning置1,聲明多任務OS開始運行

???????? MOV r5, #1

???????? STRB r5, [r4]

???????? LDR r4, =OSTCBHighRdy ; 偽指令,取得存儲OSTCBHighRdy的地址

???????? LDR r4, [r4] ; 得到最高優先級任務的任務堆棧地址

???????? LDR sp, [r4] ; 切換到新任務的堆棧

???????? LDMFD sp!, {r4} ;從新任務堆棧中讀取第一個參數(CPSR)到(r4)

???????? MSR cpsr_cxsf, r4 ;再傳給cpsr,堆棧中的CPSR彈出到CPU的cpsr寄存器

???????? LDMFD sp!, {r0-r12,lr,pc} ;依次恢復該任務r0~r12,lr,pc,切換到該任務


; *****下面開始OSCtxSw函數,完成任務級的任務切換*****

???? EXPORT OSCtxSw

???? IMPORT OSPrioCur

???? IMPORT OSPrioHighRdy

???? IMPORT OSTCBCur

???? IMPORT OSTaskSwHook

???? IMPORT OSTCBHighRdy;該變量指向任務切換后即將運行的任務的OS_TCB

OSCtxSw

???????? STMFD sp!, {lr} ; OSCtxSw是被調用的,lr的值就是調用前的PC值,入棧

???????? STMFD sp!, {r0-r12,lr} ; 將lr和其他寄存器入棧

???????? MRS r4, cpsr ;通過MRS指令將cpsr入棧

???????? STMFD sp!, {r4} ; 被掛起的當前任務的寄存器保存完畢,下面接著保存該

??????????????????????????????? ;任務的堆棧指針,以便下次恢復時,可以找到其堆棧指針,便可恢復其寄存器

???????? LDR r4, =OSTCBCur ; 得到當前TCB塊的地址,傳給r4

???????? LDR r5, [r4] ; 將OSTCBCur中的值傳給r5,注意OSTCBCur存的是指針

???????? STR sp, [r5] ; 將當前任務的sp傳到OSTCBCur存的指針中去


; *****下面OSCtxSw準備恢復優先級更高的就緒任務,這部分可共用OSIntCtxSw的代碼*****

; *****OSIntCtxSw函數開始*****

???? EXPORT OSIntCtxSw

???? IMPORT OSTaskSwHook

OSIntCtxSw ;準備任務切換

???????? BL OSTaskSwHook ;調用Hook函數,此為空函數

???????? LDR r4, =OSTCBHighRdy

???????? LDR r4, [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] ;從r4中取得要恢復的任務的棧頂指針

???????? LDMFD sp!, {r4} ;彈出任務棧中的第一個參數,即cpsr

???????? MSR cpsr_cxsf, r4 ;首先開始恢復cpsr

???????? LDMFD sp!, {r0-r12,lr,pc} ;依次恢復r0~r12,lr,pc,任務切換


; *****OSTickISR開始*****

???? EXPORT OSTickISR

???? IMPORT OSIntEnter

???? IMPORT OSTimeTick

???? IMPORT OSIntExit


???? LINK_SAVE DCD 0 ;用來保存時鐘節拍中斷前的lr,以便計算出pc而使之入棧

???? PSR_SAVE DCD 0 ;用來保存中斷前的spsr,中斷產生時,svc模式下的cpsr存到spsr

OSTickISR ;時鐘節拍中斷服務程序入口,需要用戶在主函數中安裝

???????? STMFD sp!, {r4} ;因為r4下面要使用,故先保存r4到irq模式的堆棧中

???????? LDR r4, =LINK_SAVE ; 準備保存LR,SPSR,以便得到中斷前的pc和cpsr_svc

???????? STR lr, [r4] ; LINK_SAVE = lr_irq,此時lr=PC(中斷發生前)+4

???????? MRS lr, spsr ;lr已保存,用lr取得spsr(保存的是中斷前的cpsr)

???????? STR lr, [r4, #4] ; PSR_SAVE = spsr_irq

???????? LDMFD sp!, {r4} ;恢復r4

???????? ORR lr, lr, #0x80 ;在上下文切換前,屏蔽irq中斷。注意lr存的是中斷前的cpsr

???????? MSR cpsr_cxsf, lr ;中斷產生前是svc模式,故必須要切換到此模式下保存現場

???????? SUB sp, sp, #4 ;按任務棧結構,空一個空間預留給PC

???????? STMFD sp!, {r0-r12,lr} ; 依次保存lr、r12~r0

???????? LDR r4, =LINK_SAVE ;準備保存pc,取得存svc模式下發生中斷前lr的地址

???????? LDR lr, [r4, #0]

???????? SUB lr, lr, #4 ;中斷前的pc = LINK_SAVE - 4,此前lr為異常前pc+4的值

???????? STR lr, [sp, #(14*4)];保存pc到任務棧中預留的空間

???????? LDR r4, [r4, #4] ;開始保存cpsr,r4 = PSR_SAVE,即中斷前的cpsr_svc

???????? STMFD sp!, {r4} ;保存svc模式下任務的cpsr,寄存器保護完畢

???????? LDR r4, =OSTCBCur ;下面開始將該堆棧指針傳給OSTCBCur所指向的指針

???????? LDR r4, [r4] ;便于OSIntExit函數判斷是否當前任務優先級最高

???????? STR sp, [r4] ;在OSTCBCur->OSTCBstkptr保存被中斷的任務的棧頂指針

???????? BL OSIntEnter ;異常前的上下文保存好之后,開始準備中斷服務,將OSIntNesting++

???????? BL OSTimeTick ;將所有延時節拍不為1的任務的節拍數都減1,并清中斷標志

???????? BL OSIntExit ;將OSIntNesting--,并判斷是否有高優先級任務就緒,若有,則調

?????????????????????????? ;用OSIntCtxSw()調度該任務并不再返回; 若沒有則返回到這里

???????? LDMFD sp!, {r4} ;這里sp存的仍是調用OSIntEnter前的sp,即被中斷的任務棧頂指針

???????? MSR cpsr_cxsf, r4 ;從堆棧中恢復中斷前任務的cpsr,注意此時irq才被重新允許

???????? LDMFD sp!, {r0-r12,lr,pc} ;恢復中斷前任務的 r0-r12,lr和pc,返回被中斷的任務


;******OSTickISR函數代碼完成,下面是臨界段代碼前后開關中斷的函數******

???? EXPORT ARMDisableInt

ARMDisableInt

???????? MRS r0, cpsr ;由于任務和內核都運行在svc模式下,因此可方便地操作cpsr

???????? STMFD sp!, {r0} ; 保存當前的cpsr

???????? ORR r0, r0, #0xc0 ;屏蔽FIQ,IRQ中斷

???????? MSR cpsr_c, r0 ;回寫cpsr,只屏蔽IRQ中斷

???????? MOV pc, lr ;返回

???????? EXPORT ARMEnableInt

???????? ARMEnableInt ;必須和ARMDisableInt成對使用

???????? LDMFD sp!, {r0} ;彈出在ARMDisableInt中被保存的cpsr

???????? MSR cpsr_c, r0 ;恢復關中斷前的cpsr

???????? MOV pc, lr ;返回

???????? END ;匯編代碼結束

;*****OS_CPU_A.S文件結束******

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的uCOS-II中的OS_CPU.h,OS_CPU_A.s,OS_CPU.c的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。