STM32のUSB CDCにC# SerialPortで接続できない時の対応方法

STM32マイコンソフト

以前の記事でSTM32マイコンのUSBペリファレラル機能を使い、PCとシリアル通信を行う手順を説明しました。

Tera Term などのターミナルソフトではこの記事の通りで動いているのですが、C#のSerialPortクラスを使用して通信をしようとしたところ、接続が出来ないことがありました。

原因はUSB CDCのコマンド未実装によるものでした。このような場合の対応方法を記載します。

検証環境・デバイス

 やりたいこと  C#のSerialPortクラスでSTM32とUSBシリアル通信を行う 
 統合開発環境  STM32CubeIDE Ver1.6.1
  デバイス STM32F765ZITx
 PCフレームワーク .NET Framework 4.8

.NET Framework の5.0以降のバージョンでは、SeriapPortクラスが未対応になっています。SerialPortを使う場合は、Ver4.8以前の.NETをインストールして使用してください。

接続出来なかった時の状況

下記に記載したのが接続できなかった時の状況です。TeraTermなどでは通信できるのですが、C#のSerialPortクラスでは接続が出来ない状況でした。

ここでの設定自体に間違いはありません(コードの不足が原因)ので、設定やコードは参考にしていただいて問題有りません。

STM32CubeIDE設定

STM32をUSBでPCとつなぐために、CubeMXで下記のようにCommunication Device Class に設定をします。

Device_Onlyにチェック画面
Connectivity → USB_OTG_FS Mode で Device_Onlyを選択
Communication Device Class に設定画面
Middleware → USB_DEVICE でCommunication Device Classを選択

Configurationは全てデフォルトのままとしています。

C#のSerialPort接続 コード

C#側のSerialPortクラスの記述は下記のようになります。

using System.IO.Ports;

var usbPort =  new System.IO.Ports.SerialPort(this.components);

usbPort.BaudRate = 115200;
usbPort.Parity = Parity.None;
usbPort.DataBits = 8;
usbPort.StopBits = StopBits.One;
usbPort.Handshake = Handshake.None;
usbPort.PortName = "COM1";
usbPort.Open();    //ここで例外が発生する。

これらのコードをビルドしてPCにSTM32ボードを接続、C#アプリを実行すると最後の” usbPort.Open();” のところで例外が発生してしまい、SerialPortの接続が上手くいきませんでした。

原因と対策方法

原因は、STM32側のコードにありました。

CubeMXでCommunication Device Class としてUSBを設定しているのですが、PCからのリクエストに対応するコードを記述しておらず、リクエストが正しく返ってこない→例外発生となっていたようです。

コードを追記すべきファイルは、CubeMXで生成された”usbd_cdc_if.c”ファイルになります。このファイルの中にある”CDC_Control_FS”関数にコードを記述します。追記するコートは下記のようになります。

static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
  /* USER CODE BEGIN 5 */
  //追加コード①
  static uint8_t lineCoding[7] = {
        0x00, 0xC2, 0x01, 0x00,  //119200bps
        0x00,                    //1 stop bit
        0x00,                    //Parity None
        0x08                     //8 data bits
  };
  //追加コード①ここまで

  switch(cmd)
  {

・・・

    case CDC_GET_LINE_CODING:
        //追加コード②
    	memcpy(pbuf, lineCoding, sizeof(lineCoding));
        //追加コード②ここまで
    break;

・・・

CDC_GET_LINE_CODING” というのは、通信レートやパリティなどのシリアル通信の各種設定をホスト(PC)に返すコマンドになります。ここに、通信設定を返信するコードを追記すれば良いのです。

上のコードでは、通信設定は”lineCoding”配列に記述してあります。データの構造については、下のようUSBの仕様で規定されています。

INDEX 内容
0~3 通信速度(bps) 
4  ストップビット(0:1bit, 1:1.5bits, 2:2bits)
5 パリティ(0:None, 1:Odd, 2:Even, 3:Mark, 4:Space)
6 データビット長さ(5, 6, 7, 8, 16)

CDC_Control_FS ”関数内に生成されているコメントにも同様のコメントが記載がされています。

このコードをビルド、書き込みしてテストしたところ、無事にC#のSerialPortクラスでSTM32と接続することが出来ました。

コメント