FPU简介
近年,在Cortex-M3之后ARM公司又推出Cortex-M4内核,ARM Cortex-M4处理器是由ARM专门开发的最新嵌入式处理器,在M3的基础上强化了运算能力,新加了浮点、DSP、并行计算等。Cortex-M4处理器的最大亮点之一,也是本文主要描述的一个功能就是增加了一个单精度浮点单元(FPU),能够高效率处理较为复杂的浮点运算,如电机闭环控制、PID算法、快速傅里叶变换等。
Cortex-M4的指令集分两部分,一部分是在M3的指令集外增加了一些扩展功能。另一部份就是用于FPU单元的单精度浮点运算指令。
浮点运算指令都是V开头的汇编指令,用于FPU单元的单精度浮点运算,只有当FPU开启后才能使用这些指令,否则会产生硬fault异常。
DSP库
如果要使用FPU单元来进行浮点运算,就需要在工程中加入DSP库。
FPU属于ARM架构一部分,不是厂商MCU特有,所以在ARM包安装中已经包含。
在keil包路径下能找到
D:\EmbededSofts\KeilMDK5_PACKS\ARM\CMSIS-DSP\1.14.2\Source
关于这个函数库的详细信息,请移步官网:
arm_math.h File Reference
DSP库主要包含以下几个分库:
BasicMathFunctions
基本数学函数:提供浮点数的各种基本运算函数,如向量加减乘除等运算。
CommonTables
arm_common_tables.c文件提供位翻转或相关参数表。
ComplexMathFunctions
复杂数学功能,如向量处理,求模运算的。
ControllerFunctions
控制功能函数。包括正弦余弦,PID电机控制,矢量Clarke变换,矢量Clarke逆变换等。
FastMathFunctions
快速数学功能函数。提供了一种快速的近似正弦,余弦和平方根等相比CMSIS计算库要快的数学函数。
FilteringFunctions
滤波函数功能,主要为FIR和LMS(最小均方根)等滤波函数。
MatrixFunctions
矩阵处理函数。包括矩阵加法、矩阵初始化、矩阵反、矩阵乘法、矩阵规模、矩阵减法、矩阵转置等函数。
StatisticsFunctions
统计功能函数。如求平均值、最大值、最小值、计算均方根RMS、计算方差/标准差等。
SupportFunctions
支持功能函数,如数据拷贝,Q格式和浮点格式相互转换,Q任意格式相互转换。
TransformFunctions
变换功能。包括复数FFT(CFFT)/复数FFT逆运算(CIFFT)、实数FFT(RFFT)/实数FFT逆运算(RIFFT)、和DCT(离散余弦变换)和配套的初始化函数。
对于一个项目来说,为了工程的完整性和源文的管理,一般将库文件拷贝到项目工程中文件路径下。这里有两种处理用方法。
--使用该目录下的“Lib”库,该文件夹就是FPU相关运算函数库,使用时根据头文件函数名调用库。
--按照常规方式直接拷贝函数库源码,每个浮点运算函数都提供源码,比较好理解和使用。各类函数都有分好类,可以查看源码,具体函数功能和描述官方有标准的手册介绍。
两种方法各有优势,方法一中已将源码编译程库文件,不参与编译过程,只参与链接,编译速度快,但是看不到源码,也就是跳转时无法找到定义;方法二,参与编译、链接过程,编译耗时,但使用时可以查看源码,便于理解和使用。
CMSIS DSP的.LIB库文件
考虑到方便用户使用,ARM官方已编译好Cortex-M各型号的.lib库(静态库)文件,并放置于Lib文件夹。
库文件能在KEIL包的安装路径中找到
D:\EmbededSofts\KeilMDK5_PACKS\ARM\CMSIS\5.6.0\CMSIS\DSP\Lib\ARM
DSP库函数的声明位域头文件arm_math.h中,用户只要简单地将该头文件和.lib文件添加到自己的工程中,即可呼叫DSP库函数。该头文件对于浮点运算单元(FPU)的变量同样适用。
这几种库有啥区别?
arm_cortexM4b_math.lib代表设备为大端模式;
arm_cortexM4bf_math.lib代表设备为浮点大端模式
其中arm_cortexM4l_math.lib代表设备为小端模式
其中arm_cortexM4lf_math.lib代表设备为浮点小端模式
对于F407来说,使用arm_cortexM4lf_math.lib即可。
当导入了该库之后,就不用再添加对应的源文件了,只需要添加对应的头文件即可。
Keil运行环境配置
第一步
首先,我们在例程工程目录下新建:DSP_LIB 文件夹,存放我们将要添加的文件:
arm_cortexM4lf_math.lib 和相关头文件,如下图所示:
Include 文件夹,则是直接拷贝:STM32F4xx_DSP_StdPeriph_Lib_V1.4.0→Libraries→CMSIS→Include 这个 Include 文件夹,里面包含了我们可能要用到的相关头文件。
然后,打开工程,新建 DSP_LIB 分组,并将 arm_cortexM4lf_math.lib 添加到工程里面,如下图所示:
第二步, 添加头文件包含路径
添加好.lib 文件后,我们要添加头文件包含路径,将第一步拷贝的 Include 文件夹和DSP_LIB文件夹,加入头文件包含路径,如下图所示:
第三步, 添加全局宏定义
FPU单元是指的芯片上的一个独立于CPU处理的浮点运算单元,整个单元在大多数厂家的芯片中都是可以被使能和关闭的。相对于芯片,编译器也设置了相应的FPU功能开启/关闭的选项,在编译时需要告诉编译器是否开启FPU功能。编译器一旦开启FPU功能,在处理单精度浮点运算的语句时就会用带V-开头的汇编指令进行编译。
如果编译器使能了FPU功能,而芯片未开启FPU单元,程序运行到浮点语句时就会出现异常。相反,如果编译器未使能FPU功能,芯片即使开启了FPU单元,程序还是会按照未使能FPU的代码进行处理。
为了使用 DSP 库的所有功能,我们还需要添加几个全局宏定义:
1,__FPU_USED
2,__FPU_PRESENT
3,ARM_MATH_CM4
4,__CC_ARM
5,ARM_MATH_MATRIX_CHECK
6,ARM_MATH_ROUNDING
致此,配置已完成。
以下为选读内容
其中,也可以不添加__FPU_PRESENT,在工程里开启即可。
在官方提供的对应MCU型号的头文件中,将FPU选择宏开启,如STM32的“stm32f407xx.h”
一般来说,默认就是开启的。
但是,仅仅只是说明处理器有 FPU 是不够的,我们还需要开启 FPU 功能。开启 FPU 有两种方法,第一种是直接在头文件 STM32f4xx.h 中手动定义宏定义标识符__FPU_USED 的值为 1。也可以直接在 MDK 编译器上面设置,我们在 MDK5 编译器里面,点击 按钮,然后在 Target 选项卡里面,设置 Floating Point Hardware 为 Use Single Precision
经过这个设置,编译器会自动加入标识符__FPU_USED 为 1。这样遇到浮点运算就会使用
硬件 FPU 相关指令,执行浮点运算,从而大大减少计算时间。
关于这两个宏定义的由来
经验证,使用硬件 FPU 和不使用硬件 FPU 对比,同样的条件下,快了近 10 倍,充分体现了 STM32F4 硬件 FPU 的优势。
注意
Cortex M4默认的开启浮点运算功能的,但目前M4只支持单精度浮点运算,单精度浮点运算对于大部分场合来说已经足够使用。
一般情况下,编译器对于小数处理默认是双精度(double)类型,所以在涉及小数运算时,若要使用FPU功能,应该指定为单精度类型,如:float a = 1.23f * 2.34f。
#warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
明明已经定义了__FPU_PRESENT 1
也勾选了__FPU_USED
可能勾选没有生效,直接加上这两个宏定义即可
1,__FPU_USED
2,__FPU_PRESENT