STM32Cube USB Device Libraryを使ってPCと通信

ST社が提供しているHALなどのライブラリは構造が複雑で、何がどう動いているのか分からないものを使いたくないという気持ちがあって敬遠してきた。

しかしUSBを使ってPCと通信しようとしてこれを使わざるを得なくなった。
USBの通信仕様が思った以上に複雑で、USB1.1の規格書だけでも300ページ以上ある。確かによくできてはいるけど、よくこんなものが世界標準になったなと感心した。

これを習得するのには時間がかかるし、さらにまともなライブラリとしてまとめるには恐らく数千行のコードを書く必要が出てくる。私の能力だと仕事の忙しさによっては半年以上かかるかもしれない。この先USB2.0やイーサネットを扱いたくなった時にまた同じことをやるのかと考えると、それは無いなと思った。
よってUSBに関してはST社が提供するUSB Device Libraryを使うことにした。

USB Device Libraryの実装

マイコン内部の情報をパソコンへ送信して画面に表示したいのでCDCクラスを使うことにした。
以下のサイトに手順が書かれている。少し古い記事なのでCubeMXのUIが変わっていたりするが、問題になるレベルではないだろう。
https://gsmcustomeffects.hatenablog.com/entry/2017/06/04/014231

PCとの通信で問題

ここからが本記事の本題なのだが、上の記事に従って通信をしたところ、TeraTermだと通信ができるのだが、EasyCommを使ったエクセルなど、他のソフトでは接続に失敗してしまう。

TeraTermでの挙動も若干変で、ボーレートを変えても同じ速度で通信されているようだ。恐らくUSB1.1で出せる最高速度で固定されている。さらにストップビット、パリティの設定を変えても普通に通信できる。

ST-Linkのように完全にシリアル通信を再現するものを想定していたが、どうやら違うようだ。これは私の予想だが、ST-LinkはCDCクラスを使ったUSB通信に加えてマイクロソフトの通信規格であるバーチャルCOMポート(VCP)まで実装されているのに対して、上の記事で実装できるのはCDCクラスを使ったUSB通信までということではないか。

私の環境でデバイスマネージャで確認するとST-Linkの方は「STMicroelectronics STLink Virtual COM Port(COM3)」と表示されているのに対して実装したUSBの方は「USB シリアル デバイス(COM7)」と表示されている。どちらもCOMxと表示されているので同じだろうと思ったが違うようだ。紛らわしい!

解決策

USB Device Libraryを使ってプロジェクトを作ると「usbd_cdc_if.c」というファイルができるが、この中にある「CDC_Control_FS」という関数に以下のように追記することによって接続に失敗する問題は解決した。


元の状態

case CDC_GET_LINE_CODING:

break;


追記後

case CDC_GET_LINE_CODING:
    *((uint32_t*)&pbuf[0]) = 921600;
    pbuf[4] = 1;
    pbuf[5] = 0;
    pbuf[6] = 8;
    break;

実際にファイルを見てみれば分かると思うが、pbufという配列がコマンドデータを扱っている。ここからは予想だが、PCと接続するときにデバイスの情報を読み取りに来て、ここに何も入っていないからエラーになっていたのではないか。

通信速度がボーレートに影響されない点やパリティなどの設定が反映されないことに変わりはないが、通信自体はできるようになったのでこれで良しとする。

本当はVCPやCDCクラスの規格書を読んだりすれば良いのだろうけど、趣味でも書類と格闘するのはごめんだ。