概要
STM32CubeIDEのFWプロジェクトに、ソースファイル(または、それらを含むフォルダ)を追加する一例を紹介します。ここでは例として、CMSIS-DSPのライブラリのソースファイルを追加します。この記事の大まかな流れは以下の通りです。
0. 準備
以下ソースファイル追加の操作手順です。
1. 追加したいファイルのコピーを作成
2. ファームウェアプロジェクトを開く
3. ファームウェアプロジェクトにソースファイルを追加
4. インクルードファイルのパスを設定
5. 使用しないファイルをファームウェアプロジェクト上から削除
6. コンパイラの最適化オプションの設定
( 5,6に関しては、必要なケースのみ)
使用したサンプルコードについて
0ー準備
- ファイル追加を必要とするFWプロジェクト
(例:ここでは、cmsis_dsp_firというFIRのFWプロジェクト) - 追加(インポート)するファイル
(例:CMSIS-DSPライブラリ) - 動作確認用のボード
(例:NUCLEO-U545RE-Q)
*CMSIS-DSPライブラリは、STM32Cubeのソフトウェアパックもしくは、GitHubからでも入手可能です。今回は、下のリンク先にあるSTM32CubeU5のソフトウェアパックにあるCMSIS-DSPライブラリを利用しました。
https://www.st.com/ja/embedded-software/stm32cubeu5.html
使用したSTM32CubeIDEのVersion:Version: 1.19.0
1ー追加したいファイルのコピーを作成
追加したいファイルまたはフォルダを、FWプロジェクト内にコピーしておきましょう。ここでは、下図のように、FWプロジェクト内にDSPというフォルダを新規に作成し、ここに必要なファイルをコピーします。CMSIS-DSPライブラリの必要なファイルは、次の3つのフォルダーです。
・Includeフォルダ
・PrivateIncludeフォルダ
・Sourceフォルダ
2ーファームウェアプロジェクトを開く
STM32CubeIDE(以下CubeIDE)を起動し、[File]ー [Open Pojects from File System...] を選択し、FWプロジェクトを開く
3ーファームウェアプロジェクトにソースファイルを追加
① 画面上の [File] - [Import] メニューを選択
② Importウィザードの選択画面が開いたら、File System を選択し、[Next] ボタンをクリックして、File SystemのImportウィザード画面を開く。
③ インポート元を指定:
- ”From directory”の [Browse] ボタンをクリックして、インポートしたいファイル(またはフォルダ)を含むフォルダを指定
- 下に表示されるツリー表示からインポートしたいフォルダにチェックをし、その右に表示されたファイルに関してもインポートするファイルを選択
④ インポート先を指定:
”Into folder”の [Browse] ボタンをクリックして、インポート先のCubeIDE内のフォルダを指定。
⑤ インポートオプションの設定
[Advanced] ボタンをクリックし、すべてのオプションを有効にする。
オプションの設定完了後、[Finish] ボタンをクリック。
インポートの設定内容と、設定後のCubeIDEとファイルシステムの状態は、下図のようになります。(図をクリックすると別ウィンドウに拡大表示)

4ーインクルードファイルのパスを設定
追加したヘッダーファイルにパスを通すための設定を行います。
①画面左端にあるProjectExplorerの中でプロジェクトを選択して、右クリックして表示されるメニュー からProperties をクリック
(もしくは、画面上のProjectメニューからPropertiesをクリックします。)

② [C/C++ Build] - [Settings] を選択
③ [Tool Settings]のタブ にある [Include paths] を選択
④include pathsの横にあるアイコンをクリック
⑤ [File System..]ボタン をクリックし、パスを通したいフォルダを指定し、[OKボタン] をクリック。include pathを複数設定する場合は、④ー⑤を繰り返し行う。

WindwosではFile systemボタンでパスを指定すると、"\"(バックスラッシュ)を使用した絶対パスで表示されますが、ここでは、上図のように"/"(スラッシュ)を使用し、相対パスに変更してあります。
CMSIS-DSPライブラリの場合は、下図のように2つのパスを追加します。
⑥パスを追加完了後、[Apply and Close] ボタンをクリックし、その後、Settingsのダイアログが表示されるので、[Rebuild Index] ボタンをクリックします。
CMSIS-DSPライブラリを使用する際は、”arm_math.h” のヘッダーファイルをインクルードする必要があります。
今回は、サンプルコードのmain.cのソースコードに記載済みです。
CubeIDEへのソースファイルの追加手順としては、以上となります。
今回は、インポートしたライブラリの中に不要なファイルも含まれているため、以下の操作を行います。
5ー使用しないファイルをファームウェアプロジェクト上から削除
サンプルコードで使用するCMSIS-DSPのAPIは、
・arm_fir_init_q15()
・arm_fir_q15()
上の2つのみで、いずれもSourceフォルダ内にあるFilteringFunctionsのAPIです。
① FilteringFunctionsフォルダ以外のAPIフォルダを削除
STM32CubeIDE上での削除方法
削除したいファイルを選択し、キーボード上のDeleteキーを押すか、右クリックしてDeleteを選択することで削除できます。「4. インポートの設定」にて仮想フォルダを使用しているため、実際のファイルシステム上のフォルダは削除されません。
② FilteringFunctionsフォルダの中の使用しないファイルを削除
Sourceフォルダ下の各フォルダの中には、大きく分けて次の2種類あります。
・各APIのソースファイル(arm_fir_q15.c etc.)
・各フォルダにあるAPIをまとめたソースファイル(FilteringFunctions.c etc.)
プロジェクトに両方とも追加すると、関数の定義が重複することになるので、どちらか一方のみにする必要があります。
今回は、APIをまとめたソースファイル(FilgeringFunctions.c, FilteringFunctionF16.c)を削除して進めます。
6ーコンパイラの最適化オプションの設定
このFWプロジェクトでは、CMSIS-DSPライブラリを使用しましたので、 最適化オプションの設定を行います。ProjectのPropertiesの中で
[ C/C++ Build ] - [ Settings ] - [ MCU/MPU GCC Compiler ] - [ Optimization ]
を選択し、Optimization levelを-Ofastに変更。

