Posted at

SW4STM32でFPUによる単精度浮動小数点演算を行う


はじめに

ARM Cortex-M4FシリーズのMCUは単精度のFPUを搭載していて,浮動小数点演算を行うことができる.

Cortex-M4FシリーズであるSTM32マイコンをSystem Workbench for STM32 (SW4STM32)で扱うときに,FPUを使って演算を行うためのメモ.

なお,環境はmacOS Mojave,SW4STM32 v2.8.ボードはNucleo F411REとした.

また,C Standard Libraryのmath.hを使うこととする.


環境整備

まず,SW4STM32でFPUを使うための設定を行う.


MCU設定

Project Explorerでプロジェクトを選択し,メニューバーの"Project">"Properties"をクリックする.

"C/C++ Build">"Settings"をクリックする.

"MCU Settings"にて,"Floating point hardware"を"fpv4-sp-d16"に,"Floating-point ABI"を"softfp"に設定する.

Screenshot 2019-03-01 at 19.00.38.png


リンカ設定

C Standard Libraryのmath.hを使うため,"MCU GCC Linker">"Libraries"にて,"m"を追加する.

(本来は"-lm"だが,"-l"は自動的に付加される)

Screenshot 2019-03-01 at 19.04.10.png


コーディング


math.hのインクルード

これはいつもと同じ.


main.c

/* Private includes ------------------------------------------*/

/* USER CODE BEGIN Includes */
#include <math.h>
/* USER CODE END Includes */


演算部分

演算するコードを書く際は,扱う全ての値をfloatにすること.

数値リテラルは,末尾にfをつけておく.例えばfを付けずに100.0と記述すると,doubleとして演算されてFPUが使われない.当たり前だが,定数はdefineではなく,const floatを使えば自動的にfloatになるので安心である.

もちろん変数はfloatにする必要があるが,関数もfloatを返すものにする.例えば正弦関数ならsinf()となる.


main.c

// Global ///////////////////////////

// 定数はconst floatが無難.
const float Scale = 0.5;
// #defineを使う場合は以下.
// #define Scale (0.5f)

// 変数ももちろんfloatにする.
float SinTable[500];

// main /////////////////////////////
// 円周率は"M_PI"で定義される.
const float dt = 2.0f * M_PI / 500.0f;
for( uint32_t i = 0; i < 500; i++ ){
// sinはsinfなど単精度のものを使う.
SinTable[i] = 100.0f * sinf( dt * i );
}

/////////////////////////////////////
// 定数にはfをつける.
float result = Scale * SinTable[10] + 100.0f;



FPUが使われていることの確認

SW4STM32に逆アセンブルリストを吐かせることで,FPUが使われているかを確認することができる.

SW4STM32で逆アセンブルリストを出力する - Qiita

生成された逆アセンブラリストを開き,Cのソースに該当する部分のアセンブラ命令を確認する.

例えば,VMUL,VMLA,VMLS,VNMUL,VNMLA,VNMLSなどは浮動小数点乗算および積和を行う命令であるから,以下のようになった場合,FPUを使った演算が行われていることが確認できる.

Screenshot 2019-03-01 at 19.38.49.png

以上.