FPU

STM32的HAL库如何开启FPU?

已邀请:

admin

赞同来自: 忙卟迭

还没搞过,帮顶先.......貌似提供的有例程.....不过,还没看.....

admin

赞同来自:

调试别的程序,偶然看到了这个,
是不是在keil配置里面设置了USE FPU就可以了啊,
还要进行什么操作吗?
貌似这样设置之后,keil编译的时候就自动调用了浮点运算了.......
不对的话请指正下.....

6.png

admin

赞同来自:

刚刚找了一篇文章,自己记录一下...

大致意思是:要实现简单的加减乘除的浮点运算,除了以上的设置外,还要在上面图中的c/c++选项卡中的define中添加__FPU_PRESENT=1,__FPU_USED =1
9.png

要是复杂的例如开方,乘方等等的就要按照下面的方法来....



STM32-F4属于Cortex-M4F构架,这和M0、M3的最大不同就是多了一个F-float,即支持浮点指令集,因此在处理数学运算时能比M0/M3高出数十倍甚至上百倍的性能,但是要充分发挥FPU的数学性能,还需要一些小小的设置:
1.编译控制选项:虽然STM32F4XX固件库的例程之system_stm32f4XXX.c文件中添加了对应的代码,但给用户评估使用的STM32F4-Discovery例程中却没有,因此MDK4.23编写浮点运算程序时,虽然编译器正确产生了V指令来进行浮点运算,但是因为system_stm32f4XXX.c文件没有启用FPU,因此CPU执行时只认为是遇到非法指令而跳转到HardFault_Handler()中断中原地踏步。因此要保证这个错误不发生,必须要在system_init()函数里面添加如下代码:

#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10[i]2)|(3UL << 11[/i]2));
#endif

注意:上面的这个程序我们如果工程师stm32cubemx生成的,那么里面已经写好了,无需再次写了.

因为这个选项是有条件编译控制的,因此需要在工程选项(Project->Options for target "XXXX")中的C/C++选项卡的Define中加入如下的语句:__FPU_PRESENT=1,__FPU_USED =1。这样编译时就加入了启动FPU的代码,CPU也就能正确高效的使用FPU进行简单的加减乘除了。
但这还远远不够。对于复杂运算,比如三角函数,开方等运算,如果编程时还是使用math.h头文件,那是没法提升效率的:因为math.h头文件是针对所有ARM处理器的,其运算函数都是基于定点CPU和标准算法(IEEE-754),并没有预见使用FPU的情况,需要很多指令和复杂的过程才能完成运算,也就增加了运算时间。因此要充分发挥M4F的浮点功能,就需要使用固件库自带的arm_math.h,这个文件根据编译控制项(__FPU_USED == 1)来决定是使用那一种函数方法:如果没有使用FPU,那就调用keil的标准math.h头文件中定义的函数;如果使用了FPU,那就是用固件库自带的优化函数来解决问题。
在arm_math的开头部分是有这些编译控制信息:
#ifndef _ARM_MATH_H
#define _ARM_MATH_H

#define __CMSIS_GENERIC

#if defined (ARM_MATH_CM4)
#include "core_cm4.h"
#elif defined (ARM_MATH_CM3)
#include "core_cm3.h"
#elif defined (ARM_MATH_CM0)
#include "core_cm0.h"
#else
#include "ARMCM4.h"
#warning "Define either ARM_MATH_CM4 OR ARM_MATH_CM3...By Default building on ARM_MATH_CM4....."
#endif

#undef __CMSIS_GENERIC
#include "string.h"
#include "math.h"
就是说如果不使用CMSIS的,就会调用keil自带的标准库函数。否则就用CMSIS的定义。这里因为是用的STM32F4,所以应该要ARM_MATH_CM4控制,即加入core_cm4.h,否则就用使用ARMCM4.h——但在编译时keil会提示找不到这文件。因此需要在工程选项之C/C++选项卡的define中继续加入语句ARM_MATH_CM4。
加入上述编译控制项之后,高级数学函数的使用基本没问题了,比如正余弦三角函数的计算。但需要注意,如果你直接使用sin()、cos()、sqrt()这样的函数,那结果还算调用keil的math.h,你可以在debug时看对应的代码,其汇编指令为BL.W __hardfp_xxx。因此这时要完成三角函数的计算就要使用arm_sin_f32()或者arm_cos_f32(),用法不变,这两个函数的原型分别在arm_sin_f32.c和arm_cos_f32.c中。通过对256点三角函数表的查询和插值算法得到任意角度的精确函数值,这就比“原装”的sin()、cos()快多了。
当然有些例外的是开发函数sqrt(),在arm_math.h中是这么定义的:
static __INLINE arm_status arm_sqrt_f32(float32_t in, float32_t *pOut)
{
if(in > 0)
{
// #if __FPU_USED
#if (__FPU_USED == 1) && defined ( __CC_ARM )
*pOut = __sqrtf(in);
#else
*pOut = sqrtf(in);
#endif
return (ARM_MATH_SUCCESS);
}
else
{
*pOut = 0.0f;
return (ARM_MATH_ARGUMENT_ERROR);
}
}
即开方用的函数是arm_sqrt_f32(),其中首先判断被开发的书是否大于0,只有大于0的才能进行运算,否则输出结果为0并返回“错误”标志。如果大于0,并且实用了FPU和__CC_ARM控制项,那调用__sqrtf()来完成编译,否则调用sqrtf()——这个sqrtf()是能在keil的math.h中找到的,即调用子函数来完成运算,而__sqrtf()呢?新出现的,相信大家都能猜到是什么玩意儿:对,就是VSQRT指令!因此要把这点性能也要发挥出来,就需要工程选项之C/C++选项卡的define中继续加入语句__CC_ARM才行。大家可以比较一下是否加入__CC_ARM编译后会汇编代码的差别巨大差别。
当然,对于arm_sqrt_f32()函数还是有些麻烦,如果你确认被开方的书是大于等于0的,那就直接使用__sqrtf()函数完成运算,即一条简单的VSQRT指令。
STM32F4固件库还提供了其他很有用的数学函数,都位于DSP_Lib文件夹,请大家慢慢探索,Discovery!

admin

赞同来自: 忙卟迭

或者在文件 core_cm4.h中的第187行到195行之间的代码改成如下: 即将0改成1


#ifndef __FPU_PRESENT
#define __FPU_PRESENT 0
#warning "__FPU_PRESENT not defined in device header file; using default!"
#endif

#ifndef __MPU_PRESENT
#define __MPU_PRESENT 0
#warning "__MPU_PRESENT not defined in device header file; using default!"
#endif


但是,不建议这样改动,最好还是用楼上的图示方法

>这个帖子里写的不错,http://www.amobbs.com/thread-5520187-1-1.html

忙卟迭

赞同来自:

谢谢回复!我明天测试一下

admin

赞同来自:

你好,测试过了没呢?我都不知道怎么去测试。。。。。。
如果有可行的方案或者测试还算满意的,能不能共享下你的设置或者测试方法?

东皇

赞同来自:

讲得很细致。学习了。

忙卟迭

赞同来自:

找到了比较官方的说法,具体参见附件

该问题目前已经被锁定, 无法添加新回复