Cortex-M4FのFPUを使う

ARM Cortex-M4は、M3にDSP(SIMD,MAC)命令を追加したものだが、Cortex-M4Fと呼ばれるものは、さらに単精度のFPU(浮動小数点ユニット)を持っている。どれくらい効果があるものか、三角関数の計算で速さを比較してみた。

方法

Cortex-M4Fをコアに持つLPC4370を用い、FPUを使った場合と使わない場合で、三角関数の計算1万回にかかる時間を比較する。

  • マイコンボード: LPC-Link2 (LPC4370搭載 / 動作クロック204MHz)
  • 開発環境: LPCXpresso v8.1.4_606
  • DSPライブラリ: CMSIS_DSPLIB_CM4 v3.20


三角関数は下記の3種類を使用する。

関数 ヘッダファイル 説明
double sin(double) math.h ANSI標準ライブラリの倍精度実数のsin関数
float sinf(float) math.h ANSI規格外の単精度実数のsin関数
float arm_sin_f32(float) arm_math.h CMSIS DSPライブラリの単精度実数のsin関数


下記のようなコード(抜粋)をもちい、実行時間をオシロスコープで測定する。

while(1) {
    // 三角関数を1万回計算する
    for( float x=0.0f; x<10.0f; x+=0.001f){
        //volatile float y = sin(x);        // ANSI標準 倍精度版
        //volatile float y = sinf(x);       // ANSI規格外 単精度版
        volatile float y = arm_sin_f32(x);  // CMSIS DSPライブラリ版
    }
    // テストピンをパタパタさせてオシロで計測
    if(toggle){
        Chip_GPIO_SetPinOutHigh(LPC_GPIO_PORT, TEST_PORT, TEST_PIN);
    }else{
        Chip_GPIO_SetPinOutLow(LPC_GPIO_PORT, TEST_PORT, TEST_PIN);
    }
    toggle = !toggle;
}

FPUを使用する設定 (LPCXpressoの場合)

プロジェクト作成時のウィザードの「Floating point unit」で「Enabled_SoftABI」を選択する。「Disabled」を選択するとFPUは無効になる。


もしくは、プロジェクト作成後にプロジェクトのPropertiesで次のように設定する。

  • C/C++ Build > Settings > MCU C Compiler > Architecture で
    • Floating point を「FPv4-SP(Soft ABI)」に設定する。
  • C/C++ Build > Settings > MCU Linker > Architecture で
    • Floating point を「FPv4-SP(Soft ABI)」に設定する。

※ Soft ABIでなくHard ABIを選ぶと、関数の引数も浮動小数レジスタで渡されるのでより高速になるが、ライブラリも含めてリンクされる全てのコードをHard ABIでビルドする必要がある。

CMSIS DSPライブラリを使用する設定 (LPCXpressoの場合)

プロジェクト作成時のウィザードの「CMSIS DSP Library to link project to」で「CMSIS_DSPLIB_CM4」を選択する。

もしくは、プロジェクト作成後にプロジェクトのPropertiesで次のように設定する。

  • C/C++ Build > Settings > MCU C Compiler > Includes で
    • Include paths に"${workspace_loc:/CMSIS_DSPLIB_CM4/inc}"を追加
  • C/C++ Build > Settings > MCU C Linker > Libraries で
    • Libraries に CMSIS_DSPLIB_CM4 を追加
    • Library search path に"${workspace_loc:/CMSIS_DSPLIB_CM4/lib}"を追加

結果

表:三角関数の計算1万回にかかった時間

三角関数 FPUを使ったとき FPUを使わないとき
double sin(double) 110msec 115msec
float sinf(float) 9.5msec 73msec
float arm_sin_f32(float) 4.7msec N/A
  • Cortex-M4FのFPUは単精度なので、double型の計算については差が出ない。
  • float型の計算ではFPUを使うと劇的に高速になる。
  • DSPライブラリの三角関数を使うと、さらに高速になる。(精度は未検証)

まとめ

PCアプリでは実数といえばdoubleを使うことが常で、floatはあまり使われない。しかし、floatといえども仮数部が23ビットあり(doubleは仮数部52ビット)、マイコンで扱うセンサの精度がせいぜい16ビットくらいであることを考えれば、たいていの場合には十分な精度と思われる。特にCortex-M4FではFPUを使うことでfloatの計算が劇的に高速になるので、効果的に使っていきたい。