NoInt EQU 0x80 //禁止IRQ中斷
USR32Mode EQU 0x10 //用戶模式
SVC32Mode EQU 0x13 //管理模式
SYS32Mode EQU 0x1f //系統(tǒng)模式
IRQ32Mode EQU 0x12 //中斷模式
FIQ32Mode EQU 0x11 //快速中斷模式
;引入的外部標(biāo)號(hào)在這聲明
//IMPORT表示引用外部的信息
IMPORT OSIntCtxSw ;任務(wù)切換函數(shù)//引用外部的函數(shù)
IMPORT OSIntExit ;中斷退出函數(shù)
IMPORT OSTCBCur ;UC/OS II正在運(yùn)行的任務(wù)指針
IMPORT OSTCBHighRdy ; UC/OS II任務(wù)就緒表中級(jí)別最高的優(yōu)先級(jí)
IMPORT OSIntNesting ;中斷嵌套計(jì)數(shù)器
IMPORT StackUsr ;用戶模式堆棧
IMPORT OsEnterSum ;開(kāi)關(guān)中斷的次數(shù)
CODE32
AREA IRQ,CODE,READONLY
MACRO
$IRQ_Label HANDLER $IRQ_Exception_Function
EXPORT $IRQ_Label ; 輸出的標(biāo)號(hào)
IMPORT $IRQ_Exception_Function ; 引用的外部標(biāo)號(hào)
$IRQ_Label
SUB LR, LR, #4 ; 計(jì)算返回地址
//進(jìn)入中斷后,它的返回地址該怎么計(jì)算呢,可以這樣來(lái)理解,因?yàn)樗闹噶盍魉是3級(jí)的,即執(zhí)行進(jìn)入中斷函數(shù)時(shí),PC已經(jīng)指向欲取值的指令即當(dāng)前執(zhí)行的地址+8;當(dāng)已進(jìn)入中斷時(shí),LR里面裝的是PC,所以要想中斷返回到正確的地址處,就必須把LR-4。
STMFD SP!, {R0-R3, R12, LR} ; 保存任務(wù)環(huán)境
//這里面為什么只把R0-R3,R12,LR保存呢,其它不用嗎,是這樣的,我們可以從你裝的ADS1.2目錄下的PDF文件夾里面的ADS_DeveloperGuide_D.PDF文件的2.2就可以發(fā)現(xiàn)r4-r11裝的是局部變量,在進(jìn)行函數(shù)跳轉(zhuǎn)時(shí),編譯器它會(huì)自動(dòng)保護(hù)它們的。
MRS R3, SPSR ; 保存狀態(tài)
STMFD SP, {R3, SP, LR}^ ; 保存用戶狀態(tài)的R3,SP,LR,注意不能回寫,前面一個(gè)SP是IRQ模式的,后面一個(gè)SP是用戶模式的,為什么不能回寫呢,如果你回寫的話,那么它保存的是用戶的SP,顯然是不行的。不知這樣理解對(duì)不對(duì)。這里保存SP和LR的目的是為了嵌套,
; 正是因?yàn)闆](méi)有回寫,所以后面調(diào)整了SP ,調(diào)整指令是 SUB SP, SP, #4*3
LDR R2, =OSIntNesting ; OSIntNesting++ 中斷嵌套數(shù)+1
;(相當(dāng)于調(diào)用了一次中斷進(jìn)入函數(shù)OSIntEnter(),與后面的BL OSIntExit 形成呼應(yīng))
LDRB R1, [R2]
ADD R1, R1, #1
STRB R1, [R2]
SUB SP, SP, #4*3 ;由于前面SP沒(méi)有回寫,保存了3個(gè)32位的寄存器,這里調(diào)整指針
;做好彈出這三個(gè)數(shù)據(jù)的準(zhǔn)備
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切換到系統(tǒng)模式。只有切換到系統(tǒng)模式,讓后面的服務(wù)程序在系統(tǒng)模式下運(yùn)行,才能實(shí)現(xiàn)嵌套。
CMP R1, #1 ;判斷是否是只有第一次進(jìn)入中斷,還是有嵌套
LDREQ SP, =StackUsr ;如果是第一次中斷則設(shè)定系統(tǒng)模式的堆棧指針
BL $IRQ_Exception_Function ; 調(diào)用c語(yǔ)言的中斷處理程序
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切換到系統(tǒng)模式。做好中斷退出的準(zhǔn)備
LDR R2, =OsEnterSum ; OsEnterSum,使OSIntExit退出時(shí)中斷關(guān)閉
MOV R1, #1 ;相當(dāng)于調(diào)用了OS_ENTER_CRITICAL();
STR R1, [R2]
BL OSIntExit ;調(diào)用UC/OS的中斷退出函數(shù) OSIntNesting--
; 如果中斷嵌套數(shù)不等于0 則不進(jìn)行任務(wù)調(diào)度
LDR R2, =OsEnterSum ; 因?yàn)橹袛喾⻊?wù)程序要退出,所以O(shè)sEnterSum=0
MOV R1, #0 ; 相當(dāng)于調(diào)用了OS_EXIT_CRITICAL()
STR R1, [R2]
MSR CPSR_c, #(NoInt | IRQ32Mode) ; 切換回irq模式
LDMFD SP, {R3, SP, LR}^ ; 恢復(fù)用戶狀態(tài)的R3,SP,LR, //前面一個(gè)SP是IRQ模式的,后面一個(gè)SP是用戶模式的,為什么不能回寫呢,如果你回寫的話,那么它保存的是用戶的SP,顯然是不行的。不知這樣理解對(duì)不對(duì)。
; 正是因?yàn)闆](méi)有回寫,所以后面調(diào)整了SP ,調(diào)整指令是 ADD SP, SP, #4*3 ;
LDR R0, =OSTCBHighRdy ;讀出就緒表中任務(wù)最高優(yōu)先級(jí),判斷是否需要任務(wù)切換
LDR R0, [R0]
LDR R1, =OSTCBCur
LDR R1, [R1]
CMP R0, R1 ;//判斷被掛起的任務(wù)是不是具有最高優(yōu)先級(jí)
ADD SP, SP, #4*3 ; ;如果不是則進(jìn)行任務(wù)切換
MSR SPSR_cxsf, R3
LDMEQFD SP!, {R0-R3, R12, PC}^ ; 不進(jìn)行任務(wù)切換
LDR PC, =OSIntCtxSw ; 進(jìn)行任務(wù)切換
MEND
END
歡迎光臨 (http://www.torrancerestoration.com/bbs/) | Powered by Discuz! X3.1 |