stm32使用FPU时注意事项

发布者:SereneVoyage最新更新时间:2017-11-07 来源: eefocus关键字:stm32  FPU 手机看文章 扫描二维码
随时随地手机看文章

除了网上的教程外,还要特别注意,当运算中有浮点的数字时要把,数字后面加上一个f。例如表达式中有4.321参与运算。。当你不在4.321后加f时,stm32F405的片子不知道把他当做单精度float用FPU来运算,,默认可能是当做double来运算(我不确定),运算速度还是很慢。。切记所有浮点数字后面加上f,,,,有时候keil会提示warning:  #1035-D: single-precision operand implicitly converted to double-precision 这句话的意思就是单精度运算隐式转换成了双精度运算了。这个时候就要在单精度数字后面加个f


keilmdk的设置中完整的define是USE_STDPERIPH_DRIVER,STM32F4XX,__FPU_PRESENT=1,__FPU_USED =1,ARM_MATH_CM4,__CC_ARM

要在MDK中有个选项设置 usr FPU


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的数学性能,还需要一些小小的设置:


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*2)|(3UL << 11*2)); 
  #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             

         #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文件夹


关键字:stm32  FPU 引用地址:stm32使用FPU时注意事项

上一篇:STM32使用BSRR和BRR寄存器快速操作GPIO端口
下一篇:stm32串口发送数据,丢失字节问题分析

推荐阅读最新更新时间:2024-03-16 15:43

STM32单片机对正交编码器的驱动
STM32正交编码器驱动,引入(突变)带进位的位置环和速度环 #include “stm32f10x.h” #include “stm32f10x_encoder.h” #include “sys.h” #include “usart.h” #include “led.h” #define COUNTER_RESET(u16)0 #define ICx_FILTER(u8) 0 // 6《-》 670nsec #define TIMx_PRE_EMPTION_PRIORITY 1 #define TIMx_SUB_PRIORITY 0 //#define MAX_COUNT ENCODER_TIM_PERIOD/2 volat
[单片机]
FreeRTOS移植,基于STM32 HAL库
一、硬件准备 一个STM32开发板(STM32F429IGT6),及其电源线等; 一个ST-Link下载器及其连接线等。 二、软件准备 FreeRTOS源码(V9.0.0); 一个基于STM32 HAL库的基础例程(跑马灯例程)。 三、移植FreeRTOS 3.1 添加FreeRTOS源码至工程 添加源代码至工程目录,添加至工程分组中,添加相关头文件路径 编译,提示找不到 FreeRTOSConfig.h 3.2 添加 FreeRTOSConfig.h 文件来源:事先参考众多例程中的 FreeRTOSConfig.h 后,总结出来的 编译结果为:2个error。SVC_Handler() 和 PendSV_Handler()
[单片机]
STM32-按键输入实验学习笔记
按键扫描函数key.c片段: //按键初始化函数 //特别注意:在该函数之后,JTAG将无法使用(SWD也无法使用) //如果想JTAG仿真,可以屏蔽该函数。 //PA0.13.15 设置成输入 void KEY_Init(void) { RCC- APB2ENR|=1 2; //使能PORTA时钟 GPIOA- CRL&=0XFFFFFFF0;//PA0设置成输入 GPIOA- CRL|=0X00000008; GPIOA- CRH&=0X0F0FFFFF;//PA13,15设置成输入 GPIOA- CRH|=0X80800000; GPIO
[单片机]
STM32的便携式手机蓝牙考勤机系统设计
引言     目前,大部分考勤系统还是磁卡考勤系统,这类系统不仅签到速度慢,而且终端设备和磁卡也造成一定成本和浪费;指纹考勤、人脸识别考勤、视网膜考勤等新一代考勤技术虽然大大地提高了考勤效率和准确率,但是这类考勤机的费用较高、操作比较麻烦。以上几种都是采用被动式的考勤机制,科技的发展和生活节奏的加快为被动式考勤方式带来了新的挑战,手机蓝牙考勤机就是针对以上考勤机的缺点而设计的,使用手机蓝牙考勤机可以实现人员经过即可轻松签到。 1 考勤机硬件设计 1.1 系统整体硬件设计     如图1所示,考勤机系统主要由以下5个部分组成:基于Cortex-M3核的STM32F103RBT6微处理器作为核心控制器件,主要负责控制系统各部分的工作
[单片机]
<font color='red'>STM32</font>的便携式手机蓝牙考勤机系统设计
stm32驱动lora模块sx1278
开发环境 keil5 子设备读取Ds18b20数据,通过iic显示到OLED 屏幕上,同时用spi协议发送给lora,再传给网关。 网关接收到数据在OLED 屏幕上显示。 单片机源码: #include stdio.h #include DELAY/Delay.h #include UART/uart.h #include ADC/ADC.h #include LED/LED.h #include IIC/IIC.h #include OLED/OLED.h #include SPIx/SPIx.h #include SX1278/SX1278.h #define ALARM 22 int ma
[单片机]
STM32学习笔记之RCC
时钟 三种不同的时钟源可被用来驱动系统时钟(SYSCLK): ● HSI振荡器时钟 ● HSE振荡器时钟 ● PLL时钟 这些设备有以下2种二级时钟源: ● 40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。RTC用于从停机/待机模式下自动唤醒系统。 ● 32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)。 当不被使用时,任一个时钟源都可被独立地启动或关闭,由此优化系统功耗。 1.当HSI被用于作为PLL时钟的输入时,系统时钟能得到的最大频率是64MHz。 2.对于内部和外部时钟源的特性,请参考相应产品数据手册中 电气特性 章节。 用户可通过多个预分频器配置AHB、高
[单片机]
stm32 nvic的理解
因为stm32有43个中断源,当同时用到多个中断时,就要指定其中断的优先级了。 nvic即是中断向量的控制!由SCB- AIRCR寄存器控制,SCB- AIRCR中目前只用到4位,也就是最高能有16级中断嵌套,如果全使用的话可以达到256级 (1);选用优先级分组(实际就是选几位用于主优先级几位用于辅优先级) group0:选0位用于主优先级,4位用于辅优先级。 group1:选1位用于主优先级,3位用于辅优先级。 group2:选2位用于主优先级,2位用于辅优先级。 group3:选3位用于主优先级,1位用于辅优先级。 group4:选4位用于主优先级,0位用于辅优先级。 (2)这样打个比方不恰当的比方吧,如
[单片机]
STM32的下载及调试模式 接口
使用的最多的调试方式莫过于 JTAG 和SWD方式。 JTAG: JTAG (Joint Test Action Group,联合测试行动小组)是一种国际标准测试协议(IEEE 1149.1兼容),主要用于芯片内部测试。现在多数的高级器件都支持JTAG协议,如ARM、DSP、FPGA器件等。标准的JTAG接口是4线:TMS、 TCK、TDI、TDO,分别为模式选择、时钟、数据输入和数据输出线。相关JTAG引脚的定义为: TMS:模式选择,TMS用来设置JTAG接口处于某种特定的测试模式; TCK:时钟输入; TDI:数据输入,数据通过TDI引脚输入JTAG接口; TDO:数据输出,数据通过TDO引脚从JTAG接
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved