STM32とPCをUSBで接続してシリアル通信する方法

STM32マイコンソフト

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に統合されています。

STM32CubeMX起動画面
STM32CubeMX起動画面

MXでデバイス設定を行う

USBを使用するためにMXで最低限設定しないといけないのは、下の2つです。

  • Pinout & Configuration
  • Clock Configuration

Pinout & Configuration

Pinout & Configuration の設定では、USBペリフェラル機能の有効化と設定を行います。

まずはConnectivity → USB から、Mode欄でDevice(FS)にチェックを入れます。

Device(FS)にチェック画面
Device(FS)にチェック

USB_OTG機能のあるSTM32デバイスの場合、表示が異なると思います。

その場合は下記のように設定してください。

USB_OTG設定画面
USB_OTG設定画面

こうすると、Middleware → USB_DEVICE が選択できるようになります。

そこからClass For FS IP欄で ”Communication Device Class” を選択します。

VPCを選択画面
VPCを選択

その他のCategoriesに対して、基板固有の設定をしていきます。今回の例では、下記の2個を設定しました。

  • RCC → HSE → Crystal/Ceramic Resonator を選択
  • SYS → Debug → Serial Wire を選択

Clock Configuration

Clock Configurationでは、USB用クロックの周波数設定を行います。USBペリフェラル機能を使うためには、USB用クロックの周波数を48MHzにしなければなりません。

Clock Configuration タブをクリックすると、下記のように自動設定を走らせるか聞いてきます。とりあえず”Yes”としてみます。

Clock Configuration画面
Clock Configuration画面 USB-CLKを48MHzに設定する

自動でガチャガチャ動いて設定してくれたのですが、今回の基板はHSEに接続している発振子が16MHzだったので、ここからさらに調整していきます。

まずはHSEのinput frewuencyを16MHzにして、そこからUSB_CLKが48MHzになるように、その上でHCLKがデバイスの最大周波数(例のデバイスは72MHz)に近くなるようにしていきます。

クロック設定はいろいろなところが編集できるので戸惑いますが、ポイントは3点です。

  • 回路図を確認して、接続されている発振子の周波数を設定
  • USBクロックは48MHzに設定する
  • HCLKは出来るだけ大きな値にする

いろいろなところをポチポチした結果、今回は下のよう設定しました。

ClockConfiguration設定例
Clock Configuration設定例

設定がまずくて周波数がマイコンのスペックを超えている箇所は赤色になってくれるので非常にわかり易いです。

一通り設定を行いMXをセーブしようとCtrl+Sとすると、コード生成を行うか?と聞かれます。Yesでコード生成が実行されます。このコードに、動作確認用の簡単なコードを記述していきます。

プロジェクトのビルド設定

ここでトラブルが発生しました。

コードを記述する前にコード生成されたままの状態でビルドをしてみると、エラーが発生してビルドが出来ませでした。

まずはこのエラーを解消し、そのあとでコードを記述していきます。私はこのエラー解消で結構つまづいてしまいました。

問題無くビルドできるならばこの項目は読み飛ばして頂いて構いません。

別型番のマイコンで試したところ、このビルドエラーは発生しませんでした。この項に記述している各種設定も不要(自動で設定済)でした。STM32F103ZETxのコード生成特有のバグかもしれません。

Includeパスの設定

エラー内容を確認すると、生成されたUSB関連のインクルードファイルが見つかっていないようです。まずはこれらのIncludeファイルの場所を設定します。

メニューバーから Project → Properties とクリックしてプロパティ設定画面を開きます。

プロパティ設定画面で、C/C++Build → Setting → MCU GCC Compiler → Include paths とすると、Includeファイルのパス設定画面になります。
(下図の①~④)

Includeパス設定画面
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パスの設定完了です。

Includeパス設定例
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.. をクリック。

Exclude from build 起動画面
Exclude from build 起動画面

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

Exclude from build 画面
Exclude from build 画面

これでビルドの設定は全て完了しました。エラー無しでビルド完了するようになりました。

ファームウェアの使い方

ファームウェアの使い方といっても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 とは、定番のターミナルソフトです。オープンソースで公開されているので、使ったことのない方は試してみてください。リンクを貼っておきます。

Tera Term Open Source Project

TeraTerm接続画面
TeraTerm接続画面にVCPが表示されます

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 */

の間になります。

もしビルドが上手くいかないようでしたら、本記事の【プロジェクトのビルド設定】の項目を参照してみてください。

TeraTermなどのターミナルソフトでは接続/通信が出来るのにC#のSerialPortクラスでは接続が出来ないことがあります。このような場合の対応について、別の記事に記載していますのでこちらもご参照ください。

その他のHowto記事

STM32のソフト開発に関するHowtoは他にも記事があります。こちらも参考にしてください。

割り込みを使う方法

Nucleoをデバッガとして使う方法

Flashメモリに読み書きする方法

コメント