UCOS_STM32的任务切换

本文详细解析了UCOS_STM32操作系统中任务切换的过程,从启动第一个任务的步骤开始,包括OSInit、OSTaskCreate、OSTaskStkInit、OSStart和OSStartHighRdy。重点介绍了OSTaskStkInit函数如何构造任务伪现场,以及在中断返回时如何进行堆栈操作。此外,还概述了普通任务切换的流程,涉及到OSTaskResume、OSSched和NVIC_PENDSVSET的使用,以及在任务切换中断处理中对寄存器和堆栈的操作。

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

1、启动第一个任务

os_start

   |--》OSInit

   |--》OSTaskCreate

              |--》OSTaskStkInit

   |--》OSStart

             |--》OSStartHighRdy


2、OSTaskStkInit,这个函数用于构造一个伪现场,用于调度中断的出栈处理

CPU_STK  *OSTaskStkInit (OS_TASK_PTR    p_task,
                         void          *p_arg,
                         CPU_STK       *p_stk_base,
                         CPU_STK       *p_stk_limit,
                         CPU_STK_SIZE   stk_size,
                         OS_OPT         opt)
{
    CPU_STK  *p_stk;


    (void)opt;                                              /* Prevent compiler warning                               */

    p_stk = &p_stk_base[stk_size];                          /* Load stack pointer                                     */
                                                            /* Registers stacked as if auto-saved on exception        */
    *--p_stk = (CPU_STK)0x01000000u;                        /* xPSR                                                   */
    *--p_stk = (CPU_STK)p_task;                             /* Entry Point                                            */
    *--p_stk = (CPU_STK)OS_TaskReturn;                      /* R14 (LR)                                               */
    *--p_stk = (CPU_STK)0x12121212u;                        /* R12                                                    */
    *--p_stk = (CPU_STK)0x03030303u;                        /* R3                                                     */
    *--p_stk = (CPU_STK)0x02020202u;                        /* R2                                                     */
    *--p_stk = (CPU_STK)p_stk_limit;                        /* R1                                                     */
    *--p_stk = (CPU_STK)p_arg;                              /* R0 : argument                                          */
                                                            /* Remaining registers saved on process stack             */
    *--p_stk = (CPU_STK)0x11111111u;                        /* R11                                                    */
    *--p_stk = (CPU_STK)0x10101010u;                        /* R10                                                    */
    *--p_stk = (CPU_STK)0x09090909u;                        /* R9                                                     */
    *--p_stk = (CPU_STK)0x08080808u;                        /* R8                                                     */
    *--p_stk = (CPU_STK)0x07070707u;                        /* R7                                                     */
    *--p_stk = (CPU_STK)0x06060606u;                        /* R6                                                     */
    *--p_stk = (CPU_STK)0x05050505u;                        /* R5                                                     */
    *--p_stk = (CPU_STK)0x04040404u;                        /* R4                                                     */

    return (p_stk);
}

3、OSStartHighRdy --》1、把psp置为0,2、MSP指向OS_CPU_ExceptStkBase,3,、触发PendSV exception

OSStartHighRdy
    LDR     R0, =NVIC_SYSPRI14                                  ; 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]
    
    CPSIE   I                                                   ; Enable interrupts at processor level

OSStartHang
    B       OSStartHang                                         ; Should never get here

4、PendSV_Handler 

1)因为psp为0,所以直接跳转到OS_CPU_PendSVHandler_nosave

2)调用OSTaskSwHook

3)OSPrioCur   = OSPrioHighRdy;

4)OSTCBCurPtr = OSTCBHighRdyPtr;

5)SP = OSTCBHighRdyPtr->StkPtr;这个时候从堆栈依次弹出R4-R11,PSP指向R0+#0x20

6)ORR     LR, LR, #0x04,确保中断返回后使用PSP。

7)从中断返回。BX LR表示从中断中返回。

PendSV_Handler
    CPSID   I                                                   ; Prevent interruption during context switch
    MRS     R0, PSP                                             ; PSP is process stack pointer
    CBZ     R0, OS_CPU_PendSVHandler_nosave                     ; Skip register save the first time

    SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack
    STM     R0, {R4-R11}

    LDR     R1, =OSTCBCurPtr                                    ; OSTCBCurPtr->OSTCBStkPtr = SP;
    LDR     R1, [R1]
    STR     R0, [R1]                                            ; R0 is SP of process being switched out

                                                                ; At this point, entire context of process has been saved
OS_CPU_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]

    LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;
    LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
    ADDS    R0, R0, #0x20
    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

5、STM发生中断需要做的事情:

z  入栈:  把8个寄存器的值压入栈 
z  取向量:从向量表中找出对应的服务程序入口地址 
z  选择堆栈指针MSP/PSP,更新堆栈指针SP(使用MSP),更新连接寄存器LR(一个特殊值),更新程序计数器PC(指向ISR)


从中断返回即弹出以上堆栈,可以看出,堆栈顺序和OSTaskStkInit是一致的。


6、普通任务切换:

OSTaskResume --》 OSSched --》OS_TASK_SW -》触发任务切换 --》回到函数PendSV_Handler

#define  OS_TASK_SW()               NVIC_INT_CTRL = NVIC_PENDSVSET

这是的任务切换中断处理多了两个步骤:

1)保存R4-R11

2)保存SP到原任务堆栈OSTCBCurPtr->OSTCBStkPtr = SP;



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值