STM32マイコンのUSBペリファレラル機能を使い、PCとシリアル通信を行う手順を説明します。
マイコンとPCでシリアル通信が出来るようになると、マイコンのログが取得できるようになり、コードの通過チェックや状態確認などのデバッグ作業がはかどります。
また、STM32CubeIDE1.6.1でUSB通信ファームウェアをコード生成した際に発生したトラブルについての解決策も解説します。
- STM32のUSBペリフェラル機能を初めて使われる方
- 使用経験はあるが、最新の開発環境での使い方に戸惑っている方
- 自動生成されたコードがビルド出来ずに困っている方
検証環境・デバイス
やりたいこと | STM32とPCをUSBで接続してシリアル通信を行う |
統合開発環境 | STM32CubeIDE Ver1.6.1 |
PCのOS | Windows10 |
デバイス | STM32F103ZETx |
※ターゲットデバイスは他の型番でも基本は同じ操作です。
プロジェクトの新規作成
STM32CubeIDEを立ち上げたら、
ツールバーから File -> New -> STM32 Project と選択すると、下図が立ち上がります。

ここでデバイスの型式を指定して Next> をクリックします。
もしNucleoなどの評価ボードを使う場合は、BoartSelectorのタブからボードを選択すると良いです。ボード固有の各種設定が出来ている状態でプロジェクトが生成されますので。
Next>をクリックしたら下図になります。

ここでProjectNameを設定して”Finish”をクリックします。
すると、”Open Associated Perspective?” とか聞かれますがYesとしておきます。しばらくするとプロジェクトが作成されて、STM32CubeMXが立ち上がります。
MXは以前は別アプリでしたが、今はCubeIDEに統合されています。

MXでデバイス設定を行う
USBを使用するためにMXで最低限設定しないといけないのは、下の2つです。
- Pinout & Configuration
- Clock Configuration
Pinout & Configuration
Pinout & Configuration の設定では、USBペリフェラル機能の有効化と設定を行います。
まずはConnectivity → USB から、Mode欄でDevice(FS)にチェックを入れます。

こうすると、Middleware → USB_DEVICE が選択できるようになります。
そこからClass For FS IP欄で ”Communication Device Class” を選択します。

その他のCategoriesに対して、基板固有の設定をしていきます。今回の例では、下記の2個を設定しました。
- RCC → HSE → Crystal/Ceramic Resonator を選択
- SYS → Debug → Serial Wire を選択
Clock Configuration
Clock Configurationでは、USB用クロックの周波数設定を行います。USBペリフェラル機能を使うためには、USB用クロックの周波数を48MHzにしなければなりません。
Clock Configuration タブをクリックすると、下記のように自動設定を走らせるか聞いてきます。とりあえず”Yes”としてみます。

自動でガチャガチャ動いて設定してくれたのですが、今回の基板はHSEに接続している発振子が16MHzだったので、ここからさらに調整していきます。
まずはHSEのinput frewuencyを16MHzにして、そこからUSB_CLKが48MHzになるように、その上でHCLKがデバイスの最大周波数(例のデバイスは72MHz)に近くなるようにしていきます。
クロック設定はいろいろなところが編集できるので戸惑いますが、ポイントは3点です。
- 回路図を確認して、接続されている発振子の周波数を設定
- USBクロックは48MHzに設定する
- HCLKは出来るだけ大きな値にする
いろいろなところをポチポチした結果、今回は下のよう設定しました。

設定がまずくて周波数がマイコンのスペックを超えている箇所は赤色になってくれるので非常にわかり易いです。
一通り設定を行いMXをセーブしようとCtrl+Sとすると、コード生成を行うか?と聞かれます。Yesでコード生成が実行されます。このコードに、動作確認用の簡単なコードを記述していきます。
プロジェクトのビルド設定
ここでトラブルが発生しました。
コードを記述する前にコード生成されたままの状態でビルドをしてみると、エラーが発生してビルドが出来ませでした。
まずはこのエラーを解消し、そのあとでコードを記述していきます。私はこのエラー解消で結構つまづいてしまいました。
Includeパスの設定
エラー内容を確認すると、生成されたUSB関連のインクルードファイルが見つかっていないようです。まずはこれらのIncludeファイルの場所を設定します。
メニューバーから Project → Properties とクリックしてプロパティ設定画面を開きます。
プロパティ設定画面で、C/C++Build → Setting → MCU GCC Compiler → Include paths とすると、Includeファイルのパス設定画面になります。
(下図の①~④)

