ARM周立功模板启动代码中断处理文件IRQ.C的中文解释 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