uC/OS任务切换问题 STM32F4

2019-07-20 20:38发布

下面是任务站的初始化程序,对于该程序我有一个疑问,希望知道的同学可以帮助我(假设所有的预编条件都满足)

疑问用红的写出

OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)
{
    OS_STK *stk;


    (void)opt;                                   /* 'opt' is not used, prevent warning                 */
    stk       = ptos;                            /* Load stack pointer                                 */

#if (__FPU_PRESENT==1)&&(__FPU_USED==1)       
        *(--stk) = (INT32U)0x00000000L; //No Name Register   
        *(--stk) = (INT32U)0x00001000L; //FPSCR                                    
        *(--stk) = (INT32U)0x00000015L; //s15                                         
        *(--stk) = (INT32U)0x00000014L; //s14
        *(--stk) = (INT32U)0x00000013L; //s13
        *(--stk) = (INT32U)0x00000012L; //s12
        *(--stk) = (INT32U)0x00000011L; //s11
        *(--stk) = (INT32U)0x00000010L; //s10
        *(--stk) = (INT32U)0x00000009L; //s9
        *(--stk) = (INT32U)0x00000008L; //s8
        *(--stk) = (INT32U)0x00000007L; //s7
        *(--stk) = (INT32U)0x00000006L; //s6
        *(--stk) = (INT32U)0x00000005L; //s5
        *(--stk) = (INT32U)0x00000004L; //s4
        *(--stk) = (INT32U)0x00000003L; //s3
        *(--stk) = (INT32U)0x00000002L; //s2
        *(--stk) = (INT32U)0x00000001L; //s1
        *(--stk) = (INT32U)0x00000000L; //s0   
#endif
                                                 /* Registers stacked as if auto-saved on exception    */
    *(stk)    = (INT32U)0x01000000L;             /* xPSR                                               */               
请问该数据是否覆盖s0的数据,*(--stk) 应该是先减1,然后向该地址存入数据,那么相邻的这两句不就是使用同一个地址吗。
    *(--stk)  = (INT32U)task;                    /* Entry Point                                        */                     
    *(--stk)  = (INT32U)OS_TaskReturn;           /* R14 (LR) (init value will cause fault if ever used)*/
    *(--stk)  = (INT32U)0x12121212L;             /* R12                                                */
    *(--stk)  = (INT32U)0x03030303L;             /* R3                                                 */
    *(--stk)  = (INT32U)0x02020202L;             /* R2                                                 */
    *(--stk)  = (INT32U)0x01010101L;             /* R1                                                 */
    *(--stk)  = (INT32U)p_arg;                   /* R0 : argument                                      */

#if (__FPU_PRESENT==1)&&(__FPU_USED==1)       
        *(--stk) = (INT32U)0x00000031L; //s31
        *(--stk) = (INT32U)0x00000030L; //s30
        *(--stk) = (INT32U)0x00000029L; //s29
        *(--stk) = (INT32U)0x00000028L; //s28
        *(--stk) = (INT32U)0x00000027L; //s27
        *(--stk) = (INT32U)0x00000026L; //s26
        *(--stk) = (INT32U)0x00000025L; //s25
        *(--stk) = (INT32U)0x00000024L; //s24
        *(--stk) = (INT32U)0x00000023L; //s23
        *(--stk) = (INT32U)0x00000022L; //s22
        *(--stk) = (INT32U)0x00000021L; //s21
        *(--stk) = (INT32U)0x00000020L; //s20
        *(--stk) = (INT32U)0x00000019L; //s19
        *(--stk) = (INT32U)0x00000018L; //s18
        *(--stk) = (INT32U)0x00000017L; //s17
        *(--stk) = (INT32U)0x00000016L; //s16
#endif
               
                                                /* Remaining registers saved on process stack         */
    *(--stk)  = (INT32U)0x11111111L;             /* R11                                                */
    *(--stk)  = (INT32U)0x10101010L;             /* R10                                                */
    *(--stk)  = (INT32U)0x09090909L;             /* R9                                                 */
    *(--stk)  = (INT32U)0x08080808L;             /* R8                                                 */
    *(--stk)  = (INT32U)0x07070707L;             /* R7                                                 */
    *(--stk)  = (INT32U)0x06060606L;             /* R6                                                 */
    *(--stk)  = (INT32U)0x05050505L;             /* R5                                                 */
    *(--stk)  = (INT32U)0x04040404L;             /* R4                                                 */

    return (stk);
}


下面的函数存在PenSV中断中,该函数就是任务切换的根本
PendSV_Handler
    CPSID   I                                                   ; Prevent interruption during context switch
    MRS     R0, PSP                                           ; PSP is process stack pointer
    CBZ     R0, PendSV_Handler_Nosave                    ; Skip register save the first time
       
        ;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
    STM     R0, {R4-R11}

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

在此为什么要保存上一个任务的PSP到R0中

PendSV_Handler_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, =OSTCBCur                                       ; OSTCBCur  = OSTCBHighRdy;
    LDR     R1, =OSTCBHighRdy
    LDR     R2, [R1]
    STR     R2, [R0]                                               
上面我可以看懂,是通过全局变量得到一个任务的堆栈段,然后把SP指针放在R0寄存其中,现在的R0就是上面OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)函数返回的stk(最后一个语句 return(stk);
    LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
    LDM     R0, {R4-R11}                                     ; Restore r4-11 from new process stack
该指令执行完成之后R0的内容应该保持不变,这样才可以保证后面FPU寄存器数据恢复正确(问 分析的是否正确)
    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}
该指令执行完成之后R0的内容应该变化,R0应该指向堆栈段中任务上次R0寄存器中的内容(问 分析的是否正确)
               
    MSR     PSP, R0                                             ; Load PSP with new process SP
uC/OS II在STM32F4上使不使用双堆栈?堆栈指针不是在中断返回指令下自动恢复吗?此处为什么还要手动恢复?
    ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack
    CPSIE   I
    BX      LR                                                  ; Exception return will restore remaining context

此处不是该使用中断返回指令吗,M4内核的中断返回指令和跳转指令一样吗?该指令会自动恢复R0-R4、S0-S16、PC、SP、xPSR吗?
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
9条回答
灼灼其华
1楼-- · 2019-07-20 23:59
我只能回答这几个问题.
在此为什么要保存上一个任务的PSP到R0中: PendSV_Handler是中断服务程序,在中断时内核使用的SP是MSP不能用PSP.
uC/OS II在STM32F4上使不使用双堆栈?:我也纳闷 既然出现了PSP就应该是使用双堆栈的但是我看遍整个汇编部分也没看到切换堆栈指针的语句.
堆栈指针不是在中断返回指令下自动恢复吗? 不能自动回复的.
此处不是该使用中断返回指令吗,M4内核的中断返回指令和跳转指令一样吗?该指令会自动恢复R0-R4、S0-S16、PC、SP、xPSR吗?:一样的,在中断状态这几个寄存器是自动回复的.建议你去看<<ARM CortexM3和M4权威指南>>
brave_dancing
2楼-- · 2019-07-21 00:33
在线等、、、、、
brave_dancing
3楼-- · 2019-07-21 04:46
灼灼其华 发表于 2016-8-7 14:31
我只能回答这几个问题.
在此为什么要保存上一个任务的PSP到R0中: PendSV_Handler是中断服务程序,在中断时 ...

谢谢指教,其实我最不可以理解的是第一个问题,那个数据覆盖会导致FPU数据丢失导致出错、、、
brave_dancing
4楼-- · 2019-07-21 09:58
 精彩回答 2  元偷偷看……
hello_galaxy
5楼-- · 2019-07-21 13:15
 精彩回答 2  元偷偷看……
brave_dancing
6楼-- · 2019-07-21 16:09
hello_galaxy 发表于 2016-8-8 09:32
初学ucos,我想问楼主一个问题,每次任务切换都是运行最高优先级的任务,那低优先级的任务怎样才能得到运行 ...

uC/OS的最高任务必须有延时,这样在延时最高任务的时候回发生任务切换,切换到比较低的任务。如果最高任务没有延时,或者没有被挂起、等待信号量的的任务,那么低级任务不会得到CPU的使用权。

一周热门 更多>