OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 12239|回复: 9

ucosii中调用Printf打印浮点型数据就进入硬件错误,STM32F4?

[复制链接]

9

主题

1385

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
11912
金钱
11912
注册时间
2013-3-8
在线时间
1269 小时
发表于 2015-2-5 15:53:55 | 显示全部楼层 |阅读模式
5金钱
打印整数都没有问题。就是打印浮点数就直接进入硬件错误了。
网上说字节对齐问题。但我改成8字节对齐后还是不正确

最佳答案

查看完整内容[请看2#楼]

问题已解决。把FPU关掉就可以了
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

9

主题

1385

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
11912
金钱
11912
注册时间
2013-3-8
在线时间
1269 小时
 楼主| 发表于 2015-2-5 15:53:56 | 显示全部楼层
问题已解决。把FPU关掉就可以了
回复

使用道具 举报

9

主题

1385

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
11912
金钱
11912
注册时间
2013-3-8
在线时间
1269 小时
 楼主| 发表于 2015-2-5 15:53:56 | 显示全部楼层
本帖最后由 不要神话 于 2013-8-10 16:28 编辑


基于CORTEX-M4的STM32F407最大的特色就是加入了一个FPU浮点处理器,能支持DSP运算。但是UCOS III官方的移植版本竟然不支持FPU浮点运算,如果在MDK的设置选项中把使能FPU打上的话运行的时候会把芯片带到硬fault,我用STLINK逐步跟踪,发现在使能FPU后系统在进行任务堆栈切换的时候发生错误进入硬fault,遂在GOOGLE上搜索了半天,并查看了M4的参考手册,发现使能FPU之后系统在进入中断的时候会自动将部分FPU寄存器入栈,而不支持FPU的UCOS移植版本显然没有为FPU寄存器做堆栈设置,所以在堆栈进行还原的时候导致还原点不同,进入硬fault。下面逐一分析:

1. 在UCOS III for STM32F4 中,UCOS在进行任务切换的时候并不是直接在任务中进行堆栈切换,而是使用了CORTEX-M系统架构中的一个叫做PENDSV的异常,通过悬起一个PENDSV异常,PENDSV异常其实想当于一个SVC(系统高胜),但是跟SVC的在于PENDSV的悬起特性,即是说置位一个PSNDSV异常之后如果当前还有更高优先级的异常在进行,则PENDSV会被延迟执行,当更高优先级的异常执行完毕才轮到PENDSV例程执行,CORTEX-M的尾链技术能够确保在别的中断完毕退出之后能够快速进入PENDSV执行,在PENDSV中,UCOS才进行实际的任务切换操作,PS:STM32有两个堆栈,一个是PSP(线程堆栈),一个是MSP(管理堆栈),一般来说用户程序运行在PSP的线程模式中,所有中断例程运行在MSP的特权模式中。更多关于PENDSV的内容参见《Cortex-M3权威指南》中文版(宋岩译)P121-P124

2. 使能/失能 FPU时的中断入栈区别。这个就是修改FPU支持的重点,在STM32F4中,发生中断时会将部分寄存器入栈,再进入中断全程,但是使能和失能FPU这两两种情况的入栈流程是有区别的。
a). 首先是普通情况下,不使用FPU的时候,这个时候CORTEX-M4是跟CORTEX-M3一样的入栈方式,一个异常到来的时候,系统自动将R1-R3、R12、LR、PC、xPSR入栈,这个时候UCOS官方移植版会接着将剩下的R4-R11入栈,保证当前任务的执行上下文全部保存起来,在os_cpu_a.asm的OS_CPU_PendSVHandler中有如下语句:
    SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack    STM     R0, {R4-R11}

b). 在使用FPU的情况下,异常到来的时候,CORTEX-M4会将部分FPU的寄存器也一起自动入栈,包括一个未知的字,一个FPSCR寄存器,以及S15-S0,所以如果要使UCOS支持FPU,就必须配合M4的这种入栈/出栈行为相应地修改任务堆栈的结构以及任务切换时的入栈/出栈汇编代码

3. 要修改的有两个地方,一个是任务初始化时的堆栈结构设置,在os_cpu_c.c的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;                                              /* revent compiler warning                               */

    p_stk = &p_stk_base[stk_size];                          /* Load stack pointer                                     */
                                                                /* Align the stack to 8-bytes.                            */
    p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8);
                                                            /* Registers stacked as if auto-saved on exception        */
    *--p_stk = (CPU_STK)0x01000000u;                        /* xPSR                                                   */
    *--p_stk = (CPU_STK)p_task;                             /* Entry oint                                            */
    *--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);
}

