Spresense SDKにCMSIS-DSPライブラリをリンクしました。これによって、ARMが提供している基本演算や信号処理ライブラリをSpresenseアプリケーションで使えるようになります。
なぜCMSIS-DSPが必要か
CMSIS-DSPは、ARMがCMSIS-5の一部として公開している演算ライブラリです。このライブラリは固定小数点数、浮動小数点数による関数を集めたもので、基本的なものからフィルタ、FFTといった信号処理関数まで含んでいます。わざわざ信号処理関数を集めたのは、汎用DSPがおさえていた組み込み信号処理市場に手を伸ばすためでしょう。
なんにせよ、このライブラリをアプリケーションから使うことで信号処理アプリの開発が楽になります。CMSISはドキュメントがそこそこしっかりしているので、使うときのハードルが低いのも良い点です。
NuttXへの外部ライブラリの追加方法
外部ライブラリの追加は、実際にはNuttXカーネルに対して行います。言い換えると、アプリケーションごとにライブラリを分けてリンクするのではなく、パッケージ全体にライブラリを1つ追加します。
CMSIS-DSPのライブラリは、ARMがコンパイル済みのライブラリをgithubにプッシュしているので、そちらを使います。どこにおいても構いませんが、私はspresenseディレクトリの直下に置きました。以下のスクリプトでCMSIS-5のリポジトリをクローンし、masterからチェックアウトしています。
# Clone CMSIS-5 cd ~/spresense git clone https://github.com/ARM-software/CMSIS_5.git cd CMSIS_5 git checkout master git pull
持ってきたライブラリを使用するには、ビルドルールの中にインクルードファイルやライブラリを追加しなければなりません。追加の仕方についてはHow to properly include an external library source in a NuttX build?として論じられている内容を参考にしました。
具体的にはMake.defsに対してCFLAGS, EXTRA_LIBS, EXTRA_LIBPATHを追加します。Spresense SDKにはMake.defsが複数あるのですが、spresense/sdk/Make.defsに追加しました。なお、ARM_MATH_CM4マクロと__FPU_PRESENTマクロについてはドキュメントを参考にしました。
CFLAGS += -I$(SDKDIR)/../CMSIS_5/CMSIS/DSP/Include CFLAGS += -I$(SDKDIR)/../CMSIS_5/CMSIS/Core/Include CFLAGS += -DARM_MATH_CM4 CFLAGS += -D__FPU_PRESENT=1 CXXFLAGS += -I$(SDKDIR)/../CMSIS_5/CMSIS/DSP/Include CXXFLAGS += -I$(SDKDIR)/../CMSIS_5/CMSIS/Core/Include CXXFLAGS += -DARM_MATH_CM4 CXXFLAGS += -D__FPU_PRESENT=1 EXTRA_LIBS += -larm_cortexM4lf_math EXTRA_LIBPATHS += -L$(SDKDIR)/../CMSIS_5/CMSIS/Lib/GCC
サンプルアプリケーション
ソースコードだけ貼り付けておきます。sine関数を計算して出力します。
/**************************************************************************** * Included Files ****************************************************************************/ #include <sdk/config.h> #include <stdio.h> #include <arm_math.h> /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * cmsis_main ****************************************************************************/ #ifdef CONFIG_BUILD_KERNEL int main(int argc, FAR char *argv[]) #else int cmsisdsp_main(int argc, char *argv[]) #endif { int i; float theta; for ( i = 0; i<100; i++ ) { theta = i * 3.1415*2 / 100.0; printf("arm_sin_f32(%8.5g) : %8.5g\n", theta, arm_sin_f32(theta) ); } return 0; }
このプログラムを書いた時に気がついたのですが、NuttXのprintf()関数は、浮動小数点型を出力する際フォーマット文字列で明示的にフィールド幅と小数点以下の数字を指示する必要があるようです。最初は無指定で出力していたのですが、四捨五入されて整数として表示されるので困惑しました。
実行結果はこんな感じになります。
スクリプト
CMSIS-DSPの環境設定用のスクリプトを以下に示します。Spresense SDKのインストールと、ターミナル・デバイス名の設定も混じっていますが、不要であれば適当に削ってください。spresenseディレクトリはホームディレクトリにあるものと仮定したスクリプトになっています。
Ubuntu 16.04 LTSで動作確認済みです。なおkermitの設定ファイルがspresense/sdkにコピーされますが、生のubuntu desktop 16.04 LTSにはckermitパッケージが入っていません。使ってみたい方はapt-getでインストールしてください。
######################################################################################## # Spresense SDK installation ######################################################################################## # based on https://developer.sony.com/ja/develop/spresense/developer-tools/get-started-using-nuttx/set-up-the-nuttx-environment # Install the enssential ubuntu tools. sudo apt-get install -yV git gperf libncurses5-dev flex bison gcc-arm-none-eabi genromfs pkg-config autoconf automake # Download the NuttX configuration tool, build and install cd ~ mkdir nuttxtool cd nuttxtool git clone https://bitbucket.org/nuttx/tools.git cd tools/kconfig-frontends/ ./configure --disable-shared make sudo make install cd ~ rm nuttxtool -rf # Clone the Spresense SDK repo. cd ~ git clone --recursive git@github.com:sonydevworld/spresense.git ######################################################################################## # CMSIS-DSP installation ######################################################################################## # Clone CMSIS-5 cd ~/spresense git clone https://github.com/ARM-software/CMSIS_5.git cd CMSIS_5 git checkout master git pull # Additional definition to use CMSIS-5-DSP cat >> ~/spresense/sdk/Make.defs <<-'EOF' CFLAGS += -I$(SDKDIR)/../CMSIS_5/CMSIS/DSP/Include CFLAGS += -I$(SDKDIR)/../CMSIS_5/CMSIS/Core/Include CFLAGS += -DARM_MATH_CM4 CFLAGS += -D__FPU_PRESENT=1 CXXFLAGS += -I$(SDKDIR)/../CMSIS_5/CMSIS/DSP/Include CXXFLAGS += -I$(SDKDIR)/../CMSIS_5/CMSIS/Core/Include CXXFLAGS += -DARM_MATH_CM4 CXXFLAGS += -D__FPU_PRESENT=1 EXTRA_LIBS += -larm_cortexM4lf_math EXTRA_LIBPATHS += -L$(SDKDIR)/../CMSIS_5/CMSIS/Lib/GCC EOF ######################################################################################## # Terminal device setting for Spresense ######################################################################################## # Terminal device name setting as /dev/ttySPRESENSE sudo cat <<-'EOF' | sudo tee /etc/udev/rules.d/52-spresense.rules > /dev/null # SONY SPRESENSE ( main board ) # The deivce will be linked to /dev/ttySPRESENSE SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE="0666", SYMLINK+="ttySPRESENSE" # If you have more than 1 CP210x devices connected to system, # you can not distinguish them correctly by above declaration. # In this case, you need to specify the unique serial number of # your SPRESENSE device. # In the following description, we assume your SPRESENSE board is # registered as /dev/ttyUSB0 # First of all, comment out the above declaration. # Then, run following command in the console. # sudo udevadm info -n /dev/ttyUSB0 | grep SERIAL_SHORT # Now, you will see the output like this # E: ID_SERIAL_SHORT=b869b9acca27e811a67ce54aa9a0087c # where b869.... is the unique serial number copy your displayed # strings and substitute the serial number of the following # declaration by your device's one. # Then, remove "#" of the following line to enable it. # SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{serial}=="b869b9acca27e811a67ce54aa9a0087c", MODE="0666", SYMLINK+="ttySPRESENSE" EOF # Make a script file for kermit cat > ~/spresense/sdk/terminal <<- 'EOF' #!/usr/bin/kermit + set line /dev/ttySPRESENSE set speed 115200 set carrier-watch off set flow-control none EOF chmod +x ~/spresense/sdk/terminal