ucos2在MIPS的中断嵌套实现

本文详细介绍了在SOC3210i平台上UCOS2的中断嵌套处理机制,特别是针对系统时钟中断和普通中断的不同处理方式。文中通过具体的代码示例,解释了如何在中断服务程序中实现中断嵌套,包括中断嵌套层数的计算、任务切换的条件判断等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在SOC3210i上测试过的UCOS2的中断嵌套

 

ucos2任务切换,是通过系统时钟中断进行任务调度来实现的。所以系统时钟中断在中断服务程序中就有区别于其它中断的特殊之处。在这里,对于中断嵌套而言,主要分为两类:系统时钟中断和其它普通中断。

 

对于这两类,在中断嵌套的处理里,如果不考虑中断优先级的话,有如果三种情形:

1、系统时钟中断服务程序处理中发生普通中断嵌套

2、普通中断服务程序处理中发生系统时钟中断嵌套

3、普通中断服务程序处理中发生普通中断嵌套

 

需要注意的是,系统时钟中断可能会产生任务切换,所以得特别处理,实现如下:

 

    BSS
   
    /* 32 bit align */
    ALIGN(2)

    .globl exc_stack_low
exc_stack_low:
    .space _EXC_STKSIZE
    .globl exc_stack_hi
exc_stack_hi:

    ALIGN(4) /* 16 bytes align */
exc_context:
    .space    8

    ALIGN(4)
exc_sp_vetor:
    .space    1024

LEAF(UCOS_INTHandler)

    MFC0(k0,C0_EPC)            #读取中断返回地址
    STORE_REG_RET(k0)        #保存中断现场

    la k1,exc_context        #保存状态寄存器和原因寄存器
    MFC0(t0,C0_STATUS)
    sw t0, 0(k1)
    MFC0(t0,C0_CAUSE)
    sw t0, 4(k1)

    la k0,OSIntNesting        #将当前堆栈指针sp压入SP堆栈
    lw k0,0(k0)            #根据中断嵌套层数保存各层中断的堆栈指针
    sll k0,2
    la t0,exc_sp_vetor
    addu t0,k0
    sw sp,0(t0)

    bne k0,0,nest            #如果当前状态为嵌套,跳转到nest
    nop   

    la sp,exc_stack_hi        #改变中断执行的堆栈为exc_stack_hi
    la gp,_gp            #指定gp指针
   
nest:
    jal OSIntEnter            #进入中断,主要是计算中断嵌套层数
    nop

    jal rt_interrupt_dispatch    #执行中断服务程序,传入参数为exc_context地址
    move a0,k1
   
    jal OSIntExit            #出中断
    nop

    la k0,OSIntNesting        #根据中断嵌套层数,获取堆栈指针,并由k1保存
    lw k0,0(k0)
    sll k0,2
    la t0,exc_sp_vetor
    addu t0,k0   
    lw k1,0(t0)

    la t0,OSIntCtxSwFlag        #如果需要进行任务切换,跳转到_IntCtxSw
    lw t1,0(t0)               
    beq t1,1,_IntCtxSw
    nop

    move sp,k1            #sp指针指向新堆栈
   
    RESTORE_REG_ERET()        #出栈,恢复中断现场

_IntCtxSw:
    sw zero,0(t0)            #清空任务切换标志位

    la t0,OSPrioCur            #相当于OSPrioCur = OSPrioHghRdy
    la t1,OSPrioHighRdy
    lb t1,0(t1)
    sb t1,0(t0)

    jal OSTaskSwHook        #调用任务切换钩子函数
    nop

    la t2,OSTCBHighRdy   
    lw t2,0(t2)            #获取最高优先级任务的堆栈
   
    la t0,OSTCBCur
    lw a0,0(t0)

    la t1,exc_sp_vetor   
    lw a1,0(t1)
    sw a1,0(a0)            #保存当前任务的堆栈指针
    sw t2,0(t0)            #相当于OSTCBCur = OSTCBHighRdy   

    beq k0,0,nonest
    nop   

    move sp,k1
   
    RESTORE_REG_ERET()        #出栈,恢复中断现场

nonest:   
    lw sp,0(t2)
   
    RESTORE_REG_ERET()        #出栈,恢复中断现场

END(UCOS_INTHandler)

 

分析代码的执行过程如下:

 

1、当产生中断后,首先读取中断返回地址并将其同其它寄存器一起压栈,并读取状态寄存器和原因寄存器;

2、将本次中断产生前的堆栈压入堆栈指针堆栈,也就是把该堆栈指针保存到exc_sp_vetor;

3、如果本次中断是嵌套中断,跳转到5;

4、将堆栈指针从任务堆栈改变为中断堆栈,并指定全局指针gp;

5、执行OSIntEnter,OSIntNesting自加1,表示进行一次中断嵌套;

6、执行中断服务程序,传入参数为指向状态寄存器和原因寄存器的指针;

7、执行OSIntExit,OSIntNesting自减1;

8、从堆栈指针堆栈中读取出中断后的堆栈指针;

9、判断OSIntCtxSwFlag是否为1,如果为1,表示要进行任务切换,跳转到11;

10、把堆栈指针赋值给sp指针,出中断,恢复中断现场;

11、清零OSIntCtxSwFlag标志;

12、调用任务切换钩子函数;

13、将当前任务堆栈指针保存到当前任务的TCB中;

14、获取最高优先级任务的TCB,并将该TCB指向的任务堆栈保存到exc_sp_vetor的第一个元素,这样在最后一个中断返回时,就进行了任务切换;

15、如果本次中断是嵌套中断,从exc_sp_vetor中找到堆栈指针,返回中断。

16、如果本次中断是非嵌套中断,从OSTCBHighRdy获取最高优先级任务的堆栈,返回中断。

 

 

另外:

        对于MIPS中断嵌套的实现,还需要在中断服务程序中打开中断嵌套,并且屏蔽该中断及比该中断优先级低的中断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值