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件
2020-11-14
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
今日の20件
- counter: 10907
- today: 2
- yesterday: 0
- online: 1