読者です 読者をやめる 読者になる 読者になる

ガレスタさんのDIY日記

電子回路、Web、組み込み、自作エフェクターを語るblog

STM32でCMSIS DSPライブラリを使ってみる

今回は高速に三角関数とかを計算できるARM社提供ライブラリであるCMSIS DSPライブラリを使ってみる話です。

API各種はarm_math.hというファイルで用意されています。

今回の実習環境は以下の通りです

  • IDE:AtollicTrueStudio
  • Board:STM32F767 Nucleo144

導入

今回はCortexM7のNucleo144を使います(746か767

CubeMXで適当にプロジェクトを作ってビルドが通るとこまで作っておきます。

その次にmain.cプログラム上部のインクルードの上に

#define ARM_MATH_CM7

の定義を追加します。

これはCortexM7で使うよというのをコンパイラに教えてあげる定義です。

次にヘッダーをインクルードします。

#include "arm_math.h"
#include "arm_const_structs.h"

オブジェクトの追加

次にライブラリのオブジェクトを追加していきます。
オブジェクト自体はCubeF7のフォルダ内にあります。

場所を調べるには

CubeMX上記メニューからhelp->UpdaterSettingでパスをコピーします

f:id:gsmcustomeffects:20170405164420p:plain

ファイルエクスプローラーでそこに移動します。

するとこんな感じのファイル構成になっていると思います

f:id:gsmcustomeffects:20170405164606p:plain

オブジェクトは以下のPATHにあります。

STM32Cube\Repository\STM32Cube_FW_F7_V1.6.0\Drivers\CMSIS\Lib

f:id:gsmcustomeffects:20170405165503p:plain

三つありますがダブルポイント(倍精度)かシングル(単精度)かを選ぶ。
今回はF767なのでdpがついてるlibarm_cortexM7lfdp_math.aを選びます。

それをコピーしてプロジェクト直下にいれます。

f:id:gsmcustomeffects:20170405164940p:plain

Linkerなどの設定

プロジェクトのプロパティーで「C/C++Build」の設定内の
Linker、LibrariesでDSP処理のLinkerとかを設定していく

Librariesに下記を追加。

「:」を頭につける

:libarm_cortexM7lfdp_math.a

Library search pathに下記を追加

"${workspace_loc:/${ProjName}}"

f:id:gsmcustomeffects:20170405165752p:plain

んでいったんビルドする

f:id:gsmcustomeffects:20170405165819p:plain


FPUの設定

以下のように選択する

f:id:gsmcustomeffects:20170405172401p:plain

詳しい説明はここ読んでください
ARM Information Center

コードを書いていく

今回は試しに平方根でもやってみます。
FastMathのとこに入ってます。

CMSIS DSP研究室さんで詳しく解説されています。

DIGITALFILTER.COM

APIとしては

arm_sqrt_f32 (float32_t in,float32_t * pOut )

を用います

f:id:gsmcustomeffects:20170405170921p:plain
Square Root

こんな感じに書いた
f:id:gsmcustomeffects:20170405171946p:plain

動作

f:id:gsmcustomeffects:20170405172020p:plain

入力した値の平方根が帰ってきているのでちゃんと動いているといえる。

ちなみに返り値でStatを見ているがそれの返り値はENUMで定義されてる。

f:id:gsmcustomeffects:20170405172126p:plain

まとめ

  • DSPライブラリを導入できた
  • FastMath使った割に速度については検討してないので今後やって行きたい

STM32でUARTをやってみる6(float型printfをUART経由で出力)

何だかんだこのシリーズも6個目ですねw

前回まででUARTの基本的な使い方はマスターしたと思います。
今回はCubeMXでの出力は詳しくは解説しないので

まだの方は1から読んでみてください

gsmcustomeffects.hatenablog.com

gsmcustomeffects.hatenablog.com

gsmcustomeffects.hatenablog.com

gsmcustomeffects.hatenablog.com

gsmcustomeffects.hatenablog.com

さっそくやってく

今回の環境は以下に示す通り

  • AC6 SystemWorkbenchForSTM32
  • STM32F303K Nucleo
  • Teraterm

とりあえずCubeでUART2を有効にしてボーレートを各自設定しファイルを出力する。
ココまでは今までと同じです。

Syscall.cを持ってくる

syscall.cがCにおけるスタンダードライブラリを読んでいるのでそれをどっかからもってこないとリンクできないわけです。
とりあえずSTが提供するサンプルには入っているのですがCubeMXが出力するsrcフォルダには入っていません。

なのでAc6で適当な空プロジェクトを作る必要があります。

f:id:gsmcustomeffects:20170404195559p:plain

で今回使うボードを選択

f:id:gsmcustomeffects:20170404195630p:plain

CubeHALを選択

f:id:gsmcustomeffects:20170404195658p:plain

そうするとsyscall.cができるのでそれをCubeMXが出力したSrcにコピーしてくる

f:id:gsmcustomeffects:20170404195814p:plain

f:id:gsmcustomeffects:20170404195841p:plain

んで一度コンパイルします。


Main.cでputcharを再定義。

syscall.c内では

__io_putchar(int ch) __attribute__((weak))

のようにWEAK定義されているのでMain内で再定義してこっちを使うよということをコンパイラに教えてあげる作業をします

こういうふうにします。

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
void __io_putchar(uint8_t ch) {
HAL_UART_Transmit(&huart2, &ch, 1, 1);
}

printfというのは内部で書式を整えてputcharを呼び出しているのでそのputcharの内部をHALの一文字送信APIに置き換えるということです。

コンパイルマクロがGNUとかついてるのはARMの純正コンパイラではfputcと定義されてるのでコンパイラごとに読み替えが効くようにしているためです。
GCCだけならこの部分はいらないと思います。

次にprintfを呼ぶ前にどこか最初以下の行を挿入します

setbuf(stdout, NULL);

これはprintfの仕様みたいで1024byte入れた後に呼ばれるのでコレがないと変なハンドラに飛びます。
とりあえずバッファをフラッシュするといいみたいです。

ここまででとりあえずint型のprintfは動きます。

だいたい15KBぐらいになります。

Linkerフラグの編集

リンカーオプションにfloatを追加して再ビルドする必要があります。

やることとしてはlinkerのフラグ部分に-u _printf_floatというのを追加するだけです。

f:id:gsmcustomeffects:20170404201644p:plain

それであとはApplyして再ビルドします。

f:id:gsmcustomeffects:20170404202009p:plain

結構サイズがでかくなります。

いうてGCCならKEILと違って32KB以上もビルドできるしFloat扱うようなマイコンはフラッシュ自体大きい物がのってるので特に悩まないかと思います。

動作のようす

こんな感じに書いて

f:id:gsmcustomeffects:20170404202315p:plain

Teratermで表示する

f:id:gsmcustomeffects:20170404202339p:plain

ちなみに桁数ちゃんと合わせないとゴミが入りますw

ちなみにSemihostingというARMの機能を使ってSWD経由でEclipse上のコンソールに出力することもできます。
それについてはユークリッドさんが書いているので引用させていただきます。

yuqlid.hatenablog.com

yuqlid.hatenablog.com

場合分けで使いたい方使えばいいと思います。

単に値見たいだけならExpression機能もありますしね

ARMのソフトウエアトリガ割り込みについて

ARMのソフトウエア駆動割り込みの覚え書きです。

ARMの割り込みはNVIC(統合ネスト型ベクタ割り込みコントローラ)で管理されていますがその中でSTIRというレジスタがあります

f:id:gsmcustomeffects:20170404051828p:plain

図で言うと赤の部分ですね

詳細はこちらになります

f:id:gsmcustomeffects:20170404052003p:plain

Write to the STIR to generate an interrupt from software

とあるように割り込みの番号を入れてやるとソフトウエアから割り込みを生成できるようです。

実際の使い方はこのような感じです。

f:id:gsmcustomeffects:20170404052313p:plain

STIRレジスタIRQ番号を書くだけです

STM32の場合IRQ番号はstm32f767xx.hに定義されています

f:id:gsmcustomeffects:20170404052432p:plain

ためしにピン割り込みハンドラにソフトウエアから移動してみます

f:id:gsmcustomeffects:20170404052528p:plain

図ではわからないですがスイッチを押さなくても割り込みハンドラに遷移しています。
もちろん割り込みも有効なのでスイッチを押すとそのタイミングでも割り込みがかかります。
なのでこの割り込みを使う際は使わないであろうペリフェラルを殺しておいて使うほうがいいでしょう