打印
[技术问答]

新唐M451 如何打开FPU运算单元?

[复制链接]
2530|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
断桥残雪_98|  楼主 | 2015-11-16 21:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这两天在调程序,发现只要有小数点运算,单片机就死了,突然想到,这个是有FPU运算单元,是不是没有打开就变成这样,从来没有用过,不知道什么使用,是否有大侠用过这个东西,希望能分享分享!先谢了!
沙发
mintspring| | 2015-11-16 22:08 | 只看该作者
要看你多复杂的小数运算,FPU可以处理单浮点运算,需要配置使用才行。

使用特权

评论回复
板凳
断桥残雪_98|  楼主 | 2015-11-17 10:13 | 只看该作者
本帖最后由 断桥残雪_98 于 2015-11-17 10:15 编辑
mintspring 发表于 2015-11-16 22:08
要看你多复杂的小数运算,FPU可以处理单浮点运算,需要配置使用才行。

我只要单精度浮点运算就好了,请问这个需要什么配置呢?是否有详细的配置方法?我用的是MDK5.12的

使用特权

评论回复
地板
小猫爱吃鱼| | 2015-11-17 16:58 | 只看该作者
你的浮点数太复杂了吧

使用特权

评论回复
5
捉虫天师| | 2015-11-17 19:55 | 只看该作者
近年,在Cortex-M3之后ARM公司又推出Cortex-M4内核,和之前的M3内核的区别之一就是M4带一个单精度浮点运算单元(PFU)。本文就FPU单元进行一个简单介绍,帮助工程师更快的理解FPU单元。

Cortext-M系列内核的指令集
从ARM公司发布的白皮书看,Cortex-M系列内核的指令集如下图所示:

                       

从上图可以看出,Corte-M系列的指令是向下兼容的,M0/M1的指令最少,M0/M1 和M3的指令都使用于M4的芯片。

Cortex-M4的指令集分两部分,一部分是在M3的指令集外增加了一些扩展功能。另一部即上图中粉红色部分,就是用于FPU单元的单精度浮点运算指令。这部分指令都是用V-开头的汇编指令,仅在FPU功能被使能时使用。

需要注意的是FPU单元是指的芯片上的一个独立于CPU处理的浮点运算单元,整个单元在大多数厂家的芯片中都是可以被使能和关闭的。相对于芯片,编译器也设置了相应的FPU功能开启/关闭的选项,在编译时需要告诉编译器是否开启FPU功能。编译器一旦开启FPU功能,在处理单精度浮点运算的语句时就会用带V-开头的汇编指令进行编译。

如果编译器使能了FPU功能,而芯片未开启FPU单元,程序运行到浮点语句时就会出现异常。相反,如果编译器未使能FPU功能,芯片即使开启了FPU单元,程序还是会按照未使能FPU的代码进行处理。



编译器中的FPU功能使能
以KEIL为例,在创建一个CORTEX-M4的工程后,在工程的options for target “XXX” 窗口的Target页面中选择是否开启fpu功能。如下图所示:

    编译器通过该选项来判断是否使用V开头的浮点运算指令。

一旦选择“use FPU”功能,如果代码中带有单精度浮点运算的代码,编译器就会使用带V的FPU单元汇编指令,无论芯片是否开启了FPU单元功能。如果选择不使用FPU功能,即使芯片开启了FPU单元,编译器一样不会采用带V的汇编指令。

3. 例程分析

    下面用一个实例来分析开启、关闭FPU单元的程序处理。

先上代码:

001.

static float fDat1  = 0.0;

002.

static float fDat2  = 0.01;

003.

//******************************************

004.

// fpu test.

005.

//******************************************

006.

int main(void)

007.

{

008.

    int i;

009.

    FPUEnable();

010.

    FPUStackingEnable();

011.

    for (i = 0; i <100; i++)

012.

    {

013.

        fDat1 = fDat1 + fDat2;

014.

    }

015.

}

其中011.~014. 行在开启编译器FPU功能后,编译出来的代码为:

MOVS

r0, #0x00

VLDR

