fpu测试_正点原子STM32F4/F7水星开发板资料连载第五十章 FPU 测试实验
1)實驗平臺:正點原子水星 STM32F4/F7 開發板
2)摘自《STM32F7 開發指南(HAL 庫版)》關注官方微信號公眾號,獲取更多資料:正點原子
3)全套實驗源碼+手冊+視頻下載地址:http://www.openedv.com/thread-13912-1-1.html
第五十章 FPU 測試(Julia 分形)實驗
本章,我們將向大家介紹如何開啟 STM32F767 的硬件 FPU,并對比使用硬件 FPU 和不使
用硬件 FPU 的速度差別,以體現硬件 FPU 的優勢。本章分為如下幾個部:
50.1 FPU&Julia 分形簡介
50.2 硬件設計
50.3 軟件設計
50.4 下載驗證
50.1 FPU&Julia 分形簡介
本節將分別介紹 STM32F767 的 FPU 和 Julia 分形。
50.1.1 FPU 簡介
FPU 即浮點運算單元(Float Point Unit)。浮點運算,對于定點 CPU(沒有 FPU 的 CPU)
來說必須要按照 IEEE-754 標準的算法來完成運算,是相當耗費時間的。而對于有 FPU 的 CPU
來說,浮點運算則只是幾條指令的事情,速度相當快。
STM32F767 屬于 Cortex M7 架構,帶有 32 位雙精度硬件 FPU,支持浮點指令集,相對于
Cortex M0 和 Cortex M3 等,高出數十倍甚至上百倍的運算性能。
STM32F767 硬件上要開啟 FPU 是很簡單的,通過一個叫:協處理器控制寄存器(CPACR)
的寄存器設置即可開啟 STM32F767 的硬件 FPU,該寄存器各位描述如圖 56.1.1.1 所示:
圖 50.1.1.1 協處理器控制寄存器(CPACR)各位描述
這里我們就是要設置 CP11 和 CP10 這 4 個位,復位后,這 4 個位的值都為 0,此時禁止訪
問協處理器(禁止了硬件 FPU),我們將這 4 個位都設置為 1,即可完全訪問協處理器(開啟
硬件 FPU),此時便可以使用 STM32F7 內置的硬件 FPU 了。CPACR 寄存器這 4 個位的設置,
我們在 system_stm32f7xx_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,
以開啟 STM32F7 的硬件 FPU 功能。從程序可以看出,只要我們定義了全局宏定義標識符
__FPU_PRESENT 以及__FPU_USED 為 1,那么就可以開啟硬件 FPU。其中宏定義標識符
__FPU_PRESENT 用來確定處理器是否帶 FPU 功能,標識符__FPU_USED 用來確定是否開啟
FPU 功能。
實際上,因為 F7 是帶 FPU 功能的,所以在我們的 stm32f767xx.h 頭文件里面,我們默認是
定義了__FPU_PRESENT 為 1。大家可以打開文件搜索即可找到下面一行代碼:
#define __FPU_PRESENT 1但是,僅僅只是說明處理器有 FPU 功能是不夠的,我們還需要開啟 FPU 功能。開啟 FPU
有兩種方法,第一種是直接在頭文件 STM32f767xx.h 中定義宏定義標識符__FPU_USED 的值為
1。也可以直接在 MDK 編譯器上面設置,我們在 MDK5 編譯器里面,點擊
按鈕,然后在 Target
選項卡里面,設置 Floating Point Hardware 為 Use Double Precision,如圖 50.1.1.2 所示:
圖 50.1.1.2 編譯器開啟硬件 FPU 選型
經過這個設置,編譯器會自動加入標識符__FPU_USED 為 1。這樣遇到浮點運算就會使用
硬件 FPU 相關指令,執行浮點運算,從而大大減少計算時間。
最后,總結下 STM32F7 硬件 FPU 使用的要點:
1, 設置 CPACR 寄存器 bit20~23 為 1,使能硬件 FPU(參考 SystemInit 函數開頭部分)。
2, MDK編譯器Target選項卡中 Floating Point Hardware選項設置為:Use Double Precision。
經過這兩步設置,我們的編寫的浮點運算代碼,即可使用 STM32F7 的硬件 FPU 了,可以
大大加快浮點運算速度。
50.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++;} if(lcdltdc.pwidth!=0)lcdbuf[lcddev.width-x-1]=color_map[i]; //保存顏色值到 lcdbuf else LCD->LCD_RAM=color_map[i];//繪制到屏幕} if(lcdltdc.pwidth!=0)LTDC_Color_Fill(0,y,lcddev.width-1,y,lcdbuf); //DM2D 填充 } }這種算法非常有效地展示了 FPU 的優勢:無需修改代碼,只需在編譯階段激活或禁止
FPU(在 MDK 的 Float Point Hardware 選項里面設置:Use Double Precision/Not Used),即可
測試使用硬件 FPU 和不使用硬件 FPU 的差距。
注意,是該函數將顏色數據填充到 LCD 的時候,根據 MCU 屏還是 RGB 屏,做了不同的
處理:MCU 屏可以直接寫 LCD_RAM,將顏色顯示到 LCD 上面;而 RGB 屏,則需要先緩存
到 lcdbuf,然后通過 DMA2D 一次性填充,以提高速度。
50.2 硬件設計
本章實驗功能簡介:開機后,根據迭代次數生成顏色表(RGB565),然后計算 Julia 分形,
并顯示到 LCD 上面。同時,程序開啟了定時器 3,用于統計一幀所要的時間(ms),在一幀
Julia 分形圖片顯示完成后,程序會顯示運行時間、當前是否使用 FPU 和縮放因子(zoom)等
信息,方便觀察對比。KEY0/KEY2 用于調節縮放因子,KEY_UP 用于設置自動縮放,還是手
動縮放。DS0 用于提示程序運行狀況。
本實驗用到的資源如下:
1,指示燈 DS0
2,三個按鍵(KEY_UP/KEY0/KEY2)
3,串口
4,LCD 模塊
這些前面都已介紹過。
50.3 軟件設計
本章代碼,分成兩個工程:
1,實驗 45_1 FPU 測試(Julia 分形)實驗_開啟硬件 FPU
2,實驗 45_2 FPU 測試(Julia 分形)實驗_關閉硬件 FPU
這兩個工程的代碼一模一樣,只是前者使用硬件 FPU 計算 Julia 分形集(MDK 設置 Use
Double Precision),后者使用 IEEE-754 標準計算 Julia 分形集(MDK 設置 Not Used)。由于兩
個工程代碼一模一樣,我們這里僅介紹其中一個:實驗 45_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) { ……//代碼省略,詳見 53.1.2 節 } u8 timeout; int main(void) {u8 key, i=0, autorun=0; float time; u8 buf[50];Cache_Enable(); //打開 L1-Cache HAL_Init();//初始化 HAL 庫Stm32_Clock_Init(432,25,2,9); //設置時鐘,216Mhzdelay_init(216); //延時初始化 uart_init(115200);//串口初始化LED_Init(); //初始化 LEDKEY_Init(); //初始化按鍵SDRAM_Init(); //初始化 SDRAMLCD_Init(); //LCD 初始化TIM3_Init(65535,10800-1); //10Khz 計數頻率,最大計時 6.5 秒超出 ……//此處省略部分代碼 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_Toggle; } } 這里面,總共 3 個函數:InitCLUT、GenerateJulia_fpu 和 main 函數。InitCLUT 函數,該函數用于初始化顏色表,該函數根據迭代次數(ITERATION)計算出顏
色表,這些顏色值將顯示在 TFTLCD 上。
GenerateJulia_fpu 函數,該函數根據給定的條件計算 Julia 分形集,當迭代次數大于等于
ITERATION 或者半徑大于等于 4 時,結束迭代,并在 TFTLCD 上面顯示迭代次數對應的顏色
值,從而得到漂亮的 Julia 分形圖。我們可以通過修改 REAL_CONSTANT 和 IMG_CONSTANT
這兩個常量的值來得到不同的 Julia 分形圖。
main 函數,完成我們在 56.2 節所介紹的實驗功能,代碼比較簡單。這里我們用到一個縮放
因子表:zoom_ratio,里面存儲了一些不同的縮放因子,方便演示效果。
最后,為了提高速度,同上一章一樣,我們在 MDK 里面選擇使用-O2 優化,優化代碼速
度,本例程代碼就介紹到這里。
再次提醒大家:本例程兩個代碼(實驗 45_1 和 45_2)程序是完全一模一樣的,他們的區
別就是 MDK→Options for Target ‘Target1’→Target 選項卡→Floating Point Hardware 的設置不
一樣,當設置 Use Double Precision 時,使用硬件 FPU;當設置 Not Used 時,不使用硬件 FPU。
分別下載這兩個代碼,通過屏幕顯示的 runtime 時間,即可看出速度上的區別。
50.4 下載驗證
代碼編譯成功之后,下載本例程任意一個代碼(這里以 45_1 為例)到 ALIENTEK 水星
STM32 開發板上,可以看到 LCD 顯示 Julia 分形圖,并顯示相關參數,如圖 50.4.1 所示:
圖 50.4.1 Julia 分形顯示效果
實驗 45_1 是開啟了硬件 FPU 的,所以顯示 Julia 分形圖片速度比較快。如果下載實驗 45_2,
同樣的縮放因子,會比實驗 51_1 慢 11 倍左右。
因此可以看出,使用硬件 FPU 和不使用硬件 FPU 對比,同樣的條件下,硬件 FPU 快了近
11 倍,充分體現了 STM32F767 硬件 FPU 的優勢。
總結
以上是生活随笔為你收集整理的fpu测试_正点原子STM32F4/F7水星开发板资料连载第五十章 FPU 测试实验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 专项---APP安全---Android
- 下一篇: Virtualbox 设置共享文件夹