STM32CubeIDEでSemihostingを使ってprintfを使う方法を解説します。
まずは下記の画像をご覧になってください。Semihostingを使うことでデバッグコンソールにprintf出力ができるようになります。

またUARTの線も使わないので省配線にもなるというメリットもあり、デバッグ作業がとても便利になります。ただし、速度は遅く処理の邪魔になりやすい点には注意してください。
以降では具体的にSemihostingでprintfをするための方法を解説していきます。
目次
1.前提条件
今回は下記の環境を前提に話を進めます。STLinkはNUCLEO-F401REに実装されているものをそのまま使いました。
- STM32CubeIDE ver.1.00
- NUCLEO-F401RE
2.printf用のプロジェクトの準備
2-1.プロジェクトの作成
まずは適当にプロジェクトを作成してください。Device Configuration Tool(CubeMX)で特別な設定は必要ありません。
2-2.syscall.cの無効化
Semihostingを使う場合はsyscall.cが競合してしまうので無効化しておきましょう。
- プロジェクトを右クリック→Properties
- C/C++ General→Path and Symbols→Source Locationタブ
- <プロジェクト名>/Src→Filterを選択して、Edit Filterボタンからsyscall.cを追加してください

2-3.リンカの設定
続いてリンカの設定を行います。まずはライブラリの追加です。
- プロジェクトを右クリック→Properties
- C/C++ Builde→Settings→Tool Settingsタブ→MCU GCC Linker→Libraries
- Libraries (-l)の『+ボタン』から『rdimon』を追加してください

次にライブラリの有効化の設定をします。
- プロジェクトを右クリック→Properties…
- C/C++ Builde→Settings→Tool Settingsタブ→MCU GCC Linker→Miscellaneous
- Other flagsの『+ボタン』から『-specs=rdimon.specs』を追加してください

3.printf用のコードを追加
3-1.printfの初期化
printfを使う前に初期化コードを入れておく必要があります。例えば、下記のように追加します。
main.c
/* USER CODE BEGIN 0 */
extern void initialise_monitor_handles(void);
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
initialise_monitor_handles();
/* USER CODE END 1 */
UARTを使った方法とは違い、setbuf()ではないことに注意してください。
3-2.printfの追加
実際にprintfを追加してみましょう。今回は定期的に『Hello World!!』するだけのプログラムにしました。
main.c
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
printf("Hello World!!\n");
HAL_Delay(1000);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
4.デバッグの設定
このプロジェクト用のデバッグ設定を作成します。
- プロジェクトを右クリック→Debug as→STM32 MCU C/C++ Application
- デバッガタブ→デバッグプローブで『ST-Link (OpenOCD)』を選択してください

続いて、このデバッグでSemihostingを使うための設定を追加します。
- Startupタブ→Initialization Commandsに『monitor arm semihosting enable』を追加してください

5.デバッグの実行
ここまでで準備は完了です。最後にDebugボタンを押してデバッグを実行してみましょう。

デバッグコンソールに出力されましたね!お疲れ様でした!
6.おわりに
本記事ではSTM32CubeIDEでSemihostingを使ってprintfを実現する方法をご紹介しました。
Semihostingを使うことで、UARTの線を使うことなくprintfが使えるようになります。また、出力はデバッグコンソールに行われるため、使い勝手は良いと思います。ただし、通信速度はあまり速くありません。
printfの使用頻度が少なく、printfをしても処理への影響が小さい時には便利な方法かと思います。