STM32 FPU的使用

 

浮点运算一直是定点CPU的难题,对于8位单片机来说已经完全是噩梦,对32为单片机来说也不会有多大改善。

虽然将浮点数进行Q化处理能充分发挥32位单片机的运算性能,但是精度受到限制而不会太高。

对于有FPU(浮点运算单元)的单片机或者CPU来说,浮点加法只是几条指令的事情。

        现在又FPU或者硬件浮点运算能力的主要有高端DSP(比如TI F28335/C6000/DM6XX/OMAP等),通用CPU(X87数学协处理器)和高级的ARM+DSP处理器等。

加F-float,即支持浮点指令集,因此在处理数学运算时能比M0/M3高出数十倍甚至上百倍的性能,但是要充分发挥FPU的数学性能,还需要一些小小的设置:

        1.编译控制选项:虽然STM32F4XX固件库的例程之system_stm32f4XXX.c文件中添加了对应的代码,但给用户评估使用的STM32F4-Discovery例程中却没有,因此MDK4.23编写浮点运算程序时,虽然编译器正确产生了V指令来进行浮点运算,但是因为system_stm32f4XXX.c文件没有启用FPU,因此CPU执行时只认为是遇到非法指令而跳转到HardFault_Handler()中断中原地踏步。因此要保证这个错误不发生,必须要在system_init()函数里面添加如下代码:

/* FPU settings ------------------------------------------------------------*/ 

  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) 

    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */ 

  #endifProject->Options for target "XXXX")

中的C/C++选项卡的Define中加入如下的语句:__FPU_PRESENT=1,__FPU_USED =1。这样编译时就加入了启动FPU的代码,CPU也就能正确高效的使用FPU进行简单的加减乘除了。

但这还远远不够。对于复杂运算,比如三角函数,开方等运算,如果编程时还是使用math.h头文件,那是没法提升效率的:

因为math.h头文件是针对所有ARM处理器的,其运算函数都是基于定点CPU和标准算法,并没有预见使用FPU的情况,需要很多指令和复杂的过程才能完成运算,也就增加了运算时间。

因此要充分发挥M4F的浮点功能,就需要使用固件库自带的arm_math.h,这个文件根据编译控制项(__FPU_USED == 1)来决定是使用那一种函数方法:

如果没有使用FPU,那就调用keil的标准math.h头文件中定义的函数;

如果使用了FPU,那就是用固件库自带的优化函数来解决问题。

比如正余弦三角函数的计算,完成三角函数的计算就要使用arm_sin_f32()或者arm_cos_f32(),在arm_math.h中是这么定义的。

当然,STM32F4固件库还提供了其他很有用的数学函数,都位于DSP_Lib文件夹

 

SOP:

若使用的是STM32CubeMX生成的工程,DSP库文件就在工程目录中,位于.\Drivers\CMSIS\Lib\ARM,里面有4个文件:

STM32H7系列浮点数运算和定点运算 stm32浮点运算能力_STM32H7系列浮点数运算和定点运算

 

 

 点击 Project -> Options for Target,打开工程选项界面,点击Target选项卡,在Code Generation区域的Floating Point Hardware中选择Single Precision(单精度)。

STM32H7系列浮点数运算和定点运算 stm32浮点运算能力_STM32H7系列浮点数运算和定点运算_02

 

 

点击C/C++选项卡,在Preprocessor Symbols区域的Define中添加如下内容:

ARM_MATH_CM4,__TARGET_FPU_VFP,__FPU_PRESENT=1

 stm32f4xx.h 头文件里面

#define __FPU_PRESENT 1

在 system_stm32f4xx_c 文件里面开启,代码如下:

void 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
……//省略部分代码
}