在uc/os-II的移植进程中存在一个通用的irq中止处理函数,其间的完结进程如下:
OS_CPU_IRQ_ISR
STMFD SP!, {R1-R3} ; We will use R1-R3 as temporary registers
MOV R1, SP
ADD SP, SP, #12 ;Adjust IRQ stack pointer
SUB R2, LR, #4 ;Adjust PC for return address to task
MRS R3, SPSR ; Copy SPSR (Task CPSR)
MSR CPSR_cxsf, #SVCMODE|NOINT ;Change to SVC mode
; SAVE TASKS CONTEXT ONTO OLD TASKS STACK
STMFD SP!, {R2} ; Push tasks PC
STMFD SP!, {R4-R12, LR} ; Push tasks LR,R12-R4
LDMFD R1!, {R4-R6} ; Load Tasks R1-R3 from IRQ stack
STMFD SP!, {R4-R6} ; Push Tasks R1-R3 to SVC stack
STMFD SP!, {R0} ; Push Tasks R0 to SVC stack
STMFD SP!, {R3} ; Push tasks CPSR
LDR R0,=OSIntNesting ;OSIntNesting++
LDRB R1,[R0]
ADD R1,R1,#1
STRB R1,[R0]
CMP R1,#1 ;if(OSIntNesting==1){
BNE %F1
LDR R4,=OSTCBCur ;OSTCBHighRdy->OSTCBStkPtr=SP;
LDR R5,[R4]
STR SP,[R5] ;}
1 MSR CPSR_c,#IRQMODE|NOINT ;Change to IRQ mode to use IRQ stack to handle interrupt
LDR R0, =INTOFFSET
LDR R0, [R0]
LDR R1, IRQIsrVect
MOV LR, PC ; Save LR befor jump to the C function we need return back
LDR PC, [R1, R0, LSL #2] ; Call OS_CPU_IRQ_ISR_handler();
MSR CPSR_c,#SVCMODE|NOINT ;Change to SVC mode
BL OSIntExit ;Call OSIntExit
LDMFD SP!,{R4} ;POP the tasks CPSR
MSR SPSR_cxsf,R4
LDMFD SP!,{R0-R12,LR,PC}^ ;POP new Tasks context
IRQIsrVect DCD HandleEINT0
这个函数是irq中止的通用处理方式,我对其间的代码做一下扼要的剖析和评论。
首要我需求扼要的剖析一下中止处理进程中咱们应该完结的使命,首要cpu会主动完结一些操作,其间包含中止的封闭现已回来地址的保存,还有形式的切换等。咱们程序员则需求完结一些寄存器的保存作业以及跳转到详细的处理函数中,最终完结回来操控。
需求留意的是,本文中的UC/OS-II使命都运行在SVC形式下,而不是SYS形式下。使命栈中保存的寄存器也是这种形式下对应的值。
我依照注释号对代码进行解说:
2、STMFD SP!, {R1-R3}; 首要是完结几个寄存器的压栈操作,为什么这么做呢?由于咱们接下来即将运用这写寄存器。为什么需求呢?这是由于当时CPU作业的irq形式下,因而这儿的SP并不是SVC形式下的SP指针,可是在UC/OS-II的移植进程中通常将各个使命作业在SVC形式下,一起还需求对寄存器的保存,在中止发生今后,需求保存一切的寄存器以及CPSR的值,而当时的SP并不是使命的栈,此刻除了SP、R14的值发生了改动以外,其他的寄存器并没有发生改动。可是由于后边需求运用这些寄存器,因而需求压栈。
3、MOV R1, SP; 将R14_irq的值保存到R1中,这个SP的保存首要是为了经过这个值拜访IRQ形式下的仓库空间,完结对数据的拜访。
4、ADD SP, SP, #12; 调整IRQ形式下的仓库指针SP_irq,将这个指针指向IRQ仓库的开端方位,便利下一次中止的处理操作。
5、SUB R2, LR, #4 ;这个操作首要是调整回来地址,了解反常回来地址的了解其间的意义,这时候的回来地址实质上便是使命的回来地址,也便是将来需求加载到PC中的值。
6、MRS R3, SPSR;由于发生了IRQ中止,此刻CPU进入IRQ形式中,这时的SPSR_irq中保存了svc形式下的CPSR状况。而使命仓库中保存的刚好是SVC形式下的状况寄存器,因而需求将SVC形式下的状况寄存器首要读出来,然后保存进使命的仓库中,因而用R3来保存CPSR值。
7、MSR CPSR_cxsf, #SVCMODE|NOINT; 由于使命的仓库空间坐落SVC形式下,因而首要需求将CPU的状况切换到SVC形式下,然后进行使命情形的切换操作。
9、STMFD SP!, {R2}; 这时候的SP是指在SVC形式下的R13_svc。中止发生今后,SVC形式下的SP并没有发生改动,回来今后,该值依然存在,依然指向使命的栈顶方位。依据使命栈空间的散布,首要需求保存PC值,然后是R14-R0,CPSR的值,最终是保存SP到使命中,这种散布状况是和仓库初始化进程的散布共同的。而经过调整的回来地址刚好就保存在了R2中,因而需求压栈保存PC值。
10、STMFD SP!, {R4-R12, LR};由于在之前的一系列操作中,并没有对R4-R12,R14的值进行损坏,因而能够直接进行压栈操作,完结使命仓库中R4-R12,LR的保存操作。
接下来的几句代码是要点:完结了在对其他形式下仓库空间的拜拜访题。
11、LDMFD R1!, {R4-R6};是指将R1地址处加载一些数据到R4-R6,这三个寄存器的值现已被压入栈中,对他们的修正并不会导致过错的发生,因而这三个寄存器实质上是作为中心地址。其间加载的次序满意高地址对应高的高编号的寄存器值。R1我在前面就强调了用来拜访IRQ形式仓库空间的参阅地址。从这个地址向上别离保存了压入栈中的R1-R3寄存器的值,也便是被中止使命R1-R3的值。
12、STMFD SP!, {R4-R6};也便是完结了对使命寄存器R1-R3的压栈操作。
13、STMFD SP!, {R0} ;前面的代码中并没有修正R0的值,因而其间的值依然是使命的R0值,因而也需求压栈操作。经过上面的几句代码就完结了使命的R0-R15一切寄存器的保存操作。接下的就应该完结CPSR的保存。
14、STMFD SP!, {R3};当时的R3中保存了实际上是前面所说的SPCR_irq中的值,也便是SVC形式下的状况寄存器的值,因而能够以为便是完结了使命的状况寄存器的保存。