STM32F4シリーズのFPUを使う。

  • STM32F4・Cortex M4 の最大の特徴は、単精度とは言え、浮動小数点演算プロセッサを持っていることだろう。
  • 実は、2012.6.26現在、本Wikiの本題であるデジタルオーディオプレーヤーでは、浮動小数点演算を使っていない。
  • しかし、STM32F4の情報を知りたくて、本Wikiに着た人の中には FPU を使いたい、FPUの使い方を知りたいと思う人が多いと思われる。
  • そこで、本題からは外れるが、私が理解した範囲で、FPUの使い方の説明する。

FPUを有効にするコンパイラとライブラリーの構築

  • STM32プログラム開発環境に、FPUを有効にするコンパイラとライブラリーの構築方法を書いておいた。
    • なお、上記のライブラリーの構築時において、「-mfloat-abi=softfp -mfpu=fpv4-sp-d16」と言うオプションを使っている。このオプションは、浮動小数点演算プロセッサを使うものの関数呼び出しの時に、汎用レジスタを用いて float 変数の値を渡すというオプションである。
    • アプリケーションプログラムを作る時のオプションは、ライブラリー構築時と一致させる必要がある。
    • その他のオプションとしては、「-mfloat-abi=soft」:ソフトウエア・エミュレーションで浮動小数点演算を行う。「-mfloat-abi=hard」:浮動小数点演算プロセッサを使い、かつ関数呼び出しの時には、浮動小数点レジスタを使って float 変数の値を渡す
    • 常に、浮動小数点演算プロセッサを使うのなら、「-mfloat-abi=hard」を使えば良いようにも思える。しかし、どうやら、「-mfloat-abi=hard」オプションを使うと「printf」などの関数が正常に動作しないようだ。そこで、ここでの説明では、オプションは「-mfloat-abi=softfp -mfpu=fpv4-sp-d16」に統一している。
      • 「-mfloat-abi=hard」オプションを使って、なおかつ「printf」などの関数を正常に動作させることができるかどうかについては、調査続行中。

FPUを有効にするプログラムのサンプル

  • GitHubに、FPUを有効にするプログラムのサンプルを入れておいた。
  • 本プログラムは、とても収束の遅いアルゴリズムで円周率を計算するものであり、計算結果を、シリアルポート USART1から、38400ボーで出力する。
    • USARTは、makefile の27行目で、USART1とUSART2から選ぶ事ができる。
    • ボーレートは、inc/uart_support.h の19行目で変える事ができる。なお、ボーレートは、外部クロックの周波数が8MHzだと言う前提で設定されようにしてある。
    • USART1からの出力は、非同期の8N1形式で設定した端末プログラムで受信するように。
  • 本サンプルプログラムは、STM32F405でもSTM32F407でも共通して動作する。
  • サンプルプログラムの入手及びコンパイル方法を下記に示す。
$ mkdir ~/STM32F4  << これは何処でも良いけど、この後の作業エリアになる
$ cd ~/STM32F4
$ unzip stm32f4discovery_fw.zip
$ git clone https://github.com/madnoda/stm32f4-fpu stm32f4-fpu
$ cd stm32f4-fpu
$ make

FPUを有効にするプログラムの構築方法

  • サンプルプログラムに付加した makefile が一番の参考になるだろう。
  • コンパイル時には、「-mfloat-abi=softfp -mfpu=fpv4-sp-d16 -mcpu=cortex-m4 -march=armv7e-m -mtune=cortex-m4」を忘れないように。
  • リンク時には「-mcpu=cortex-m4 -march=armv7e-m -mthumb」を忘れないように。
    • 三角関数などの算術関数を使うときには、リンク時に更に「-lm」を入れるように。
  • src/system_stm32f4xx.c の初めの方(213行目くらい)に下記の行があることを確認すること。もし無いような場合は、追加すること。
 #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
   SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
 #else
 #endif

FPUの効果と プログラミングのコツ

  • サンプルプログラムの main.c 中の円周率を求めるルーチンは、次の通りである。
volatile float fnk1=0;
fnk1 = 0.0;
for (i = 1;i < 50000000;i += 4) {
  fnk1 += 4.0f / (float)(i) - 4.0f / (float)(i + 2);
}
printf("pi: %f\n",fnk1);
  • 上記の計算ループの実行時間は次の通りである。
    • 外部クロック使用 CPUクロック 168MHz FPU付き:4秒
    • 外部クロック使用 CPUクロック 168MHz FPU無し:35秒
    • 内部クロック使用 CPUクロック 16MHz FPU付き:26秒
    • 内部クロック使用 CPUクロック 16MHz FPU無し:356秒
  • FPUを有効にしていると1250万回のループを4秒で実行しており、その有効性が判る。
  • ただし、FPUを有効にするためには、少々コツが要る
    • 定数および整数から浮動小数点への変換は float(単精度浮動小数点変数)であることを明示する。
      • 例えば、ループの中にある「4.0f」を、「4.0」と変えると、処理速度は遅くなる。これは、「4.0」は暗黙的に倍精度浮動小数点と判断され、式全体の計算を倍精度演算で行うからだ。もちろん、STM32F4は単精度浮動小数点演算プロセッサしか持っていないので、倍精度演算はソフトウエアエミュレーションで計算するために、処理速度が遅くなるのである。
  • しかし、まるで余談だが、普通に printf が使えるなんて、ワンチップマイコンのプログラムとは思えない・・・

参考にしたリンク



プロジェクト


共通



最新の20件

2016-12-31 2014-11-10 2014-08-17 2013-12-23 2013-09-29 2013-08-09 2013-08-07 2013-08-03 2012-11-28 2012-08-25 2012-07-05 2012-07-03 2012-07-01

今日の1件

  • STM32F4の情報/FPUの使い方(1)

  • counter: 6853
  • today: 1
  • yesterday: 2
  • online: 1