OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 12424|回复: 6

【正点原子探索者STM32F407开发板例程连载+教学】第51章 FPU测试(Julia分形)实验

[复制链接]

230

主题

1950

帖子

10

精华

论坛元老

Rank: 8Rank: 8

积分
4562
金钱
4562
注册时间
2010-12-14
在线时间
32 小时
发表于 2014-12-9 12:50:22 | 显示全部楼层 |阅读模式

第五十一章 FPU测试(Julia分形)实验

 

1.硬件平台:正点原子探索者STM32F407开发板
 2.软件平台:MDK5.1 
 3.固件库版本:V1.4.0

本章,我们将向大家介绍如何开启STM32F4的硬件FPU,并对比使用硬件FPU和不使用硬件FPU的速度差别,以体现硬件FPU的优势。本章分为如下几个部:

51.1 FPU&Julia分形简介

51.2 硬件设计

51.3 软件设计

51.4 下载验证

 

51.1 FPU&Julia分形简介   

本节将分别介绍STM32F4FPUJulia分形。

51.1.1 FPU简介  

FPU即浮点运算单元(Float Point Unit)。浮点运算,对于定点CPU(没有FPUCPU)来说必须要按照IEEE-754标准的算法来完成运算,是相当耗费时间的。而对于有FPUCPU来说,浮点运算则只是几条指令的事情,速度相当快。

STM32F4属于Cortex M4F架构,带有32位单精度硬件FPU,支持浮点指令集,相对于Cortex M0Cortex M3等,高出数十倍甚至上百倍的运算性能。

STM32F4硬件上要开启FPU是很简单的,通过一个叫:协处理器控制寄存器(CPACR)的寄存器设置即可开启STM32F4的硬件FPU,该寄存器各位描述如图51.1.1.1所示:

51.1.1.1 协处理器控制寄存器(CPACR)各位描述

这里我们就是要设置CP11CP104个位,复位后,这4个位的值都为0,此时禁止访问协处理器(禁止了硬件FPU),我们将这4个位都设置为1,即可完全访问协处理器(开启硬件FPU),此时便可以使用STM32F4内置的硬件FPU了。CPACR寄存器这4个位的设置,我们在system_stm32f4xx_c文件里面开启,代码如下:

void SystemInit(void)

{

  /* FPU settings ------------------------------------------------------------*/

  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)

    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */

  #endif

……//省略部分代码

}

此部分代码是系统初始化函数的部分内容,功能就是设置CPACR寄存器的20~23位为1,以开启STM32F4的硬件FPU功能。从程序可以看出,只要我们定义了全局宏定义标识符__FPU_PRESENT以及__FPU_USED1,那么就可以开启硬件FPU。其中宏定义标识符__FPU_PRESENT用来确定处理器是否带FPU功能,标识符__FPU_USED用来确定是否开启FPU功能。

实际上,因为F4是带FPU功能的,所以在我们的stm32f4xx.h头文件里面,我们默认是定义了__FPU_PRESENT1。大家可以打开文件搜索即可找到下面一行代码:

#define __FPU_PRESENT             1   

但是,仅仅只是说明处理器有FPU是不够的,我们还需要开启FPU功能。开启FPU有两种方法,第一种是直接在头文件STM32f4xx.h中定义宏定义标识符__FPU_USED的值为1。也可以直接在MDK编译器上面设置,我们在MDK5编译器里面,点击按钮,然后在Target选项卡里面,设置Floating Point HardwareUse FPU,如图51.1.1.2所示:

51.1.1.2 编译器开启硬件FPU选型

经过这个设置,编译器会自动加入标识符__FPU_USED1。这样遇到浮点运算就会使用硬件FPU相关指令,执行浮点运算,从而大大减少计算时间。

最后,总结下STM32F4硬件FPU使用的要点:

1,  设置CPACR寄存器bit20~231,使能硬件FPU

2,  MDK编译器Code Generation里面设置:Use FPU

经过这两步设置,我们的编写的浮点运算代码,即可使用STM32F4的硬件FPU了,可以大大加快浮点运算速度。

51.1.2 Julia分形简介 

Julia分形即Julia集,它最早由法国数学家Gaston Julia发现,因此命名为Julia(朱利亚)集。Julia集合的生成算法非常简单:对于复平面的每个点,我们计算一个定义序列的发散速度。该序列的 Julia 集计算公式为:

zn+1 = zn2 + c