以上で、CMSIS-DSPライブラリ追加時の操作が完了です。
最後に、使用したサンプルコードの内容を紹介します。
使用したサンプルコードについて
使用したサンプルコードは、FIRフィルタ―をCMSIS-DSPライブラリを使用して実装した内容となっています。コード内にあるノイズを含むサイン波のデータ配列:aInputValues1[](Q1.15形式)を、FIRフィルタし、その結果の配列(Q1.15形式)をバッファ(firOutput[])に格納するシンプルな内容です。STM32U545マイコンを搭載したNUCLEOボード(NUCLEO-U545RE-Q)をターゲットとしています。
STM32CubeMXの設定とmain()コード [ ⇐ クリックすると展開します ]
(1) 下のようにSTM32CubeMXを操作・設定を行い、初期化コードを含んだFWプロジェクトを生成。(2) 生成されたmain.cの中身のコードを以下のように変更。
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "arm_math.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define ARRAY_SIZE 100
#define FIR_TAP_NUM 5
#define BLOCK_SIZE ARRAY_SIZE
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* Array of input values in Q1.15 format */
static int16_t aInputValues1[ARRAY_SIZE] =
{
0, 5276, -1548, 13844, 7, 17551, 5802, 16142, 14198, 12009,
21624, 8678, 24576, 8672, 21611, 11990, 14172, 16111, 5765, 17510,
-37, 13797, -1598, 5225, -51, -5327, 1498,-13892, -52,-17592,
-5838,-16174,-14223,-12029,-21637, -8685,-24576, -8665,-21597,-11970,
-14146,-16080, -5729,-17469, 82,-13749, 1647, -5174, 103, 5378,
-1449, 13939, 96, 17632, 5874, 16205, 14249, 12048, 21650, 8691,
24575, 8658, 21583, 11950, 14120, 16048, 5692, 17428, -127, 13701,
-1697, 5122, -154, -5429, 1399,-13987, -141,-17673, -5910,-16236,
-14274,-12068,-21663, -8698,-24575, -8651,-21570,-11930,-14094,-16016,
-5655,-17387, 171,-13654, 1747, -5071, 206, 5480, -1349, 14034,
};
static q15_t firCoeffs[FIR_TAP_NUM] = {
2212, 8848, 13272, 8848, 2212,
};
static q15_t firOutput[ARRAY_SIZE]={0}; // FIR出力
static q15_t firState[FIR_TAP_NUM + BLOCK_SIZE] = {0}; //CorTex33
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void SystemPower_Config(void);
static void MX_GPIO_Init(void);
static void MX_ICACHE_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the System Power */
SystemPower_Config();
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ICACHE_Init();
/* USER CODE BEGIN 2 */
arm_fir_instance_q15 fir;
arm_fir_init_q15(&fir, FIR_TAP_NUM, firCoeffs, firState, BLOCK_SIZE);
arm_fir_q15(&fir, aInputValues1, firOutput, BLOCK_SIZE);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
実行結果 [ ⇐ クリックすると展開します ]
FIRへの入力データとFIR後の出力データを、データ配列のインデックス値を横軸にしてプロットしてみました。 ちなみに、今回のサンプルFWのデータは、下のSTM32G4Cubeソフトウェアパック:
https://www.st.com/ja/embedded-software/stm32cubeg4.html
のFMACのExampleのサンプルコード:”FMAC_FIR_PollingToIT” で使われている入力データの一部を使用しています。このSTM32G4Cubeのサンプルコードでは、FMACのゲインを2倍(GAIN==1)に設定しているため、今回のCMSIS-DSPでの演算結果は、この1/2の振幅となっています。
今回のサンプルコードでは、CMSIS-DSPライブラリの関数を使用して、ソフトウェアによるFIR演算をしましたが、STM32U5シリーズなどの一部のSTM32マイコンでは、フィルタ演算アクセラレータ(FMAC) を使用してFIR/IIRの演算をすることが可能です。FMACはSTM32マイコンの周辺機能の一つとして搭載されており、ソフトウェアによる演算ではないため、CPU負荷の軽減につながります。
関連URL












