热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

在带FPU的Cortex-M4F上移植ucos-III

-------------序言手里有一个STM32F407的小板,于是想把ucos-III跑一下,之前在Freescale的kinetisK10上跑过ucos-III,于是直接把移植代码(

-------------序言

手里有一个STM32F407的小板,于是想把ucos-III跑一下,之前在Freescale的kinetis K10上跑过ucos-III,于是直接把移植代码(官方的K53移植范例)拿过来,发现有问题,一运行就跑到hard_fault中断里了,一开始以为是堆栈啥的,检查了一遍没问题。于是根据Cortex-M3权威指南最后的查找硬件fault的做法,发现原因是总线fault上访造成的,然后一步步调试,发现是在时钟节拍任务里跑飞的:我只建了一个任务,而内核在时钟节拍里却检查到有多个任务,然后进行任务切换 ···  换句话说,在任务切换后,我建立的任务的OS_TCB数据被破坏了,任务的名称也变了,寄存器的值也不是初始化的值。百思不得其解,网上搜了下,发现有人说使能FPU的话其寄存器在中断发生时也入栈。一看,果然,我在建立IAR的工程时在配置里使能了FPU。而目前ucos-III官方的移植都没有考虑到使能FPU的情况。于是翻看M4的手册,再修改移植代码,果然就对了!现在做个小结,也算是给自己的备忘。

------------------------------------------------------------------------------------------

首先,如下图所示,FPU有32个32位的单精度寄存器S0-S31,也可以组成16个64位的双精度寄存器D0-D15。



当使能FPU的时候,中断入栈如下:其中第一个不知道是啥,没有名字,第二个是FPU的状态控制寄存器,后面是S15到S0,接下来才是和M3一样的入栈。如果没有使能FPU,那么入栈也和M3一样。



再看一下STM32驱动库的初始化函数SystemInit(void),里面第一行如下:

 /* FPU settings ------------------------------------------------------------*/
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    SCB->CPACR |= ((3UL <<10*2)|(3UL <<11*2));  /* set CP10 and CP11 Full Access */
  #endif

__FPU_PRESENT是在stm32f4xx.h里定义的,代表该型号带有FPU;__FPU_USED应该是对应工程配置属性里的是否使能FPU。如果使能,则在此进行初始化。因为复位后默认FPU是不使能的。

根据前面的讨论,几个移植过程中设计入栈出栈的函数应修改。首先是堆栈初始化函数:

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        */
    #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    *--p_stk = (CPU_STK)0x00000000u;                        /* No Name Register                         */
    *--p_stk = (CPU_STK)0x00000000u;                        /* FPSCR                                              */
    *--p_stk = (CPU_STK)0x15151515u;                        /* S15                                                    */
    *--p_stk = (CPU_STK)0x14141414u;                        /* S14                                                    */
    *--p_stk = (CPU_STK)0x13131313u;                        /* S13                                                    */
    *--p_stk = (CPU_STK)0x12121212u;                        /* S12                                                    */
    *--p_stk = (CPU_STK)0x11111111u;                        /* S11                                                    */
    *--p_stk = (CPU_STK)0x10101010u;                        /* S10                                                    */
    *--p_stk = (CPU_STK)0x09090909u;                        /* S9                                                     */
    *--p_stk = (CPU_STK)0x08080808u;                        /* S8                                                     */
    *--p_stk = (CPU_STK)0x07070707u;                        /* S7                                                     */
    *--p_stk = (CPU_STK)0x06060606u;                        /* S6                                                     */
    *--p_stk = (CPU_STK)0x05050505u;                        /* S5                                                     */
    *--p_stk = (CPU_STK)0x04040404u;                        /* S4                                                     */
    *--p_stk = (CPU_STK)0x03030303u;                        /* S3                                                     */
    *--p_stk = (CPU_STK)0x02020202u;                        /* S2                                                     */
    *--p_stk = (CPU_STK)0x01010101u;                        /* S1                                                     */
    *--p_stk = (CPU_STK)0x00000000u;                        /* S0                                                     */
    #endif

    *--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             */
    #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    *--p_stk = (CPU_STK)0x31313131u;                        /* S31                                                    */
    *--p_stk = (CPU_STK)0x30303030u;                        /* S30                                                    */
    *--p_stk = (CPU_STK)0x29292929u;                        /* S29                                                    */
    *--p_stk = (CPU_STK)0x28282828u;                        /* S28                                                    */
    *--p_stk = (CPU_STK)0x27272727u;                        /* S27                                                    */
    *--p_stk = (CPU_STK)0x26262626u;                        /* S26                                                    */
    *--p_stk = (CPU_STK)0x25252525u;                        /* S25                                                    */
    *--p_stk = (CPU_STK)0x24242424u;                        /* S24                                                    */
    *--p_stk = (CPU_STK)0x23232323u;                        /* S23                                                    */
    *--p_stk = (CPU_STK)0x22222222u;                        /* S22                                                    */
    *--p_stk = (CPU_STK)0x21212121u;                        /* S21                                                    */
    *--p_stk = (CPU_STK)0x20202020u;                        /* S20                                                    */
    *--p_stk = (CPU_STK)0x19191919u;                        /* S19                                                    */
    *--p_stk = (CPU_STK)0x18181818u;                        /* S18                                                    */
    *--p_stk = (CPU_STK)0x17171717u;                        /* S17                                                    */
    *--p_stk = (CPU_STK)0x16161616u;                        /* S16                                                    */
    #endif

    *--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);
}

