Longan NanoでUSBのCDC転送にチャレンジしてみました。CDCで転送ができるとUSBケーブル一本でコンソール出力できる可能性があるからです。
で、まだまだまだまだ道のりは遠いですが、とりあえずライブラリのサンプルプログラムを無理やり動かしてCDC転送はできました。
まず、Platform IOで通常通り、プロジェクト作成します。デバイスは sipeed longan nanoです。
サンプルプログラムについてはGD32VF103_Firmware_Library_V1.0.1の中のExamples/USBFS/USB_Device/CDC_ACMの下にあるものを使用しました。
Sourceディレクトリの中の以下のファイルをプロジェクトディレクトリのsrcの下に放り込みました。
- app.c
- cdc_acm_core.c
- gd32vf103_hw.c
- gd32vf103_it.c
- system_gd32vf103.c
同じく、Includeディレクトリの中の以下のファイルをプロジェクトディレクトリのincludeの下に放り込みました。
- cdc_acm_core.h
- gd32vf103_it.h
- gd32vf103_libopt.h
- usb_conf.h
- usbd_conf.h
さらに、ドライバは、GD32VF103_Firmware_Library_V1.0.1/Firmware/GD32VF103_usbfs_driverの下にあるものを同様に
Sourceディレクトリの中の以下のファイルをプロジェクトディレクトリのsrcの下に放り込みました。ファイル名に usbh を含むもの、および dev_usb_host.c はホストモードのドライバっぽく、コンパイル中にエラーになるので外しました。
- drv_usb_core.c
- drv_usb_dev.c
- drv_usbd_int.c
- usbd_core.c
- usbd_enum.c
- usbd_transc.c
同じく、Includeディレクトリの中の以下のファイルをプロジェクトディレクトリのincludeの下に放り込みました。同様にファイル名に usbh を含むもの、および dev_usb_host.h は外しました。
- drv_usb_core.h
- drv_usb_dev.h
- drv_usb_hw.h
- drv_usb_regs.h
- drv_usbd_int.h
- usb_ch9_std.h
- usbd_core.h
- usbd_enum.h
- usbd_transc.h
platformio.iniは以下のように編集しました。
[env:sipeed-longan-nano] platform = https://github.com/sipeed/platform-gd32v.git board = sipeed-longan-nano framework = gd32vf103-sdk upload_protocol = dfu build_flags = -D USE_USB_FS -D__packed=
ソースコードの中で FIFO のサイズに関するマクロ定義の揺れがあるようで、今回は usb_conf.h を以下のように修正しました。
修正前は以下のような感じ。
#ifdef USB_FS_CORE #define RX_FIFO_FS_SIZE 128 #define TX0_FIFO_FS_SIZE 64 #define TX1_FIFO_FS_SIZE 128 #define TX2_FIFO_FS_SIZE 0 #define TX3_FIFO_FS_SIZE 0 #endif /* USB_FS_CORE */
修正後は以下のようにかく定義の頭に USB_ を追加したものを入れています。
#ifdef USB_FS_CORE // 頭に USB_ を追加 #define RX_FIFO_FS_SIZE 128 #define USB_RX_FIFO_FS_SIZE 128 #define TX0_FIFO_FS_SIZE 64 #define USB_TX0_FIFO_FS_SIZE 64 #define TX1_FIFO_FS_SIZE 128 #define USB_TX1_FIFO_FS_SIZE 128 #define TX2_FIFO_FS_SIZE 0 #define USB_TX2_FIFO_FS_SIZE 0 #define TX3_FIFO_FS_SIZE 0 #define USB_TX3_FIFO_FS_SIZE 0 #endif /* USB_FS_CORE */
これでビルドして書き込んでやると、dmesgに以下のように出力されて、/dev/ttyACM0 として認識されました。
[ 3666.200001] usb 2-1: USB disconnect, device number 2 [ 3666.511918] usb 2-1: new full-speed USB device number 3 using uhci_hcd [ 3666.732800] usb 2-1: New USB device found, idVendor=28e9, idProduct=018a, bcdDevice= 1.00 [ 3666.732804] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [ 3667.146893] cdc_acm 2-1:1.0: ttyACM0: USB ACM device [ 3667.148475] usbcore: registered new interface driver cdc_acm [ 3667.148476] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
$ sudo screen /dev/ttyACM0 9600
で screen で接続するとエコーバックされました。
wireshark でモニタするために公式ページの説明にそってセットアップします。
$ groups $USER xxx : xxx adm cdrom sudo dip plugdev lpadmin sambashare $ sudo adduser $USER wireshark ユーザー `xxx' をグループ `wireshark' に追加しています... ユーザ xxx をグループ wireshark に追加 完了。 $ sudo dpkg-reconfigure wireshark-common $ sudo modprobe usbmon $ sudo setfacl -m u:$USER:r /dev/usbmon* $ sudo wireshark QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
screenコマンドで接続したまま、usbmon0を選択してキャプチャして、キーボードで適当にカチャカチャ打ってエコーバックされるのを確認したあと、キャプチャを停止します。結果を見ますが、キーボード入力に伴うINTERRUPT転送が見えて鬱陶しいので、表示フィルタを以下のように設定してBULK転送のみが見えるようにします。
usb.transfer_type == 0x3
設定すると、以下のような感じになりました。
キーボードで「B」を入力してそれがホスト(host)からLongan Nano(6.13.3)へ送られたときのキャプチャです。カーソルのあるところが送信されたデータ(0x42)です。
それに対してエコーバックが帰ってきたのが以下です。
データが戻ってきているのがわかります。
とりあえず、CDCでエコーバックされるサンプルは動いたのですが、該当部分のソースを見ると、
while (1) { if (USBD_CONFIGURED == USB_OTG_dev.dev.cur_status) { if (1 == packet_receive && 1 == packet_sent) { packet_sent = 0; /* receive datas from the host when the last packet datas have sent to the host */ cdc_acm_data_receive(&USB_OTG_dev); } else { if (0 != receive_length) { /* send receive datas */ cdc_acm_data_send(&USB_OTG_dev, receive_length); receive_length = 0; } } } }
ということで、パケットバッファのデータを取り出さずにそのまま返送しているっぽいです。これをUSBシリアルっく使えるようにするにはもうひとひねり必要そうです。