您的位置:首页 > 其它

arm9-ucos中断过程分析

2012-02-07 11:12 246 查看
步骤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


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  os service function c