打印

请教关于STM32F4的浮点单元问题

[复制链接]
9769|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
sonicll|  楼主 | 2011-11-24 13:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 sonicll 于 2011-11-24 13:55 编辑

使用环境为 STM32F4DISCOVERY + MDK4.22

因为看到MDK的options for target选项里,可以选择使用或不使用FPU,想看看使用FPU和不使用FPU在浮点计算上有多大差距,就写了个简单的程序,加减乘除计算,看看每秒钟能计算多少次,把次数和计算结果从串口输出来,代码如下

#include "stm32f4xx.h"
#include <stdio.h>
#include <string.h>


void InitTIM(void);
void InitUart(void);
void UartSendStr(char buf[],int length);

char TIM2_Flag = 0;

int main(void)
{                                                                                                            
        unsigned long count = 0;
        float i = 0;
        
float j = 0.134245223423424556;
        
float k = 0.253252534536366666;

        char buffer[128];

        SystemInit();
        InitTIM();
        InitUart();

        while(1)
        {
                i = (j+5123)*821/(k-456);
               
                count++;
                                                                                                        
                if (TIM2_Flag) //TIM2的中断处理函数里把TIM2_Flag置1,周期1秒              
                {
                        TIM2_Flag = 0;
                        
                        sprintf(buffer, "%d,%f\n",count,i);
                        
                        UartSendStr(buffer,strlen(buffer));
                        
                        count = 0;               
                }
        }
}


void UartSendStr(char buf[],int length)
{
        int i;

        for(i=0;i<length;i++)
        {
                USART_SendData(USART3, buf);
                while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);        
        }
}

void InitUart(void)
{
        GPIO_InitTypeDef  GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;  
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

        GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8 | GPIO_Pin_9;
        GPIO_Init(GPIOD, &GPIO_InitStructure);
                                                        
        GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_USART3);
        GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_USART3);

        USART_InitStructure.USART_BaudRate = 115200;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        USART_InitStructure.USART_Parity = USART_Parity_No;
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
                                                                                                
        USART_Init(USART3, &USART_InitStructure);
        USART_Cmd(USART3, ENABLE);

}

void InitTIM(void)
{
        
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
        
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);

        TIM_TimeBaseStructure.TIM_Period = 41999;
        TIM_TimeBaseStructure.TIM_Prescaler = 1999;                           
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;   
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Down;  
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

        TIM_Cmd(TIM2, ENABLE);
        TIM_PrescalerConfig(TIM2, TIM_TimeBaseStructure.TIM_Prescaler, TIM_PSCReloadMode_Immediate);
        TIM_ClearFlag(TIM2, TIM_FLAG_Update);
        TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

}

MDK的选项里,target选项卡里只选择是否使用FPU,其他选项不选;C/C++选项卡里,优化等级选为0,其他选项都不选

观察结果为:
使用FPU,count为4657245
不使用FPU,count为916266
区别还是比较明显;

接下来是问题,当我把i、j、k三个变量的类型设成double后,结果变成了这样:
使用FPU,count为284680
不使用FPU,count为530620

我知道F4的FPU是单精度的,但是也不应该出现double类型使用FPU,速度反而下降的现象啊,请大家帮忙看看,是程序问题还是MDK有什么设置不对,工程在附件里

STM32F4_project_demo_20111124.rar

308.01 KB

沙发
liujl| | 2011-11-24 16:40 | 只看该作者
友情顶一下,F4的帖子真少

使用特权

评论回复
板凳
grissiom| | 2011-11-24 17:13 | 只看该作者
看汇编代码,调优化选项

使用特权

评论回复
地板
香水城| | 2011-11-24 21:39 | 只看该作者
LZ看错了吧?

使用特权

评论回复
5
sonicll|  楼主 | 2011-11-25 08:59 | 只看该作者
回香主,我确认没看错,那3个变量设成float没有问题,设成double就是开启FPU速度慢,开发板用的STM32F4DISCOVERY

使用特权

评论回复
6
香水城| | 2011-11-25 09:43 | 只看该作者
也许要看看编译出来的代码,才能知道是怎么回事。

如果有人能问问KEIL,可以得到更准确地答复。

使用特权

评论回复
7
lianshumou| | 2011-11-25 10:41 | 只看该作者
使用FPU后居然只有5倍的性能提升,这是不可能的。我就算全用定点,如果用我用汇编写的浮点算法都比标准库快5倍以上。

使用特权

评论回复
8
sonicll|  楼主 | 2011-11-25 11:04 | 只看该作者
回7楼,这个程序只是个粗略的比较,串口发送也要占用不少时间的,而且没有任何编译优化

使用特权

评论回复
9
IJK| | 2011-11-25 11:40 | 只看该作者
回7楼,这个程序只是个粗略的比较,串口发送也要占用不少时间的,而且没有任何编译优化
sonicll 发表于 2011-11-25 11:04


串口发送应该占不了多少时间,因为1秒才发送1次。
编译优化的影响应该比较大

使用特权

评论回复
10
grissiom| | 2011-11-25 11:41 | 只看该作者
使用FPU后居然只有5倍的性能提升,这是不可能的。我就算全用定点,如果用我用汇编写的浮点算法都比标准库快5倍以上。
lianshumou 发表于 2011-11-25 10:41


问题就在于,人家用的不是定点,而是浮点……

使用特权

评论回复
11
grissiom| | 2011-11-25 11:43 | 只看该作者
我觉得 LZ 可以看看生成的汇编代码,看看 double 类型的有没有用到 FPU ……

使用特权

评论回复
12
pluto55| | 2013-1-11 15:41 | 只看该作者
stm32F4是单精度的,有double类型的数据的话就会调用math.h中的库函数来执行了,根本没有用FPU指令,所以变慢了,看一下汇编代码就知道了

使用特权

评论回复
13
smartmcu| | 2013-1-25 21:43 | 只看该作者
这里的关键是 “不使用FPU” 的设置上。虽然在选项里设置了,但在相应的.h文件里有可能有
#define __FPU_PRESENT             1
这样的语句。

这样,表面上是关了fpu,但其实float还是用了fpu的。也只有这个原因,才是合乎逻辑的解释,否则就太神秘了!:lol

使用特权

评论回复
14
wwwq| | 2013-2-5 18:10 | 只看该作者
这个问题其实就是double引起的,单精度的float采用FPU,而double则使用了库函数,速度自然慢多了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

883

帖子

3

粉丝