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条回答
brave_dancing
2019-07-22 04:18
       在源程序里,堆栈的初始化会使得两个数据存放在相同的地址中,这一点从C和C的汇编我都确认过了。堆栈初始化是在任务建立的时候才会初始化一次,目的是仿造出一个中断过后的堆栈接口段,这样通过改变堆栈指针和中断返回,这样就可以实现中断切换。这些事基础,说完任务切换我们再来说说数据覆盖的问题,如果堆栈接口不正确的话,严重时会导致整个系统崩溃。所以我对那个数据覆盖相当不理解,最后我想想了,堆栈初始化里面的数据只有一个比较重要,那就是任务的地址,只要它被正确装入PC寄存器,那么堆栈初始化就应该完成了任务,其他的数据再怎么覆盖,也是无用的。从程序看,数据覆盖发生在任务指针入栈之前,这样会使得任务指针相对偏移4个字节,可是,在中断返回时,数据是从下向上出栈的,所以这个错误不会影响任务指针推入PC寄存器,这样任务就会正确开始,其他寄存器会放入什么值都无所谓。而任务一旦开始后的任务堆栈接口就不再是由人为的设置,是系统内核响应中断所决定的,其实还有一部分代码 在CPU的汇编文件的Pendvc中断里体现,这里不细说了、、、

        最后再说说,这些文件应该是STM32官方移植时候写的,难道他们没有察觉这个错误吗,答案肯定是肯定的,他们知道,但是他们为什么还要让这样的错误出现在程序里,我看了几遍代码后明白,这样可以在兼容M3内核和M4内核不使用FPU的同时,节省4字节的RAM空间,这样的解决使我觉得    、、、、,全世界的工程师也许都有强迫症吧、、、、
       但是我觉他们是不是该把这样的错误注明在程序里呢、、、、,也许他们觉得我们应该足够聪明,不会被这点小问题难道、、、、、

一周热门 更多>