美文网首页我爱编程
使用STM32F4的FPU

使用STM32F4的FPU

作者: v0cbc | 来源:发表于2015-11-24 13:31 被阅读535次

参见:STM32F4之FPU性能的充分发挥-设置要点

浮点运算一直是定点CPU的难题,比如一个简单的1.1+1.1,定点CPU必须要按照IEEE-754标准的算法来完成运算,对于8位单片机来说已经完全是噩梦,对32为单片机来说也不会有多大改善。虽然将浮点数进行Q化处理能充分发挥32位单片机的运算性能,但是精度受到限制而不会太高。对于有FPU(浮点运算单元)的单片机或者CPU来说,浮点加法只是几条指令的事情。

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

STM32-F4属于Cortex-M4F构架,这和M0、M3的最大不同就是多了一个F-float,即支持浮点指令集,因此在处理数学运算时能比M0/M3高出数十倍甚至上百倍的性能,但是要充分发挥FPU的数学性能,还需要一些小小的设置:

  • 编译控制选项:虽然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 << 112)); / set CP10 and CP11 Full Access */
#endif

因为这个选项是有条件编译控制的,因此需要在工程选项(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 /* disable NVIC and Systick functions */
#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 /* enable NVIC and Systick functions */
#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!

相关文章

  • 使用STM32F4的FPU

    参见:STM32F4之FPU性能的充分发挥-设置要点 浮点运算一直是定点CPU的难题,比如一个简单的1.1+1.1...

  • 2018-07-13

    Androguard 安装 使用 ARM汇编 汇编指令 伪指令 伪操作 .arch 框架.fpu 协处理器类型 $...

  • PHP创建的csv文件在windows上乱码的问题

    前言 做PHP开发的时候,由于业务需要,可能要经常导出csv文件。使用PHP将数据导出到csv文件不难,使用fpu...

  • C语言读写文件

    C读写文件 使用 fopen(文件名,访问模式) 函数来打开文件,一般有getc/putc , fgets/fpu...

  • 12/18

    stm32f4的systick设置:

  • RTX-阅读随笔

    线程上下文本地堆栈大小 对于 Cortex-M4 FPU 和 Cortex-M7 FPU,线程上下文需要在本地堆栈...

  • Intel x87 FPU的使用基础

    Intel x87 FPU专门用于执行标量浮点计算,可以对单精度浮点(32位)、双精度浮点(64位)以及扩展双精度...

  • 自制tbox大致思路

    选用STM32F4的芯片,使用恩智浦的can收发器,使用移远的通信模组 编写调试can驱动,移动4G模组的驱动,S...

  • STM32F429移植UCOSII笔记

    1.准备相关文件 直接使用官方的STM32F4移植例程,里面也包含UCOSII的源代码。进入官网下载中心:http...

  • 【BLE】NRF52功耗不正常

    可能是因为FPU没有关掉导致,关掉方式如下:

网友评论

    本文标题:使用STM32F4的FPU

    本文链接:https://www.haomeiwen.com/subject/lrvrhttx.html