printfは非常に有用なデバッグ手段で、STM32CubeIDEでprintfを使いたいという方もいらっしゃるでしょう。本記事ではUARTを使って、STM32CubeIDEでprintfが使えるようにするまでの手順をわかりやすく解説します。
はじめに下記の画像をご覧になってください。STM32CubeIDEのデバッグ実行中の画面をキャプチャしてものです。printfで『Hello World!!』を出力するコードを書いて、それが画面下部のターミナルで出力されていることがわかるかと思います。
printfの実現方法はいくつかありますが、UARTを使う方法では、以下のメリットがあります。
- デバッグ機能とprintf出力を平行して利用できる
- IDE内のターミナルでprintfの出力を見ることができる
- そこそこ速い通信ができるため、処理の邪魔になりにくい
とても便利な方法ですが、デメリットもあります。
- UARTを1つ潰してしまう
当たり前ですがUARTを使う以上仕方ないことですね。UARTを1つ潰してしまいますが、上記のメリットを考えると、かなり便利でおすすめできる方法です。
前置きが長くなりましたが、ここからは実際にprintfできるまでの方法を解説していきます。
目次
1.前提条件
今回は下記の環境を前提に話を進めます。NUCLEOとはUSBケーブルで接続しているだけですが、デバッグ通信とUART2との通信(仮想シリアルポート)の両方の通信ができます。
もちろんこの環境でなくても、パソコンとデバッグケーブル・UART(シリアルポート)が繋がっている環境であれば大丈夫です。
- STM32CubeIDE ver.1.00
- NUCLEO-F401RE
2.printfの準備
2-1.UARTの初期化コード生成
まずはDevice Configuration Tool(CubeMX)を使ってプロジェクトを作りましょう。ここではUARTの設定だけ説明しますね。
- Pinout & Configurationタブ→Connectivity→USART2→Mode
- ModeをDisableからAsynchronousに変更してください
- それ以外の設定は下記の画像にならって設定してください
Baud Rateは通信速度なので、もっと高速にしたい時はもっと大きな値にしてください。
設定が終わったらコードを自動生成してください。
2-2.printfの実装
printfを実装してUARTでテキストを送信するようにしてあげましょう。下記のコードをコピペしてください。
main.c
/* USER CODE BEGIN 4 */ int _write(int file, char *ptr, int len) { HAL_UART_Transmit(&huart2,(uint8_t *)ptr,len,10); return len; } /* USER CODE END 4 */
printfの内部で実際に書き込み処理をしているのは_write()関数です。_write()関数はweak宣言されているので、新しく作って上書きした形になります。
2-3.printfの初期化
printfはこれだけでは動作せず、初期化してあげる必要があります。printfを呼び出す前に、例えば下記のように1回だけ実行してあげてください。
main.c
int main(void) { /* USER CODE BEGIN 1 */ setbuf(stdout, NULL); /* USER CODE END 1 */
後、stdio.hのインクルードは忘れずにしておいてくださいね。言うまでもないとは思いますが、念のため。
main.c
/* USER CODE BEGIN Includes */ #include <stdio.h> /* USER CODE END Includes */
2-4.printfの追加
とりあえず今回は定期的に『Hello World!!』を出力するようなプログラムを書きました。
main.c
/* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ printf("Hello World!!\r\n"); HAL_Delay(1000); /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
3.printfの動作確認
最終的にはSTM32CubeIDE上のターミナルで確認しますが、準備に時間がかかりますし、ここまでの内容に問題がないか確認するために、Tera Termなどを使って動作確認しておきましょう。
Tera Termなどのターミナルがない方や、自身のある方は読み飛ばしていただいても構いません。
Tera Termの設定を、先ほどのUARTの設定に合わせてあげます。
STM32CubeIDEでデバッグ実行を開始して、Tera Termに『Hello World!!』が出力されることを確認しましょう。
出力されましたね!
これだけでもprintfを使ったデバッグはできますが、ターミナルプログラムを別途立ち上げておくのは、やはり面倒です。以降では、ターミナルをSTM32CubeIDEの中で立ち上げる方法を解説します。
4.STM32CubeIDEにターミナルを入れる
STM32CubeIDEにターミナルを入れるのはちょっと面倒ですが、くじけずやりましょう。難しいところはないので安心してください。
ソフトウェア構成を図示すると下記のようになります。
TM Terminalがターミナルプログラム本体で、Eclipseのプラグインです。RXTXはシリアル通信するためのプログラムです。2つありますが、Javaにインストールする方が基本ソフトウェアで、もう1つの方がそれを利用するEclipseのプラグインです。
4-1.RXTXをJavaにインストール
下記のURLから『RXTXcommon.jar』と『rxtxSerial.dll』の2つのファイルをダウンロードしてください。
ダウンロードしたファイルはそれぞれ下記の表の通りにコピーしてください。
ファイル | コピー先 |
RXTXcommon.jar | C:\ST\STM32CubeIDE_1.0.0\STM32CubeIDE\jre\lib\ext |
rxtxSerial.dll | C:\ST\STM32CubeIDE_1.0.0\STM32CubeIDE\jre\bin |
4-2.RXTXのプラグインをインストール
- STM32CubeIDEのメニュー→Help→Install New Software…
- Addボタンをクリックして下記のURLを追加してください
http://rxtx.qbang.org/eclipse - 最新版のRXTXをインストールしてください
4-3.TM Terminalをインストール
- STM32CubeIDEのメニュー→Help→Install New Software…
- Work with:でEclipseのリポジトリを選択してください
https://download.eclipse.org/releases/2019-03
※2019-03はIDEのバージョンによって変わります - General Purpose Toolsの中にある『TM Terminal』と『TM Terminal Serial Connector Extensioons』を選択し、インストールしてください
5.STM32CubeIDEのターミナルにprintf出力
準備が整いましたのでSTM32CubeIDE内でターミナルを起動し、printf出力を確認しましょう。
5-1.ターミナルの起動
- メニュー→Window→Show View→Other…
- Terminal→Terminalをクリックしてください
- Terminalビューのパソコンのマークをクリックし、下記の画像を参考にシリアルターミナルの設定をしてください
5-2.デバッグを実行
デバッグを実行してください。Terminalビューにprintfの出力が表示されます。
出力されましたね!
6.おわりに
printfを使ったデバッグは今でも有用なデバッグ手段です。本記事では、UARTを使ってprintfを実現する方法を解説しました。
UARTを使うことで、デバッグ実行と並行した利用、IDE内のターミナルでの出力確認、そこそこの高速通信というメリットがあります。UARTを1つ潰す以上の価値があるでしょう。
この記事で皆さんのデバッグが少しでも楽になれば幸いです。