需要在中间增加FPU寄存器的保存结构,修改成下面的代码,红色部分即是修改的,使用两人个宏来判断是否需要增加此结构,以便用户自由地在MDK设置中设置是否启用FPU,而不用亲自修改该部分代码,为些需要在该文件头中#include  "stm32f4xx.h"
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;                                              /* revent compiler warning                               */

    p_stk = &p_stk_base[stk_size];                          /* Load stack pointer                                     */
                                                                /* Align the stack to 8-bytes.                            */
    p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8);
                                                            /* Registers stacked as if auto-saved on exception        */
        #if(__FPU_PRESENT == 1)&&(__FPU_USED == 1)
        *--p_stk = (CPU_STK)0x00000000u;                        /*unknow 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;                        /*S09                                                     */
        *--p_stk = (CPU_STK)0x08080808u;                        /*S08                                                     */
        *--p_stk = (CPU_STK)0x07070707u;                        /*S07                                                     */
        *--p_stk = (CPU_STK)0x06060606u;                        /*S06                                                     */
        *--p_stk = (CPU_STK)0x05050505u;                        /*S05                                                     */
        *--p_stk = (CPU_STK)0x04040404u;                        /*S04                                                     */
        *--p_stk = (CPU_STK)0x03030303u;                        /*S03                                                     */
        *--p_stk = (CPU_STK)0x02020202u;                        /*S02                                                     */
        *--p_stk = (CPU_STK)0x01010101u;                        /*S01                                                     */
        *--p_stk = (CPU_STK)0x00000000u;                        /*S00                                                     */
        #endif
    *--p_stk = (CPU_STK)0x01000000u;                        /* xPSR                                                   */
    *--p_stk = (CPU_STK)p_task;                             /* Entry oint                                            */
    *--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);
}
第二个需要修改的地方是任务切换函数,上面说了UCOS使用PENDSV异常来执行任务切换动作,所以在源码中找出PENDSV异常例程的代码,在os_cpu_a.asm文件中,使用汇编编写,找到OS_CPU_PendSVHandler函数,原型如下:
OS_CPU_PendSVHandler
    CPSID   I                                                   ; revent interruption during context switch
    MRS     R0, SP                                             ; SP 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
    USH    {R14}                                               ; Save LR exc_return value
    LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();
    BLX     R0
    OP     {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     SP, 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

修改后为:
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 enable the FPU
    SUBS    R0, R0, #0X40
        VSTM    R0, {S16-S31}

    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 enable FPU
        VLDM    R0, {S16-S31}
        ADDS    R0, R0, #0X40
        
        
    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


这些还需要在程序一开始启动FPU,我找到cstartup.s启动文件的Reset_Handler中开头有一段被注释掉的FPU启动代码,将些注释释放出来即可


同时需要在Project->Options->Target右边的Code Generation中选择“Use FPU”.

至此,修改工作完成,测试一下跑了两个任务执行浮点运算,相互不干扰,正常运行!!

附修改后的工程源码,删除了一些不必要的代码。
回复

使用道具 举报

88

主题

7377

帖子

5

精华

资深版主

Rank: 8Rank: 8

积分
14980
金钱
14980
注册时间
2013-11-13
在线时间
1823 小时
发表于 2015-2-5 16:32:30 | 显示全部楼层
回复【2楼】augustedward:
---------------------------------
你把FPU关闭了的话,那FPU就没用了的啊,我也遇到过F4使用printf的时候出问题,使用了8字节对齐解决了的,但是我的不是进hardfault的,是printf出来的是乱码。你的在开FPU以后进hardfault估计是UCOSII在移植的时候没有处理好FPU吧。
开往春天的手扶拖拉机
回复

使用道具 举报

28

主题

1489

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1656
金钱
1656
注册时间
2013-7-24
在线时间
1 小时
发表于 2015-2-5 16:33:15 | 显示全部楼层
你这是因噎废食啊。
于20150522停用该账号:http://www.microstar.club
回复

使用道具 举报

9

主题

1385

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
11912
金钱
11912
注册时间
2013-3-8
在线时间
1269 小时
 楼主| 发表于 2015-2-5 16:35:33 | 显示全部楼层
回复【3楼】zuozhongkai:
---------------------------------
我也改过了8字节对齐,还是不行,不知道要怎么改。
回复

使用道具 举报

9

主题

1385

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
11912
金钱
11912
注册时间
2013-3-8
在线时间
1269 小时
 楼主| 发表于 2015-2-5 16:36:21 | 显示全部楼层
回复【4楼】styleno1:
---------------------------------
我也不想去掉。不过现在项目里没有用到FPU,就先去掉了。
回复

使用道具 举报

2

主题

7

帖子

0

精华

新手上路

积分
46
金钱
46
注册时间
2016-7-16
在线时间
12 小时
发表于 2017-2-27 15:23:51 | 显示全部楼层
大家看三楼:帖子发表于2015年2月5日,但是最后却修改于2013年。
但是我也想说:三楼的说法正解,解决了两天,就是三楼解决了问题!
回复

使用道具 举报

0

主题

4

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2019-8-26
在线时间
4 小时
发表于 2019-12-19 10:57:09 | 显示全部楼层
楼主查看一下:startup*****.s文件,看看Reset handler这个函数里是否有FPU初始化这段。
                                IF {FPU} != "SoftVFP"
                                                ; Enable Floating Point Support at reset for FPU
                LDR.W   R0, =0xE000ED88         ; Load address of CPACR register
                LDR     R1, [R0]                ; Read value at CPACR
                ORR     R1,  R1, #(0xF <<20)    ; Set bits 20-23 to enable CP10 and CP11 coprocessors
                                                ; Write back the modified CPACR value
                STR     R1, [R0]                ; Wait for store to complete
                DSB
               
                                                ; Disable automatic FP register content
                                                ; Disable lazy context switch
                LDR.W   R0, =0xE000EF34         ; Load address to FPCCR register
                LDR     R1, [R0]
                AND     R1,  R1, #(0x3FFFFFFF)  ; Clear the LSPEN and ASPEN bits
                STR     R1, [R0]
                ISB                             ; Reset pipeline now the FPU is enabled
                ENDIF
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2020-5-5
在线时间
6 小时
发表于 2020-5-15 16:12:26 | 显示全部楼层
augustedward 发表于 2015-2-5 15:53
本帖最后由&nbsp;不要神话&nbsp;于&nbsp;2013-8-10&nbsp;16:28&nbsp;编辑


基于CORTEX-M4的STM32F407最大 ...

为什么我没有这个use fpu
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-1 21:48

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表