ここで⑤をクリックするとIncludeパスを追加できます。今回追加するパスは下の4個になります。
- /Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc
- /Middlewares/ST/STM32_USB_Device_Library/Core/Inc
- /USB_DEVICE/App
- /USB_DEVICE/Target
これらをworkspaceからの相対パスで設定した結果が下記になります。
ここまでやったら Apply → Apply and Close とクリックすればIncludeパスの設定完了です。

ソースフォルダの設定
次はビルドするソースコードのフォルダを設定します。
メニューバーから File → New → Source folder をクリックしてNew Source Folder画面を開きます。ここのFolder name に、ビルドに追加したいフォルダを追加してFinishをクリックします。
今回追加するフォルダは、”Middlewares”、”USB_DEVICE”の2つになります。

この操作は、自前のソースコードを保存するためにフォルダを新規作成した場合にも必要な操作です。この設定をしないと、フォルダ内のソースコードがビルド対象になりません。
重複するソースコードをビルドから除外
ここまで設定すれば普通は問題無くビルドできるようになると思いますが、何故かまだビルドが出来ませんでした。
エラーメッセージを確認すると、どうも同じ名前の関数が2個定義されているようです。よくよく確認してみると、中身の同じファイルが2つ、CubeMXによって生成されていました。
STM32CubeIDEのバグでしょうか??(Verは1.6.1になります)こんなこと、以前のCubeIDEでは経験したことありません。
片方のファイルを削除すれば良いのですが、CubeMXでコード生成するたびに生成されるので、その都度削除するのも面倒です。片方のファイルをビルドの対象外に設定しておきます。

今回は、~~~~/Templates というフォルダをビルドから除外する設定とします。Project Explorer でTemplates上で右クリックして、Resource Configurations → Exclude from Build.. をクリック。

立ち上がったWindowにてSelect All → OK でビルドから除外できます。

これでビルドの設定は全て完了しました。エラー無しでビルド完了するようになりました。
ファームウェアの使い方
ファームウェアの使い方といってもPCとのシリアル通信なので、送信データ出力関数の使い方とデータ受信時の制御記述箇所を把握すればOKです。初期化はmain.c内に自動生成されて完了しています。
送信データ出力関数
送信データ出力関数は、”usbd_cdc_if.h”ファイル内に下記で設定されています。
使う際はこちらのヘッダーを#includeしてください。
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);
送信データ配列ポインタと送信データ長を指定するだけ。簡単です。
データ受信時の制御記述箇所
データ受信時の制御記述箇所は、“usbd_cdc_if.c”ファイル内の「CDC_Receive_FS」関数の内部になります。
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
}
この関数内の
/* USER CODE BEGIN 6 */ から /* USER CODE END 6 */ の中に
受信時のコードを記述していきます。(受信データは引数のBufに入っています。)
コールバックで簡単な動作確認
下コードのように、データ受信時の動作として受信データを返信するコードを1行追記します。
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
CDC_Transmit_FS(&Buf[0], 1);// 追加コード (単純なオウム返しを行う)
return (USBD_OK);
/* USER CODE END 6 */
}
これをビルドして書き込み、動作確認してみます。
プログラムを書き込んだ基板とPCをUSBで接続してTera Termを起動します。基板が正しく動作していれば、”STMicroelectronics Virtual COM Port”という名前で認識されています。
Tera Term とは、定番のターミナルソフトです。オープンソースで公開されているので、使ったことのない方は試してみてください。リンクを貼っておきます。

Windows10であれば、特別にドライバをインストールする必要はありません。STマイクロのWEBサイトにドライバソフトがアップされていて紛らわしいですが、Windows8以前のOS用のものでWindows10では不要です。

無事にエコーバックが確認出来ました。
まとめ
STM32でUSBペリフェラル機能を使う為に、MXで行う作業をまとめると下記になります。
- Pinout & Configuration → Connectivity → USB からUSB端子の設定
- Pinout & Configuration → Middleware → USB_DEVICE からミドルウェア設定
- Clock Configuration にてUSB用クロックの周波数を48MHzに調整
コード生成されたミドルウェアの使い方は下記になります。
シリアル出力するには、”usbd_cdc_if.h” ファイル内の「CDC_Transmit_FS」 関数を使います。
シリアル入力があった時の処理を記述するのは、”usbd_cdc_if.c”ファイル内の「CDC_Receive_FS」関数内の
/* USER CODE BEGIN 6 */ から /* USER CODE END 6 */
の間になります。
もしビルドが上手くいかないようでしたら、本記事の【プロジェクトのビルド設定】の項目を参照してみてください。
その他のHowto記事
STM32のソフト開発に関するHowtoは他にも記事があります。こちらも参考にしてください。
コメント