|
中斷接口文件IRQ.INC:
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
IMPORT OSTCBHighRdy
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,所以后面要調整SP
LDR R2, =OSIntNesting ; OSIntNesting++//中斷嵌套數+1
LDRB R1, [R2]
ADD R1, R1, #1
STRB R1, [R2]
SUB SP, SP, #4*3
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
STR R1, [R2]
BL OSIntExit
LDR R2, =OsEnterSum ; 因為中斷服務程序要退出,所以OsEnterSum=0
MOV R1, #0
STR R1, [R2]
MSR CPSR_c, #(NoInt | IRQ32Mode) ; 切換回irq模式
LDMFD SP, {R3, SP, LR}^ ; 恢復用戶狀態的R3,SP,LR, //前面一個SP是IRQ模式的,后面一個SP是用戶模式的,為什么不能回寫呢,如果你回寫的話,那么它保存的是用戶的SP,顯然是不行的。不知這樣理解對不對。
; 如果回寫的是用戶的SP,所以后面要調整SP
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
|
|