s0,   [r1,#0x04]

VLDR

s1,   [r1,#0x00]

ADDS

r0, r0, #1

CMP

r0, #0x64

VADD.F32

s1,s1,s0

VSTR

s1,   [r1, #0x00]

BLF

0x00000316

其中红色标注的都是以V-开头的汇编代码,这些代码在FPU单元中运行。



如果关闭编译器的FPU功能,编译出来的代码如下:

MOVS

r4, #0x00

LDR

r6, [r5,#0x04]

LDR

r0, [r5, #0x00]

MOV

r1, r6

BL.W

__aeabi_fadd(0x0000029C)

ADDS

r4, r4, #1

STR

r0, [r5, #0x00]

CMP

r4, #0x64

BLT

0x00000430

其中红色标注部分是程序执行浮点加法运算的部分,调用了单精度浮点运算的库函数。

使用特权

评论回复
6
捉虫天师| | 2015-11-17 19:56 | 只看该作者
编译器和指令都必须打开FPU单元,所以在你建立工程的时候要勾选FPU开启相关的资源才可以。

使用特权

评论回复
7
643757107| | 2015-11-17 21:17 | 只看该作者
该功能应该属于DSP核心的,所以新建工程时候要添加DSP支持才行。

使用特权

评论回复
8
734774645| | 2015-11-17 21:34 | 只看该作者
Cortex-M4的指令集分两部分,一部分是在M3的指令集外增加了一些扩展功能。另一部即上图中粉红色部分,就是用于FPU单元的单精度浮点运算指令。这部分指令都是用V-开头的汇编指令,仅在FPU功能被使能时使用。不知道这个的图在哪儿,看不出来锕

使用特权

评论回复
9
734774645| | 2015-11-17 21:59 | 只看该作者
看那个内核的头文件:core_cm4.h
/** __FPU_USED indicates whether an FPU is used or not. For this, __FPU_PRESENT has to be checked prior to making use of FPU specific registers and functions.
*/
#if defined ( __CC_ARM )
  #if defined __TARGET_FPU_VFP
    #if (__FPU_PRESENT == 1)
      #define __FPU_USED       1
    #else
      #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
      #define __FPU_USED       0
    #endif
  #else
    #define __FPU_USED         0
  #endif

#elif defined ( __ICCARM__ )
  #if defined __ARMVFP__
    #if (__FPU_PRESENT == 1)
      #define __FPU_USED       1
    #else
      #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
      #define __FPU_USED       0
    #endif
  #else
    #define __FPU_USED         0
  #endif

#elif defined ( __TMS470__ )
  #if defined __TI_VFP_SUPPORT__
    #if (__FPU_PRESENT == 1)
      #define __FPU_USED       1
    #else
      #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
      #define __FPU_USED       0
    #endif
  #else
    #define __FPU_USED         0
  #endif

#elif defined ( __GNUC__ )
  #if defined (__VFP_FP__) && !defined(__SOFTFP__)
    #if (__FPU_PRESENT == 1)
      #define __FPU_USED       1
    #else
      #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
      #define __FPU_USED       0
    #endif
  #else
    #define __FPU_USED         0
  #endif

#elif defined ( __TASKING__ )
  #if defined __FPU_VFP__
    #if (__FPU_PRESENT == 1)
      #define __FPU_USED       1
    #else
      #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
      #define __FPU_USED       0
    #endif
  #else
    #define __FPU_USED         0
  #endif
#endif
根据头文件的定义开启FPU功能。

使用特权

评论回复
10
598330983| | 2015-11-17 22:03 | 只看该作者
__FPU_USED indicates whether an FPU is used or not. For this, __FPU_PRESENT has to be checked prior to making use of FPU specific registers and functions
根据这个意思,是在宏里面定义上这两个就行了,定义第一个使用FPU功能,定义第二个宏是否使用专用寄存器。

使用特权

评论回复
11
mintspring| | 2015-11-17 22:08 | 只看该作者
开启这个需要使用内核头文件,然后在主函数的宏里面调用开启的函数,这里就是检测有没有包含那个宏,因为预编译会检测。

使用特权

评论回复
12
125008301| | 2015-11-18 09:43 | 只看该作者

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

39

帖子

0

粉丝