fpu测试_正点原子STM32F407探索者开发板资料连载第五十一章 FPU 测试实验
1)實驗平臺:alientek 阿波羅 STM32F767 開發板
2)摘自《STM32F7 開發指南(HAL 庫版)》關注官方微信號公眾號,獲取更多資料:正點原子
http://weixin.qq.com/r/hEhUTLbEdesKrfIv9x2W (二維碼自動識別)
第五十一章 FPU 測試(Julia 分形)實驗
本章,我們將向大家介紹如何開啟 STM32F4 的硬件 FPU,并對比使用硬件 FPU 和不使用
硬件 FPU 的速度差別,以體現硬件 FPU 的優勢。本章分為如下幾個部:
51.1 FPU&Julia 分形簡介
51.2 硬件設計
51.3 軟件設計
51.4 下載驗證
51.1 FPU&Julia 分形簡介
本節將分別介紹 STM32F4 的 FPU 和 Julia 分形。
51.1.1 FPU 簡介
FPU 即浮點運算單元(Float Point Unit)。浮點運算,對于定點 CPU(沒有 FPU 的 CPU)
來說必須要按照 IEEE-754 標準的算法來完成運算,是相當耗費時間的。而對于有 FPU 的 CPU
來說,浮點運算則只是幾條指令的事情,速度相當快。
STM32F4 屬于 Cortex M4F 架構,帶有 32 位單精度硬件 FPU,支持浮點指令集,相對于
Cortex M0 和 Cortex M3 等,高出數十倍甚至上百倍的運算性能。
STM32F4 硬件上要開啟 FPU 是很簡單的,通過一個叫:協處理器控制寄存器(CPACR)
的寄存器設置即可開啟 STM32F4 的硬件 FPU,該寄存器各位描述如圖 51.1.1.1 所示:
圖 51.1.1.1 協處理器控制寄存器(CPACR)各位描述
這里我們就是要設置 CP11 和 CP10 這 4 個位,復位后,這 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_USED 為 1,那么就可以開啟硬件 FPU。其中宏定義標識符
__FPU_PRESENT 用來確定處理器是否帶 FPU 功能,標識符__FPU_USED 用來確定是否開啟
FPU 功能。
實際上,因為 F4 是帶 FPU 功能的,所以在我們的 stm32f4xx.h 頭文件里面,我們默認是定
義了__FPU_PRESENT 為 1。大家可以打開文件搜索即可找到下面一行代碼:
#define __FPU_PRESENT 1
但是,僅僅只是說明處理器有 FPU 是不夠的,我們還需要開啟 FPU 功能。開啟 FPU 有兩
種方法,第一種是直接在頭文件 STM32f4xx.h 中定義宏定義標識符__FPU_USED 的值為 1。也
可以直接在 MDK 編譯器上面設置,我們在 MDK5 編譯器里面,點擊
按鈕,然后在 Target
選項卡里面,設置 Floating Point Hardware 為 Use Single Precision,如圖 51.1.1.2 所示:
圖 51.1.1.2 編譯器開啟硬件 FPU 選型
經過這個設置,編譯器會自動加入標識符__FPU_USED 為 1。這樣遇到浮點運算就會使用
硬件 FPU 相關指令,執行浮點運算,從而大大減少計算時間。
最后,總結下 STM32F4 硬件 FPU 使用的要點:
1, 設置 CPACR 寄存器 bit20~23 為 1,使能硬件 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[i];//繪制到屏幕} } }這種算法非常有效地展示了 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,串口
4,TFTLCD 模塊
這些前面都已介紹過。
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.c 和 key.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[i]=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; HAL_Init(); //初始化 HAL 庫Stm32_Clock_Init(336,8,2,7); //設置時鐘,168Mhz delay_init(168); //初始化延時函數 uart_init(115200); //初始化 USART LED_Init(); //初始化 LED KEY_Init(); //初始化按鍵 LCD_Init(); //初始化 LCD FSMC 接口TIM3_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,"2017/5/6"); 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(); __HAL_TIM_SET_COUNTER(&TIM3_Handler,0); //重設 TIM3 定時器的計數器值 timeout=0; GenerateJulia_fpu(lcddev.width,lcddev.height,lcddev.width/2,lcddev.height/2, zoom_ratio[i]); time= __HAL_TIM_GET_COUNTER(&TIM3_Handler) +(u32)timeout*65536; sprintf((char*)buf,"%s: zoom:%d runtime:%0.1fmsrn",SCORE_FPU_MODE, zoom_ratio[i],time/10); LCD_ShowString(5,lcddev.height-5-12,lcddev.width-5,12,12,buf);//顯示運行情況 printf("%s",buf);//輸出到串口 LED0=!LED0; } }這里面,總共 3 個函數:InitCLUT、GenerateJulia_fpu 和 main 函數。
InitCLUT 函數,該函數用于初始化顏色表,該函數根據迭代次數(ITERATION)計算出顏
色表,這些顏色值將顯示在 TFTLCD 上。
GenerateJulia_fpu 函數,該函數根據給定的條件計算 Julia 分形集,當迭代次數大于等于
ITERATION 或者半徑大于等于 4 時,結束迭代,并在 TFTLCD 上面顯示迭代次數對應的顏色
值,從而得到漂亮的 Julia 分形圖。我們可以通過修改 REAL_CONSTANT 和 IMG_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_1 慢 9 倍左右,這與 ST 官方給出的 17 倍有點差距,這是因為
我們沒有選擇:Use MicroLIB(還是在 Target 選項卡設置),如果都勾選這個,則會發現:使用
硬件 FPU 的例程(實驗 46_1)時間基本沒變化,而不使用硬件 FPU 的例程(實驗 46_2)則速
度變慢了很多,這樣,兩者相差差不多就是 17 倍了。
因此可以看出,使用硬件 FPU 和不使用硬件 FPU 對比,同樣的條件下,快了近 10 倍,充
分體現了 STM32F4 硬件 FPU 的優勢。
總結
以上是生活随笔為你收集整理的fpu测试_正点原子STM32F407探索者开发板资料连载第五十一章 FPU 测试实验的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 为什么聊天软件一般采用UDP协议
- 下一篇: 新概念二册 Lesson 45 A c