针对复平面的每个 x + i.y 点,我们用 c = cx + i.cy 计算该序列:

xn+1 + i.yn+1 = xn2 - yn2 + 2.i.xn.yn + cx + i.cy

xn+1 = xn2 - yn2 + cx yn+1 = 2.xn.yn + cy

一旦计算出的复值超出给定圆的范围(数值大小大于圆半径),序列便会发散,达到此限值时完成的迭代次数与该点相关。随后将该值转换为颜色,以图形方式显示复平面上各个点的分散速度。

经过给定的迭代次数后,若产生的复值保持在圆范围内,则计算过程停止,并且序列也不发散,本例程生成Julia分形图片的代码如下:

#define          ITERATION                 128                //迭代次数

#define         REAL_CONSTANT      0.285f            //实部常量

#define         IMG_CONSTANT         0.01f              //虚部常量

 

//产生Julia分形图形

//size_x,size_y:屏幕x,y方向的尺寸

//offset_x,offset_y:屏幕x,y方向的偏移

//zoom:缩放因子

void GenerateJulia_fpu(u16 size_x,u16 size_y,u16 offset_x,u16 offset_y,u16 zoom)

{

       u8 i; u16 x,y; 

       float tmp1,tmp2;

       float num_real,num_img;

       float radius;

       for(y=0;y<size_y;y++)

       {

         for(x=0;x<size_x;x++)

            {

                num_real=y-offset_y;

              num_real=num_real/zoom;

             num_img=x-offset_x;

              num_img=num_img/zoom;

             i=0;

              radius=0;

             while((i<ITERATION-1)&&(radius<4))

             {

                    tmp1=num_real*num_real;

                 tmp2=num_img*num_img;

                  num_img=2*num_real*num_img+IMG_CONSTANT;

                  num_real=tmp1-tmp2+REAL_CONSTANT;

                 radius=tmp1+tmp2;

                  i++;

             }

                     LCD->LCD_RAM=color_map;//绘制到屏幕

         }

       }

}

这种算法非常有效地展示了 FPU 的优势:无需修改代码,只需在编译阶段激活或禁止 FPU(在MDK Code Generation里面设置:Use FPU/Not Used),即可测试使用硬件FPU和不使用硬件FPU的差距。

51.2 硬件设计

本章实验功能简介:开机后,根据迭代次数生成颜色表(RGB565),然后计算Julia分形,并显示到LCD上面。同时,程序开启了定时器3,用于统计一帧所要的时间(ms),在一帧Julia分形图片显示完成后,程序会显示运行时间、当前是否使用FPU和缩放因子(zoom)等信息,方便观察对比。KEY0/KEY2用于调节缩放因子,KEY_UP用于设置自动缩放,还是手动缩放。DS0用于提示程序运行状况。

本实验用到的资源如下:

1,指示灯DS0

