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