UCOSIII(1)——SVC与PenSV实现任务切换

本文基于STM32F407ZGT6
——————————————

SVC异常:

SVC(系统服务调用,亦简称系统调用)用于产生系统函数的调用请求。
SVC 异常是必须立即得到响应的应用程序执行 SVC 时都是希望所需的请求立即得到响应。
在这里插入图片描述
在 UCOS 中并未使用 SVC 这个功能,了解一下即可。
在 UCOS 中并未使用 SVC 这个功能,了解一下即可。
在 UCOS 中并未使用 SVC 这个功能,了解一下即可。

PendSv异常:

  • 由于SVC异常是必须立即得到响应的(若因优先级不比当前正处理的高,或是其它原因使之无法立即响应,将上访成硬 fault),应用程序执行SVC 时都是希望所需的请求立即得到响应。
  • PendSV 则不同,它是可以像普通的中断一样被悬起的(不像 SVC 那样会上访)。OS
    可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动作。

1、悬 起 PendSV 的方法是:手工往 NVIC 的 PendSV 悬起寄存器中写 1。悬起后,如果优先级不够高,则将缓期等待执行。
2、PendSV 的典型使用场合是在上下文切换时(在不同任务之间切换)。异常会自动延迟上下文切换的请求,直到其它的 ISR 都完成了处理后才放行。为实现这个机制,需要把 PendSV 编程为最低优先级的异常。如果 OS 检测到某 IRQ 正在活动并且被 SysTick 抢占,它将悬起一个 PendSV异常,以便缓期执行上下文切换。
在这里插入图片描述

可以看到uCOS操作系统里(其实实时操作系统都一样)各类异常/中断的优先级关系:
SYSTICK异常>中断>PendSv异常
PendSV 异常会自动延迟上下文切换的请求,直到其它的 ISR 都完成了处理后才放行。这样保证了中断的快速响应性又保证了操作系统的正常轮转。

一、将PendSV 异常设置为最低优先级(这两段代码在os_cpu_a.asm中定义)。

NVIC_INT_CTRL   EQU     0xE000ED04    ; 中断控制寄存器   ; Interrupt control state register.
NVIC_SYSPRI14   EQU     0xE000ED22    ; 系统优先级寄存器(2)  ; System priority register (priority 14).
NVIC_PENDSV_PRI EQU         0xFFFF    ; PendSV 中断优先级为最低  ; PendSV priority value (lowest).
NVIC_PENDSVSET  EQU     0x10000000    ; 触发软件中断的值   ; Value to trigger PendSV exception.

NVIC_PENDSV_PRI EQU 0xFFFF ;这个语句把PendSV 中断优先级为了最低0xFFFF 。

OSStartHighRdy汇编函数:

OSStartHighRdy
    LDR     R0, =NVIC_SYSPRI14   ; 设置 PendSV 的优先级为最低    ; Set the PendSV exception priority
    LDR     R1, =NVIC_PENDSV_PRI
    STRB    R1, [R0]

    MOVS    R0, #0               ; Set the PSP to 0 for initial context switch call
    MSR     PSP, R0

    LDR     R0, =OS_CPU_ExceptStkBase    ; Initialize the MSP to the OS_CPU_ExceptStkBase
    LDR     R1, [R0]
    MSR     MSP, R1    

    LDR     R0, =NVIC_INT_CTRL    ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]              ;触发PenSv中断

    CPSIE   I                     ;开中断   ; Enable interrupts at processor level

OSStartHang
    B       OSStartHang          ;死循环,应该不会到这里的    ; Should never get here
  • LDR R1, =NVIC_PENDSV_PRI;这个语句把PendSV 中断优先级设置位0xFFFF,也就是最低。
  • LDR R1, =NVIC_PENDSVSET
    STR R1, [R0]
    ;这两个语句实现了触发PendSv异常,也就是说进入OSStartHighRdy函数会触发PendSv异常,然后会进入PendSv异常服务函数进行任务切换。

OSStartHighRdy 是由 OSStart()调用,OSStart()用来开启多任务的,如果多任务开启正常则进入OSStartHighRdy 函数触发PendSv异常并马上进行任务切换;如果多任务开启失败的话就会进 入 OSStartHang函数(这里没有贴出来)。

二、OSStart()函数:

OSStart()函数在我们的main函数里创建第一个任务的时候发生调用。(好像也只是调用一次,用于启动系统)

