はじめに
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"に設定する.
リンカ設定
C Standard Libraryのmath.hを使うため,"MCU GCC Linker">"Libraries"にて,"m"を追加する.
(本来は"-lm"だが,"-l"は自動的に付加される)
コーディング
math.hのインクルード
これはいつもと同じ.
/* 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()となる.
// 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を使った演算が行われていることが確認できる.
以上.