STM32F4的FPU单元讲解
搞STM32F407单片机的时候 看见的关于STM32F4系列的FPU 单元讲解 比较精彩的博客 于是特意转载 和大家分享
转自:http://blog.renren.com/blog/256814551/844695191
浮点运算一直是定点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的数学性能,还需要一些小小的设置:
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 */
#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+DSP库进行FFT运算的测试过程一
测试环境:单片机:STM32F407ZGT6 IDE:Keil5.20.0.0 固件库版本:STM32F4xx_DSP_StdPeriph_Lib_V1.4.0 第一部分:使用源码文件的方式,使 ...
- STM32F4使用FPU+DSP库进行FFT运算的测试过程二
原文地址:http://www.cnblogs.com/NickQ/p/8541156.html 测试环境:单片机:STM32F407ZGT6 IDE:Keil5.20.0.0 固件库版本:STM32 ...
- 玩转X-CTR100 l STM32F4 l FPU单精度浮点性能测试
我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] 本文介绍X-CTR100控制器如何开启ST ...
- 玩转X-CTR100 l STM32F4 l DSP指令集性能测试
我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] 本文介绍X-CTR100控制器 DSP库的 ...
- 【STM32H7教程】第14章 STM32H7的电源,复位和时钟系统
完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第14章 STM32H7的电源,复位和时钟系 ...
- Operating System:操作系统启动总结
现代操作系统的启动引导过程会有所差异,本文仅针对Intel x86系列作讲解,了解原理即可. 系统引导过程总体介绍 系统引导过程主要由以下几个步骤组成(以硬盘启动为例)1.开机:2.BIOS加电自检( ...
- Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Linux下VFP NEON浮点编译
http://blog.csdn.net/liujia2100/article/details/27236477 NEON:SIMD(Single Instruction Multiple Data ...
- 【uTenux实验】写在开始实验之前
1.使用的uTenux内核代码:http://www.uloong.cc/cn/download/uTenux_V1.6.00r180.zip 2.uTenux的特性: 1.微内核 2.开放源码.完 ...
随机推荐
- 获取linq生成的sql语句
命名空间:using System.Data.Objects; var query = db.TxtRes.Join(db.LangRes, a => new { id1 = a.ResID, ...
- hisi出的H264码流结构
hisi出的H264码流结构: IDR帧结构如下: 开始码 + nalu + I帧 + 开始码 + nalu + SPS + 开始码 + nalu + PPS + ...
- 再次写了第一个servlet
费时2小时,熟悉tomcat和编写了第一个servlet
- .NET防止重复提交数据
最近在做一个销售系统的时候,操作人员提交数据的时候数据库竟然会出现多条数据相同的记录,并且是在1秒之内,客户反馈给我们,第一反应是重复提交的问题,检查了下代码,程序执行完成后应该是跳转到别的页面的,可 ...
- Javascript 查找元素
DOM定义了多种查找元素的方法,除了我们常用的getElementById(),还有getElementsByTagName()和getElementsByName().使用这几种方法方法我们可以查找 ...
- CentOS6.7下使用非root用户(普通用户)编译安装与配置mysql数据库并使用shell脚本定时任务方式实现mysql数据库服务随机自动启动
CentOS6.7下使用非root用户(普通用户)编译安装与配置mysql数据库并使用shell脚本定时任务方式实现mysql数据库服务随机自动启动1.关于mysql?MySQL是一个关系型数据库管理 ...
- JavaScript定时机制、以及浏览器渲染机制 浅谈
昨晚,朋友拿了一道题问我: a.onclick = function(){ setTimeout(function() { //do something ... },0); }; JavaScript ...
- HDU 3374 String Problem (KMP+最大最小表示)
HDU 3374 String Problem (KMP+最大最小表示) String Problem Time Limit: 2000/1000 MS (Java/Others) Memory ...
- Delphi中点击DBGrid某一行获得其详细数据方法
http://www.cnblogs.com/leewiki/archive/2011/12/16/2290172.html Delphi中点击DBGrid某一行获得其详细数据方法 前提是用ADOTa ...
- 使用Intent创建Tab页面
前面已经介绍了如何使用TabActivity来创建Activity布局,前面添加Tab页面使用了TabHost.TabSpec如下方法. setContent(int viewId):直接将指定Vie ...