void  OSStart (OS_ERR  *p_err)
{
#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    if (OSRunning == OS_STATE_OS_STOPPED) {
        OSPrioHighRdy   = OS_PrioGetHighest();    //找出目前最高优先级的函数    /* Find the highest priority                              */
        OSPrioCur       = OSPrioHighRdy;
        OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
        OSTCBCurPtr     = OSTCBHighRdyPtr;
        OSRunning       = OS_STATE_OS_RUNNING;    /*OSRunning变为1所以退出OSStart函数以后,系统开始跑*/
        OSStartHighRdy();                         //调用 OSStartHighRdy汇编函数  /* Execute target specific code to start task             */
       *p_err           = OS_ERR_FATAL_RETURN;   /* OSStart() is not supposed to return                    */
    } else {
       *p_err           = OS_ERR_OS_RUNNING;     /* OS is already running                                  */
    }
}

调用这个函数一般是在创建第一个任务时,那时系统还没开始跑;在程序里面OSRunning = OS_STATE_OS_RUNNING;把系统开始的标志位OSRunning设置为1。这个函数正常运行结束以后代表着操作系统真正开始跑起来了。
三、PendSV 异常服务函数:
PendSV 异常服务要完成两个工作:1、保存上文;2、切换下文
任务之间的切换就是发生在PendSV 异常服务函数里面。
可以理解为——触发了PendSV 异常->函数自动跳转到PendSV 异常服务函数->执行异常服务函数->实现任务的切换。
触发PendSV 异常的函数:(在os_cpu_a.asm中定义)

  • OSStartHighRdy :用得很少,只是在任务开启时在OSStart()函数里调用
  • OSCtxSw :实现任务级的任务切换
  • OSIntCtxSw :实现中断级的任务切换
PendSV_Handler
    CPSID   I        ;关中断    ; Prevent interruption during context switch
    MRS     R0, PSP   ; 将 psp 的值加载到 R0    ; PSP is process stack pointer
	
	 ; CBZ判0转移,判断 R0如果值为 0 ,则跳转到 OS_CPU_PendSVHandler_nosave
	 ; 进行第一次任务切换的时候,R0 肯定为 0
    CBZ     R0, PendSVHandler_nosave    ; Skip register save the first time

    ;判读是否使用FPU
	;Is the task using the FPU context? If so, push high vfp registers.
	TST		R14, #0X10
	IT		EQ
	VSTMDBEQ R0!,{S16-S31}
	
    SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack
  ;————————————保存上下文————————————————————
  ; 手动存储 CPU 寄存器 R4-R11 的值到当前任务的堆栈
	STM     R0, {R4-R11}

 ; 加载 OSTCBCurPtr 指针的地址到 R1
    LDR     R1, =OSTCBCurPtr                                    ; OSTCBCurPtr->OSTCBStkPtr = SP;
    LDR     R1, [R1]
    STR     R0, [R1]                                            ; R0 is SP of process being switched out

 ;—————————切换上下文—————————————
 ; 实现 OSTCBCurPtr = OSTCBHighRdyPtr
 ; 把下一个要运行的任务的堆栈OSPrioHighRdy加载到 CPU 寄存器中                                                               ; At this point, entire context of process has been saved
PendSVHandler_nosave
    PUSH    {R14}                  ; Save LR exc_return value
    LDR     R0, =OSTaskSwHook      ; OSTaskSwHook();
    BLX     R0
    POP     {R14}

    LDR     R0, =OSPrioCur         ; OSPrioCur   = OSPrioHighRdy;
    LDR     R1, =OSPrioHighRdy
    LDRB    R2, [R1]
    STRB    R2, [R0]

    LDR     R0, =OSTCBCurPtr     ; OSTCBCurPtr = OSTCBHighRdyPtr;
    LDR     R1, =OSTCBHighRdyPtr
    LDR     R2, [R1]
    STR     R2, [R0]
                                ; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;
    LDM     R0, {R4-R11}        ; Restore r4-11 from new process stack
    ADDS    R0, R0, #0x20
   
   ;Is the task using the FPU context? If so, push high vfp registers.
	TST 	R14, #0x10
	IT 		EQ
	VLDMIAEQ R0!, {S16-S31} 
	
	MSR     PSP, R0            ; Load PSP with new process SP
    ORR     LR, LR, #0x04      ; Ensure exception return uses process stack
    CPSIE   I
    BX      LR                 ; Exception return will restore remaining context
    END
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值