zoukankan      html  css  js  c++  java
  • 移值UCOS2到M4核与M3核的区别

    之前移值过ucos2到stm32f2系列的单片机,这个单片机是属于arm的m3内核的。最近在学习永磁同步电机的控制,对于这个电机的控制,有比较多的数学计算,甚至于还有浮点的运算。所以用到了stm32f4系列的单片机,这个单片机内置FPU,可以用几条指令就可以处理单精度的浮点数据,而它是属于M4内核的。因为原先移植过M3的基础,想着应该很快会搞定,没想到移植了几天的时间才搞清楚,下面就记录下M3与M4内核的ucos2的移植不同之处。其实M3与M4内核相差不大,对于我应用的来说,其实最大的不同一是M4的最大主频提高了,二是M4带浮点功能。

    1、ucos2移植到M3核的重点(对于ucos2移植到M3内核详细的讲解以及ucos2的结构后续会单独写一篇博客描述)

    M3核对于操作系统的支持很好,它有一个NVIC向量中断控制器,它管理着对CM3的所有中断请求。其中有几个队操作系统很重要的中断:

    a、SVC(系统服务调用),用于产生系统函数的调用请求,例如操作系统通常不让用户程序直接访问硬件,而是通过提供一些系统服务函数,让用户程序使用SVC发出对系统服务函数的呼叫请求,以这种方法调用它们来间接访问硬件。因此,当用户程序想要控制特定的硬件时,它就要产生一个SVC异常,然后操作系统提供的SVC异常服务例程得到执行,它再调用相关的操作系统函数,后者完成用户程序请求的服务。这与传统的arm核比如arm7与amr9等的SWI的软件中断异常类似。

    b、PendSV(可悬起的系统中断),它是可以像普通的中断一样被悬起的(不像SVC那样会上访)。OS可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动作。悬起PendSV 的方法是:手工往NVIC的PendSV悬起寄存器中写1。悬起后,如果优先级不够高,则将缓期等待执行。所以它常常 被用来进行任务的切换,UCOS2的任务切换就是在这个中断里面实现的。

    c、SysTick定时器被捆绑在NVIC中,用于产生SysTick异常(异常号:15)。SysTick定时器能产生中断,CM3为它专门开出一个异常类型,并且在向量表中有它的一席之地。它用于操作系统的滴答时钟。在以前,操作系统还有所有使用了时基的系统,都必须一个硬件定时器来产生需要的“滴答”中断,作为整个系统的时基。滴答中断对操作系统尤其重要。例如,操作系统可以为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。

    ucos2对每一个任务都会分配一个任务控制块,任务控制块的首地址存放着该任务的堆栈指针,它存放的数据的格式如在函数,可以看到它的堆栈是向下递增的,也就是说堆栈顶部的位置始终是数值大的地址。首先存放的是M3内核发生异常时自动保存的数据,可以看到任务的函数地址也被保存在内,它的值其实就是任务发生切换时PC的值,如果后续要切换回这个任务了只要做一次PendSV中断,切换PSP指针为这个任务的堆栈指针,当从PendSV中断返回时task的值就会自动的存放到PC寄存器中,这样就做到了任务切换。接着保存M3内核发生异常时没有自动保存的寄存器,剩下的堆栈内容就保存任务函数的一些变量以及函数调用等等。

    OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)
    {
        OS_STK *p_stk;
    
    
        (void)opt;                                                  /* 'opt' is not used, prevent warning                   */
        p_stk       = ptos;                            /* Load stack pointer                                 */
                                                                    /* Registers stacked as if auto-saved on exception      */
        *(--p_stk) = (OS_STK)0x01000000uL;                          /* xPSR                                                 */
        *(--p_stk) = (OS_STK)task;                                  /* Entry Point                                          */
        *(--p_stk) = (OS_STK)OS_TaskReturn;                         /* R14 (LR)                                             */
        *(--p_stk) = (OS_STK)0x12121212uL;                          /* R12                                                  */
        *(--p_stk) = (OS_STK)0x03030303uL;                          /* R3                                                   */
        *(--p_stk) = (OS_STK)0x02020202uL;                          /* R2                                                   */
        *(--p_stk) = (OS_STK)0x01010101uL;                          /* R1                                                   */
        *(--p_stk) = (OS_STK)p_arg;                                 /* R0 : argument                                        */
                                                                    /* Remaining registers saved on process stack           */
        *(--p_stk) = (OS_STK)0x11111111uL;                          /* R11                                                  */
        *(--p_stk) = (OS_STK)0x10101010uL;                          /* R10                                                  */
        *(--p_stk) = (OS_STK)0x09090909uL;                          /* R9                                                   */
        *(--p_stk) = (OS_STK)0x08080808uL;                          /* R8                                                   */
        *(--p_stk) = (OS_STK)0x07070707uL;                          /* R7                                                   */
        *(--p_stk) = (OS_STK)0x06060606uL;                          /* R6                                                   */
        *(--p_stk) = (OS_STK)0x05050505uL;                          /* R5                                                   */
        *(--p_stk) = (OS_STK)0x04040404uL;                          /* R4                                                   */
        return (p_stk);
    }

    接着看到UCOS2在M3内核下运行时的任务切换代码,可以看到任务切换函数,主要是将被打断任务的堆栈保存好,然后将需要运行的任务的堆栈出栈,任何以从进程堆栈中做出栈操作,进行任务切换

    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           ;检查是否是从进程中进来的,如果不是,直接跳到OS_CPU_PendSVHandler_nosave
    
        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  保存当前任务堆栈指针到当前任务控制块
    
                                                                    //; 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}                                               //;//只是为了调用OSTaskSwHook函数
    
        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]                                           //当前任务控制块变为找出需要运行的任务控制块 准备切换任务堆栈
    
        LDR     R0, [R2]                                           //; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
        LDM     R0, {R4-R11}                                       // ; Restore r4-11 from new process stack 取出新任务的R4-R11寄存器值
        ADDS    R0, R0, #0x20
        MSR     PSP, R0                                            // ; Load PSP with new process SP 切换新任务指针给PSP
        ORR     LR, LR, #0x04                                      // ; Ensure exception return uses process stack  从进程堆栈中作出出栈操作
        CPSIE   I                                                  // ; 开启中断
        BX      LR                                                 // ; Exception return will restore remaining context 任务切换,切换到新任务被切换时的地址
    
        END

    2、ucos2移植到M4核

    UCOS2在M3与M4运行任务切换时的原理是一样的,都是利用的PendSV中断。但是保存的寄存器有所不同,因为M4内核可以支持单精度浮点操作,这样就会有了浮点相关的寄存器的保存。这就是与M3内核最大的不同之处。支持浮点运算的M4内核比M3内核多一个FPU模块,它里面有33个寄存器,其中S0-S16是异常上下文会自动保存的。

    a、M4内核堆栈的初始化,与M3相比多了保存34个寄存的内容

    OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)
    {
        OS_STK *p_stk;
    
        (void)opt;                                                  /* 'opt' is not used, prevent warning                   */
        p_stk       = ptos;                            /* Load stack pointer                                 */
    
            #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
            *(--p_stk) = (INT32U)0x00000000L; //No Name Register  
            *(--p_stk) = (INT32U)0x00001000L; //FPSCR
            *(--p_stk) = (INT32U)0x00000015L; //s15
            *(--p_stk) = (INT32U)0x00000014L; //s14
            *(--p_stk) = (INT32U)0x00000013L; //s13
            *(--p_stk) = (INT32U)0x00000012L; //s12
            *(--p_stk) = (INT32U)0x00000011L; //s11
            *(--p_stk) = (INT32U)0x00000010L; //s10
            *(--p_stk) = (INT32U)0x00000009L; //s9
            *(--p_stk) = (INT32U)0x00000008L; //s8
            *(--p_stk) = (INT32U)0x00000007L; //s7
            *(--p_stk) = (INT32U)0x00000006L; //s6
            *(--p_stk) = (INT32U)0x00000005L; //s5
            *(--p_stk) = (INT32U)0x00000004L; //s4
            *(--p_stk) = (INT32U)0x00000003L; //s3
            *(--p_stk) = (INT32U)0x00000002L; //s2
            *(--p_stk) = (INT32U)0x00000001L; //s1
            *(--p_stk) = (INT32U)0x00000000L; //s0
            #endif
    
                                                                    /* Registers stacked as if auto-saved on exception      */
        *(--p_stk) = (OS_STK)0x01000000uL;                          /* xPSR                                                 */
        *(--p_stk) = (OS_STK)task;                                  /* Entry Point                                          */
        *(--p_stk) = (OS_STK)OS_TaskReturn;                         /* R14 (LR)                                             */
        *(--p_stk) = (OS_STK)0x12121212uL;                          /* R12                                                  */
        *(--p_stk) = (OS_STK)0x03030303uL;                          /* R3                                                   */
        *(--p_stk) = (OS_STK)0x02020202uL;                          /* R2                                                   */
        *(--p_stk) = (OS_STK)0x01010101uL;                          /* R1                                                   */
        *(--p_stk) = (OS_STK)p_arg;                                 /* R0 : argument                                        */
            
            #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
            *(--p_stk) = (INT32U)0x00000031L; //s31
            *(--p_stk) = (INT32U)0x00000030L; //s30
            *(--p_stk) = (INT32U)0x00000029L; //s29
            *(--p_stk) = (INT32U)0x00000028L; //s28
            *(--p_stk) = (INT32U)0x00000027L; //s27
            *(--p_stk) = (INT32U)0x00000026L; //s26    
            *(--p_stk) = (INT32U)0x00000025L; //s25
            *(--p_stk) = (INT32U)0x00000024L; //s24
            *(--p_stk) = (INT32U)0x00000023L; //s23
            *(--p_stk) = (INT32U)0x00000022L; //s22
            *(--p_stk) = (INT32U)0x00000021L; //s21
            *(--p_stk) = (INT32U)0x00000020L; //s20
            *(--p_stk) = (INT32U)0x00000019L; //s19
            *(--p_stk) = (INT32U)0x00000018L; //s18
            *(--p_stk) = (INT32U)0x00000017L; //s17
            *(--p_stk) = (INT32U)0x00000016L; //s16
            #endif
                                                                    /* Remaining registers saved on process stack           */
        *(--p_stk) = (OS_STK)0x11111111uL;                          /* R11                                                  */
        *(--p_stk) = (OS_STK)0x10101010uL;                          /* R10                                                  */
        *(--p_stk) = (OS_STK)0x09090909uL;                          /* R9                                                   */
        *(--p_stk) = (OS_STK)0x08080808uL;                          /* R8                                                   */
        *(--p_stk) = (OS_STK)0x07070707uL;                          /* R7                                                   */
        *(--p_stk) = (OS_STK)0x06060606uL;                          /* R6                                                   */
        *(--p_stk) = (OS_STK)0x05050505uL;                          /* R5                                                   */
        *(--p_stk) = (OS_STK)0x04040404uL;                          /* R4                                                   */
            
        return (p_stk);
    }

    a、M4内核的任务切换,与M3相比多了保存16个寄存器

    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           ;检查是否是从进程中进来的,如果不是,直接跳到OS_CPU_PendSVHandler_nosave
    
            
            //;Is the task using the FPU context? If so, push high vfp registers.支持M4内核保存S16-S31寄存器
            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  保存当前任务堆栈指针到当前任务控制块
    
                                                                    //; 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}                                               //;//只是为了调用OSTaskSwHook函数
    
        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]                                           //当前任务控制块变为找出需要运行的任务控制块 准备切换任务堆栈
    
        LDR     R0, [R2]                                           //; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
        LDM     R0, {R4-R11}                                       // ; Restore r4-11 from new process stack 取出新任务的R4-R11寄存器值
        ADDS    R0, R0, #0x20
        
        ;Is the task using the FPU context? If so, push high vfp registers.支持M4内核出栈S16-S31寄存器
            TST     R14, #0x10
            IT         EQ
            VLDMIAEQ R0!, {S16-S31} 
        
        MSR     PSP, R0                                            // ; Load PSP with new process SP 切换新任务指针给PSP
        ORR     LR, LR, #0x04                                      // ; Ensure exception return uses process stack  从进程堆栈中作出出栈操作
        CPSIE   I                                                  // ; 开启中断
        BX      LR                                                 // ; Exception return will restore remaining context 任务切换,切换到新任务被切换时的地址
    
        END

     以上就是移值UCOS2到M4核与M3核的区别

  • 相关阅读:
    百度网盘下载太慢,试试阿里云网盘?
    linux使用过程中遇到的常见问题
    vscode设置护眼色
    为什么程序员互相之间不能透露薪水?
    机器学习:支持向量机(SVM)
    Java多线程总结(三)
    Java多线程总结(二)
    Java多线程总结(一)
    8.多线程--避免活跃性危险
    7.多线程--线程池的使用
  • 原文地址:https://www.cnblogs.com/andyfly/p/9738636.html
Copyright © 2011-2022 走看看