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