因为在汇编文件里没法include stm32f4xx.h头文件(里面有很多C的定义),所以用了另外一个宏__FPU_USED来配置是否使能FPU。而任务切换的函数修改如下:


OS_CPU_PendSVHandler
    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


  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    SUBS    R0, R0, #0x40                                       ; Save remaining regs S16-S31 on process stack
    VSTM    R0, {S16-S31}
  #endif

    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
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    VLDM    R0, {S16-S31}                                        ; Restore S16-S31 from new process stack
    ADDS    R0, R0, #0x40
  #endif

    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

----------------------------------------------------------------------------------------------------------------------------------------------------

进行上述修改后,代码就能成功运行了。在ucos-III里,任务OS_TCB带有一个扩展指针,可以指向扩展的数据,书中说可以用来保存FPU的寄存器。这样也可以,但得为每个任务再分配一个数据块,而且访问起来也麻烦,还不如直接压到栈里。任务的栈要开大一点,因为保存的寄存器比较多,考虑到嵌套什么的。幸好现在的单片机资源都很丰富,RAM一般不成什么问题。


推荐阅读
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 本文探讨了如何通过一系列技术手段提升Spring Boot项目的并发处理能力,解决生产环境中因慢请求导致的系统性能下降问题。 ... [详细]
  • QNX 微内核(procnto-instr)的监测版本内置了高级跟踪与分析工具,能够实现实时系统监控。该模块适用于单处理器及多处理器系统。 ... [详细]
  • 本文探讨了如何通过预处理器开关选择不同的类实现,并解决在特定情况下遇到的链接器错误。 ... [详细]
  • 如何使用Ping命令来测试网络连接?当网卡安装和有关参数配置完成后,可以使用ping命令来测试一下网络是否连接成功。以winXP为例1、打开XP下DOS窗口具体操作是点击“开始”菜 ... [详细]
  • 本文介绍如何从字符串中移除大写、小写、特殊、数字和非数字字符,并提供了多种编程语言的实现示例。 ... [详细]
  • Python + Pytest 接口自动化测试中 Token 关联登录的实现方法
    本文将深入探讨 Python 和 Pytest 在接口自动化测试中如何实现 Token 关联登录,内容详尽、逻辑清晰,旨在帮助读者掌握这一关键技能。 ... [详细]
  • 探讨ChatGPT在法律和版权方面的潜在风险及影响,分析其作为内容创造工具的合法性和合规性。 ... [详细]
  • 深入理解Java多线程并发处理:基础与实践
    本文探讨了Java中的多线程并发处理机制,从基本概念到实际应用,帮助读者全面理解并掌握多线程编程技巧。通过实例解析和理论阐述,确保初学者也能轻松入门。 ... [详细]
  • 探讨了一个关于使用多线程实现从0累加至1000的面试题,分析了在不同线程数量下结果出现偏差的原因,并提供了修正方案。 ... [详细]
  • 利用jstack进行死锁检测与线程堆栈分析
    本文介绍了如何使用jstack工具进行Java应用中的死锁检测及高CPU使用率线程的堆栈分析,帮助开发者快速定位并解决性能瓶颈。 ... [详细]
  • 交互式左右滑动导航菜单设计
    本文介绍了一种使用HTML和JavaScript实现的左右可点击滑动导航菜单的方法,适用于需要展示多个链接或项目的网页布局。 ... [详细]
  • 华硕主板BIOS更新指南(图文)
    本文详细介绍了如何安全有效地更新华硕主板的BIOS,包括准备工作、具体步骤以及注意事项。BIOS是计算机基本输入输出系统的关键组成部分,负责初始化硬件并加载操作系统,定期更新BIOS可以增强系统的稳定性和兼容性。 ... [详细]
author-avatar
百脑汇惠州店_956
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有