lpc2200移植ucos-II总结(六 关于中断及时钟节拍)

2.5 关于中断及时钟节拍

关于中断和时钟节拍,UCOS-II对于ARM7通用的中断服务程序的汇编与c函数接口如下:

MACRO和MEND伪指令用于宏定义。MACRO……MEND伪指令可以将一段代码定义为一个整体,称为宏定义。其中,$标号在宏指令被展开时,标号会被代换为用户定义的符号。MACRO标识宏定义的开始,MEND标识宏定义的结束。定义之后在程序中就可以通过宏指令多次调用该段代码。MACRO宏定义如下

MACRO

$标号    宏名   $参数1,$参数2,……

指令序列

MEND

IRQ异常处理代码的汇编部分

MACRO

$IRQ_Label HANDLER $IRQ_Exception_Function

                 ;$IRQ_lable标号,用于构造宏定义体内的其他标号。HANDLER是宏的名称,$IRQ_Exception_function是宏的参数

 

        EXPORT  $IRQ_Label ; 输出的标号。用于在程序中声明一个全局的标号,

 该标号可在其他文件中引用  

        IMPORT  $IRQ_Exception_Function ; 引用的外部标号。用于通知编译器要使用的标号在其他原文件中定义,但要在当前文件中引用

$IRQ_Label

        SUB     LR, LR, #4                      ; 计算返回地址

        STMFD   SP!, {R0-R3, R12, LR}           ; 保存任务环境

        MRS     R3, SPSR                        ; 保存状态

        STMFD   SP, {R3, SP, LR}^ ;保存用户状态的R3,SP,LR,注意不能回写

 ;后缀”!”表示最后的地址写回到SP中。

 ;后缀”^”不允许在用户模式或系统模式下使用,若在LDM指令且寄存器列表中包含有PC时使用,那么除了正常的多寄存器传送外,将SPSR也拷贝到CPSR中,这可用于异常处理返回。使用“^”后缀进行数据传送且寄存器列表不包含PC时,加载/存储的是用户模式的寄存器,而不是当前模式的寄存。

注意:这里用的是中断模式的堆栈,一开始就计算真正的返回地址,即将保存在R14_irq的返回地址减4,然后采用IRQ模式的R13_irq来保存中段的上下文,这里保存了R0-R3,R12。LR这6个寄存器。同时,又将用户模式下的CPSR(因为切换到中断模式,所以这里变成了SPSR)和R13(用户模式),R14(用户模式)保存到IRQ模式的堆栈中。注意,这里最后一条没有采用SP!的形式,所以SP是不回写的,保持不变。STMFD   SP, {R3, SP, LR}^指的是。如果寄存器列表里面没有PC,那么采用^就表示将用户模式的寄存器的值去出来,所以(R3,SP,LR)指的是用户模式寄存器。

        ; OSIntNesting++

        LDR     R2,  =OSIntNesting   ;将OSIntNesting的地址保存到R2         

        LDRB    R1, [R2]             ;将R2指定地址的数据加载到R1

        ADD     R1, R1, #1

        STRB    R1, [R2]

        SUB     SP, SP, #4*3

这段代码将中断嵌套层数加1,并且将刚才没有调整的SP指针向下指3个,这时候SP又指向栈顶。

        MSR     CPSR_c, #(NoInt | SYS32Mode) ; 切换到系统模式

        CMP     R1, #1

        LDREQ   SP, =StackUsr

       

        BL      $IRQ_Exception_Function      ; 调用c语言的中断处理程序

这段代码将运行模式切换到SYS32模式。比较一下R1,看上面的OSIntNesting是否为1。如果为1,则表示第一次进入系统模式,那么将系统指针设定好。

        MSR     CPSR_c, #(NoInt | SYS32Mode) ; 切换到系统模式

        LDR     R2, =OsEnterSum  ; OsEnterSum,使OSIntExit退出时中断关闭

        MOV     R1, #1

        STR     R1, [R2]

 

        BL      OSIntExit

这段为中断回复代码。这里又切回系统模式。用OsEnterSum变量保证退出OSIntExit不会把中断打开。

        LDR     R2, =OsEnterSum; 因为中断服务程序要退出,所以OsEnterSum=0

        MOV     R1, #0

        STR     R1, [R2]

 

        MSR     CPSR_c, #(NoInt | IRQ32Mode)    ; 切换回irq模式

        LDMFD   SP, {R3, SP, LR}^; 恢复用户状态的R3,SP,LR,注意不能回写

        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                 ; 进行任务切换

因为上面没有回写弹出的堆栈指针,所以将堆栈指针加3个寄存器内存。根据CMP指令的结果。当优先级没有改变,就直接把终端模式生下来的R0-R3,R12,PC和SPAR弹出,中断结束,用户态程序继续执行。如果优先级发生改变,则进行任务切换。注意,如果寄存器列表里面有PC寄存器,那么在带”^”的情况下,自动将SPSR拷贝到CPSR。

    MEND

 

    END

你可能感兴趣的:(lpc2200移植ucos-II总结(六 关于中断及时钟节拍))