当前位置: 代码迷 >> 综合 >> arm9-ucos中断过程分析
  详细解决方案

arm9-ucos中断过程分析

热度:49   发布时间:2023-12-08 20:28:50.0
步骤1:发生中断后,跳到地址0的中断向量表;b  HandlerIRQ ;handler for IRQ interrupt
步骤2:然后跳到,中断函数HandlerIRQ ,这个函数就做了并且只是了一件事取出全局变量HandleIRQ 地址上的函数并且使pc跳到该函数,

 //堆栈是满降方式就是说 ,sp指向满的地方,当压栈时,先sp自减4然后存数据到sp所指地址,这里仅仅是取出数据到pc没其他操作

具体实现代码如下:    MACRO
$HandlerLabel HANDLER $HandleLabel

$HandlerLabel
sub sp,sp,#4 ;decrement sp(to store jump address)
stmfd sp!,{r0} ;PUSH the work register to stack(lr does''t push because it return to original address)
ldr     r0,=$HandleLabel;load the address of HandleXXX to r0
ldr     r0,[r0] ;load the contents(service routine start address) of HandleXXX
str     r0,[sp,#4]      ;store the contents(ISR) of HandleXXX to stack
ldmfd   sp!,{r0,pc}     ;POP the work register and pc(jump to ISR)
MEND


 

步骤3:因为在系统复位的时候,  全局变量HandleIRQ处被安放了汇编函数OS_CPU_IRQ_ISR,

 ; Setup IRQ handler
 ldr r0,=HandleIRQ       ;This routine is needed
 ;ldr r1,=IsrIRQ   ;if there isn''t 'subs pc,lr,#4' at 0x18, 0x1c
 ldr r1, =OS_CPU_IRQ_ISR ;modify by txf, for ucos
 str r1,[r0]

OS_CPU_IRQ_ISR是一个汇编函数定义如下:

//该函数就是从cpu寄存器里面得到中断偏移,然后根据偏移,和标号IRQIsrVect(也就是定义在内存地址_ISR_STARTADDRESS上的HandleEINT0地址)

相加得到具体中断处理函数的地址,然后从这个地址取出中断函数(这个中断函数就是在c语言中用户自己放上去的,比如pISR_TIMER0= (uint32) OSTickISR;pISR_TIMER0就是定义在地址_ISR_STARTADDRESS上的变量),然后调用他,

最后OS_CPU_IRQ_ISR返回

具体实现代码:

OS_CPU_IRQ_ISR 	
STMFD   SP!, {R1-R3}			; We will use R1-R3 as temporary registers
;----------------------------------------------------------------------------
;   R1--SP
;	R2--PC 
;   R3--SPSR
;------------------------------------------------------------------------
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 TASK''S CONTEXT ONTO OLD TASK''S STACK
STMFD   SP!, {R2}				; Push task''s PC 
STMFD   SP!, {R4-R12, LR}		; Push task''s LR,R12-R4
LDMFD   R1!, {R4-R6}			; Load Task''s R1-R3 from IRQ stack 
STMFD   SP!, {R4-R6}			; Push Task''s R1-R3 to SVC stack
STMFD   SP!, {R0}			    ; Push Task''s R0 to SVC stack
STMFD   SP!, {R3}				; Push task''s 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();   这里用的是ldr指令所以用户的终端函数OSTickISR要外层要加一个汇编函数.
MSR		CPSR_c,#SVCMODE|NOINT   ;Change to SVC mode
BL 		OSIntExit           ;Call OSIntExit
LDMFD   SP!,{R4}               ;POP the task''s CPSR 
MSR		SPSR_cxsf,R4
LDMFD   SP!,{R0-R12,LR,PC}^	   ;POP new Task''s context


 

注意2:全局变量HandleIRQ的定义如下:

 ^   _ISR_STARTADDRESS  ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset  #   4
HandleUndef  #   4
HandleSWI  #   4
HandlePabort    #   4
HandleDabort    #   4
HandleReserved  #   4
HandleIRQ  #   4

 
 
OS_CPU_IRQ_ISR 函数分析:
首先把r1-r3保存到sp,然后
 
OS_CPU_IRQ_ISR

STMFD   SP!, {R1-R3} ; We will use R1-R3 as temporary registers
;----------------------------------------------------------------------------
;   R1--SP
; R2--PC
;   R3--SPSR
;------------------------------------------------------------------------
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 TASK''S CONTEXT ONTO OLD TASK''S STACK

STMFD   SP!, {R2} ; Push task''s PC
STMFD   SP!, {R4-R12, LR} ; Push task''s LR,R12-R4

LDMFD   R1!, {R4-R6} ; Load Task''s R1-R3 from IRQ stack
STMFD   SP!, {R4-R6} ; Push Task''s R1-R3 to SVC stack
STMFD   SP!, {R0}     ; Push Task''s R0 to SVC stack

STMFD   SP!, {R3} ; Push task''s 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 task''s CPSR
    MSR SPSR_cxsf,R4
    LDMFD   SP!,{R0-R12,LR,PC}^    ;POP new Task''s context

IRQIsrVect DCD HandleEINT0


 

  相关解决方案