2,三个按键(KEY_UP/KEY0/KEY2

3,串口

4TFTLCD模块   

这些前面都已介绍过。

51.3 软件设计

本章代码,分成两个工程:

1,实验46_1 FPU测试(Julia分形)实验_开启硬件FPU

2,实验46_2 FPU测试(Julia分形)实验_关闭硬件FPU

这两个工程的代码一模一样,只是前者使用硬件FPU计算Julia分形集(MDK参考图51.1.1.2设置Use FPU),后者使用IEEE-754标准计算Julia分形集(MDK设置参考图51.1.1.2设置不使用FPU)。由于两个工程代码一模一样,我们这里仅介绍其中一个:实验46_1 FPU测试(Julia分形)实验_开启硬件FPU

本章代码,我们在TFTLCD显示实验的基础上修改,打开TFTLCD显示实验的工程,由于要统计帧时间和按键设置,所以在HARDWARE组下加入timer.ckey.c两个文件。

本章不需要添加其他.c文件,所有代码均在main.c里面实现,整个代码如下:

//FPU模式提示

#if __FPU_USED==1

#define SCORE_FPU_MODE                  "FPU On"

#else

#define SCORE_FPU_MODE                  "FPU Off"

#endif

#define          ITERATION                 128                //迭代次数

#define         REAL_CONSTANT      0.285f            //实部常量

#define         IMG_CONSTANT         0.01f              //虚部常量

//颜色表

u16 color_map[ITERATION];

//缩放因子列表

const u16 zoom_ratio[] =

{

       120, 110, 100, 150, 200, 275, 350, 450,

       600, 800, 1000, 1200, 1500, 2000, 1500,

       1200, 1000, 800, 600, 450, 350, 275, 200,

       150, 100, 110,

};

//初始化颜色表

//clut:颜色表指针

void InitCLUT(u16 * clut)

{

      u32 i=0x00;

       u16  red=0,green=0,blue=0; 

       for(i=0;i<ITERATION;i++)//产生颜色表

       {

              //产生RGB颜色值

              red=(i*8*256/ITERATION)%256;

              green=(i*6*256/ITERATION)%256;

              blue=(i*4*256 /ITERATION)%256;

             //RGB888,转换为RGB565

              red=red>>3;

              red=red<<11;

              green=green>>2;

              green=green<<5;

              blue=blue>>3;

              clut=red+green+blue;

       }

}

//产生Julia分形图形

//size_x,size_y:屏幕x,y方向的尺寸

//offset_x,offset_y:屏幕x,y方向的偏移

//zoom:缩放因子

void GenerateJulia_fpu(u16 size_x,u16 size_y,u16 offset_x,u16 offset_y,u16 zoom)

{

       ……//代码省略,详见51.1.2

}

u8 timeout;

int main(void)

{  

       u8 key; u8 i=0; u8 autorun=0; u8 buf[50];

       float time;     

       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2

       delay_init(168);  //初始化延时函数

       uart_init(115200);         //初始化串口波特率为115200

       LED_Init();                         //初始化LED

       KEY_Init();                         //初始化按键

      LCD_Init();                         //初始化LCD

       TIM3_Int_Init(65535,8400-1);//10Khz计数频率,最大计时6.5秒超出

       POINT_COLOR=RED;

       LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");      

       LCD_ShowString(30,70,200,16,16,"FPU TEST");    

       LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");

       LCD_ShowString(30,110,200,16,16,"2014/7/2");      

       LCD_ShowString(30,130,200,16,16,"KEY0:+    KEY2:-");          //显示提示信息

       LCD_ShowString(30,150,200,16,16,"KEY_UP:AUTO/MANUL");   //显示提示信息    

       delay_ms(1200);

       POINT_COLOR=BLUE;       //设置字体为蓝色

       InitCLUT(color_map);          //初始化颜色表

       while(1)

       {

              key=KEY_Scan(0);

              switch(key)

              {

                     case KEY0_PRES:

                            i++;

                            if(i>sizeof(zoom_ratio)/2-1)i=0;//限制范围

                            break;

                     case KEY2_PRES:

                            if(i)i--;

                            else i=sizeof(zoom_ratio)/2-1;

                            break;

                     case WKUP_PRES: autorun=!autorun; break;//自动/手动

              }

              if(autorun==1)//自动时,自动设置缩放因子

              {

                     i++;

                     if(i>sizeof(zoom_ratio)/2-1)i=0;//限制范围

              }

              LCD_Set_Window(0,0,lcddev.width,lcddev.height);//设置窗口

              LCD_WriteRAM_Prepare();

              TIM3->CNT=0;//重设TIM3定时器的计数器值

              timeout=0;

              GenerateJulia_fpu(lcddev.width,lcddev.height,lcddev.width/2,lcddev.height/2,

zoom_ratio);

              time=TIM3->CNT+(u32)timeout*65536;

              sprintf((char*)buf,"%s: zoom:%d  runtime:%0.1fms\r\n",SCORE_FPU_MODE,

zoom_ratio,time/10);

              LCD_ShowString(5,lcddev.height-5-12,lcddev.width-5,12,12,buf);//显示运行情况

             printf("%s",buf);//输出到串口

              LED0=!LED0;

       }

}

    这里面,总共3个函数:InitCLUTGenerateJulia_fpumain函数。

InitCLUT函数,该函数用于初始化颜色表,该函数根据迭代次数(ITERATION)计算出颜色表,这些颜色值将显示在TFTLCD上。

GenerateJulia_fpu函数,该函数根据给定的条件计算Julia分形集,当迭代次数大于等于ITERATION或者半径大于等于4时,结束迭代,并在TFTLCD上面显示迭代次数对应的颜色值,从而得到漂亮的Julia分形图。我们可以通过修改REAL_CONSTANTIMG_CONSTANT这两个常量的值来得到不同的Julia分形图。

    main函数,完成我们在51.2节所介绍的实验功能,代码比较简单。这里我们用到一个缩放因子表:zoom_ratio,里面存储了一些不同的缩放因子,方便演示效果。

    最后,为了提高速度,同上一章一样,我们在MDK里面选择使用-O2优化,优化代码速度,本例程代码就介绍到这里。

再次提醒大家:本例程两个代码(实验46_1和实验46_2)程序是完全一模一样的,他们的区别就是MDKàOptions for Target Target1’àTarget选项卡àFloating Point Hardware的设置不一样,当设置Use FPU时,使用硬件FPU;当设置Not Used时,不使用硬件FPU。分别下载这两个代码,通过屏幕显示的runtime时间,即可看出速度上的区别。

51.4 下载验证

代码编译成功之后,下载本例程任意一个代码(这里以46_1为例)到ALIENTEK探索者STM32F4开发板上,可以看到LCD显示Julia分形图,并显示相关参数,如图51.4.1所示:

51.4.1 Julia分形显示效果

实验46_1是开启了硬件FPU的,所以显示Julia分形图片速度比较快。如果下载实验46_2,同样的缩放因子,会比实验46_19倍左右,这与ST官方给出的17倍有点差距,这是因为我们没有选择:Use MicroLIB(还是在Target选项卡设置),如果都勾选这个,则会发现:使用硬件FPU的例程(实验46_1)时间基本没变化,而不使用硬件FPU的例程(实验46_2)则速度变慢了很多,这样,两者相差差不多就是17倍了。

因此可以看出,使用硬件FPU和不使用硬件FPU对比,同样的条件下,快了近10倍,充分体现了STM32F4硬件FPU的优势。

 

实验详细手册和源码下载地址:http://www.openedv.com/posts/list/41586.htm 

正点原子探索者STM32F407开发板购买地址http://item.taobao.com/item.htm?id=41855882779

  

第五十一章 FPU测试(Julia分形)实验-STM32F4开发指南-正点原子探索者STM32开发板.pdf

977.06 KB, 下载次数: 456

实验46 FPU测试(Julia分形)实验.zip

1.06 MB, 下载次数: 1425

我是开源电子网?网站管理员,对网站有任何问题,请与我联系!QQ:389063473Email:389063473@qq.com
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

4

帖子

0

精华

新手入门

积分
32
金钱
32
注册时间
2015-3-4
在线时间
0 小时
发表于 2015-10-21 11:57:37 | 显示全部楼层
回复【6楼】电子玩霸:
---------------------------------
use single precision 就是启用 FPU的意思,我在ST的一个介绍性质的ppt里看到的
回复 支持 1 反对 0

使用道具 举报

13

主题

57

帖子

0

精华

初级会员

Rank: 2

积分
193
金钱
193
注册时间
2014-9-11
在线时间
15 小时
发表于 2015-4-30 16:49:52 | 显示全部楼层
mark一下 !!!!!!!!!!!!!!!!!
回复 支持 反对

使用道具 举报

1

主题

7

帖子

0

精华

新手上路

积分
36
金钱
36
注册时间
2015-3-17
在线时间
1 小时
发表于 2015-5-8 15:04:45 | 显示全部楼层
请问楼主,开启了FPU之后,是否还要添加库 arm_cortexM4lf_math.lib和包含arm_math.h头文件,我看网上别的地方说要,而你这里没有添加
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-5-8 22:33:03 | 显示全部楼层
回复【3楼】509member:
---------------------------------
说明不是必须的。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

1

主题

7

帖子

0

精华

新手上路

积分
36
金钱
36
注册时间
2015-3-17
在线时间
1 小时
发表于 2015-5-10 21:09:29 | 显示全部楼层
回复【4楼】正点原子:
---------------------------------
我明白了,开启了硬件FPU后,可以在硬件上提高加减乘除运算,而如果要用到复杂的数学运算,才需要添加那些库。另外那些库也只是软件上优化了数学运算的算法。例如正弦函数用的是查表法。这是我的理解
回复 支持 反对

使用道具 举报

13

主题

38

帖子

0

精华

初级会员

Rank: 2

积分
112
金钱
112
注册时间
2013-7-9
在线时间
6 小时
发表于 2015-10-20 09:13:24 | 显示全部楼层
回复【4楼】正点原子:
---------------------------------
原子哥,我的MDK里的Trget没有USE FPU这一项,只有not used 和use single precision,这是什么情况
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 12:31

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表