arm9-ucos中断过程分析

来源:互联网 发布:淘宝店铺推广多少钱 编辑:程序博客网 时间:2024/04/28 23:05
步骤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, SPADD     SP, SP, #12             ;Adjust IRQ stack pointerSUB     R2, LR, #4              ;Adjust PC for return address to taskMRS     R3, SPSR; Copy SPSR (Task CPSR)   MSR     CPSR_cxsf, #SVCMODE|NOINT   ;Change to SVC mode; SAVE TASK''S CONTEXT ONTO OLD TASK''S STACKSTMFD   SP!, {R2}; Push task''s PC STMFD   SP!, {R4-R12, LR}; Push task''s LR,R12-R4LDMFD   R1!, {R4-R6}; Load Task''s R1-R3 from IRQ stack STMFD   SP!, {R4-R6}; Push Task''s R1-R3 to SVC stackSTMFD   SP!, {R0}    ; Push Task''s R0 to SVC stackSTMFD   SP!, {R3}; Push task''s CPSRLDR     R0,=OSIntNesting        ;OSIntNesting++LDRB    R1,[R0]ADD     R1,R1,#1STRB    R1,[R0] CMP     R1,#1                   ;if(OSIntNesting==1){BNE     %F1 LDR     R4,=OSTCBCur            ;OSTCBHighRdy->OSTCBStkPtr=SP;LDR     R5,[R4]STR     SP,[R5]                 ;}1MSR    CPSR_c,#IRQMODE|NOINT    ;Change to IRQ mode to use IRQ stack to handle interruptLDR     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要外层要加一个汇编函数.        MSRCPSR_c,#SVCMODE|NOINT   ;Change to SVC mode    BL OSIntExit           ;Call OSIntExit        LDMFD   SP!,{R4}               ;POP the task''s CPSR     MSRSPSR_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


 

原创粉丝点击