Longan NanoでUSB CDC転送(まだまだ)

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シリアルっく使えるようにするにはもうひとひねり必要そうです。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)