組込みOS自作入門 環境構築 【Windows11, WSL2】(1/2 - USBシリアル編)

書籍『12ステップで作る 組込みOS自作入門』をWSL2で環境構築しようとしたところ、詰まったところがいくつかあったので手順を書き残しておこうと思います。

以下は2年ほど前にVirtualBoxを使って環境構築をした際の記事ですが、全く同じコマンドでできた訳ではありませんでした。
今回は特にUSBシリアルの認識に手こずりました。
hayariapp.hatenablog.com


長くなったため、記事を2つに分けました。
この記事ではUSBシリアルを認識させてデバイスファイル(/dev/ttyUSB0)を表示するまで、
次の記事で binutilsgccのインストールから Hello World を出力するまでを扱いたいと思います。

次の記事:
hayariapp.hatenablog.com



目次

環境


1. USBシリアルをWindowsから認識させる

USBシリアルケーブルをWindowsに挿してデバイスマネージャを開きます。
すると、
ほかのデバイス > USB-Serial Controller
と表示されました。
(COM1には別のデバイスを接続しています)


ドライバーが入っていないせいでこのような表示になります。

製品名などがわからない場合は以下の手順でVIDとPIDを確認してググるとわかると思います。
バイスマネージャでUSB-Serial Controllerを右クリック
> プロパティ > 詳細 > ハードウェアID

私の場合は ELECOM製 USBtoSerial変換ケーブル UC-SGT1 です。
まずはWindowsUpdateでドライバをインストールできないか確認します。

WindowsUpdate > 詳細オブション > オプションの更新プログラム

運良く「ELECOM CO., LTD. - Ports - 10/18/2013」が見つかりました。
これをインストール。

「Elecom USB-Serial Converter (COM3)」と認識されました。



2. USBシリアルをWSLから認識させる

2-1. USBシリアルをWSLにアタッチする

参考記事
ascii.jp

PowerShellでusbipd-winをインストール

PS > winget install usbipd-win

PowerShellを立ち上げ直してから接続されているデバイスを確認。

PS > usbipd list
Connected:
BUSID  VID:PID    DEVICE                                              STATE
1-2    056e:5004  Elecom USB-Serial Converter (COM3)               Not shared
1-3    0411:0338  USB 大容量記憶装置                                  Not shared
2-3    0d8c:0014  USB Audio Device, USB 入力デバイス                  Not shared
2-4    8087:0029  インテル(R) ワイヤレス Bluetooth(R)                Not shared

Persisted:
GUID                                  DEVICE


BUSID 1-2 を共有可能状態にします。

PS > Start-Process usbipd.exe "bind --busid 1-2" -Verb runas
PS > usbipd list
Connected:
BUSID  VID:PID    DEVICE                                                        STATE
1-2    056e:5004  Elecom USB-Serial Converter (COM3)                  Shared
(略)

WSLにアタッチ。
私の環境では1度目はエラー、同じコマンド2度連続で実行するとアタッチできるというケースが多いです。

PS > usbipd attach --wsl --busid 1-2
usbipd: info: Using WSL distribution 'Ubuntu' to attach; the device will be available in all WSL 2 distributions.
usbipd: info: Using IP address 172.31.176.1 to reach the host.
PS > usbipd list
Connected:
BUSID  VID:PID    DEVICE                                                        STATE
1-2    056e:5004  Elecom USB-Serial Converter (COM3)                  Attached

WSL側から確認。

$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 056e:5004 Elecom Co., Ltd UC-SGT
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Elecom製のUSBシリアルケーブル UC-SGT が表示されました。

2-2. デバイスファイル(/dev/ttyUSB0)を表示する

step1でHello WorldするにはUSBシリアルに対応するデバイスファイル(/dev/tty*)の特定が必須ですが、ここでハマりました。「lsusbには表示されるがデバイスファイルが表示されない」という状況でした。
結論から言うとUSBシリアルのドライバーが入っていないせいでした。
Windows側にドライバを入れて認識したらもうドライバの心配はなし、ではないんですね。WSL側にもドライバが必要になります。

参考記事
qiita.com


PL2303というドライバを入れます。このドライバを入れる根拠は次の項に書きました。あまり役に立たない内容ですが...

参考記事の通りに進めます。

私は libncurses-dev をインストールしたか定かでないです。(この作業の前にも色々とコマンドを試したのですが、途中でコマンドの履歴が消えて辿れなくなったため)

$ sudo apt install build-essential flex bison libssl-dev libelf-dev dwarves libncurses-dev

$ git clone https://github.com/microsoft/WSL2-Linux-Kernel --depth 1
$ cd WSL2-Linux-Kernel


menuconfigを開いてインストールするドライバを選択する。

$ make menuconfig KCONFIG_CONFIG=Microsoft/config-wsl


チェックは[M]ではなく[*]にするように注意してください。
(私は最初間違えて[M]で進めてしまい、デバイスファイルを表示できませんでした。)
スペースキーで[ ] [M] [*] 切り替え、Enter で選択します。




最後に→で移動して < Save > を選択。

$ make -j4 KCONFIG_CONFIG=Microsoft/config-wsl
$ sudo cp arch/x86/boot/bzImage /mnt/c/Users/[ユーザ名]/wsl_kernel
$ nano /mnt/c/Users/[ユーザ名]/.wslconfig
$ cat /mnt/c/Users/[ユーザ名]/.wslconfig
[wsl2]
kernel = C:\\Users\\[ユーザ名]\\wsl_kernel
$ history -a

Power Shell からシャットダウンします。これやったら最近のhistoryが消えてしまいました。
消したくない場合は history -a して.bash_historyにコマンド履歴を残しましょう。

Power Shell

PS > wsl --shutdown


CONFIG_USB_SERIAL_PL2303が有効になっていることを確認。

$ zcat /proc/config.gz | grep 2303
CONFIG_USB_SERIAL_PL2303=y

バイスファイルを確認。

$ dmesg | grep tty
[   45.330524] usb 1-1: pl2303 converter now attached to ttyUSB0
$ ll /dev/ttyU*
crw-rw-rw- 1 root dialout 188, 0  7月  7 23:25 /dev/ttyUSB0


2-3. ドライバに行き着く方法

私がどうやってドライバを入れる必要があると気付いたか、そしてどのドライバを入れる必要があるかわかったかというと、自宅にUbuntuを入れたPCがあるためです。
(そもそもそれならUbuntu機で環境構築しなさいよという話ではあるのですが......)

WSLでどうしてもデバイスファイルを表示できないため、Ubuntu機にUSBシリアルケーブルを繋いで様子を見ました。

lsusbにデバイスを表示でき、/dev/にデバイスファイルも表示できています。

$$ lsusb
(抜粋)
Bus 001 Device 005: ID 056e:5004 Elecom Co., Ltd UC-SGT

$$ ll /dev/ttyUSB*
crw-rw----   1 root dialout 188,     0  7月  7 01:50 ttyUSB0

dmesgを表示するとpl2303というドライバを使用していることがわかりました。

$$ sudo dmesg | grep usb
(抜粋)
[186993.823724] usb 1-5: new full-speed USB device number 4 using xhci_hcd
[186993.972598] usb 1-5: New USB device found, idVendor=056e, idProduct=5004, bcdDevice= 3.00
[186993.972604] usb 1-5: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[186993.972606] usb 1-5: Product: USB-Serial Controller
[186993.972608] usb 1-5: Manufacturer: Prolific Technology Inc.
[186994.053257] usbcore: registered new interface driver usbserial_generic
[186994.053270] usbserial: USB Serial support registered for generic
[186994.057230] usbcore: registered new interface driver pl2303
[186994.057248] usbserial: USB Serial support registered for pl2303
[186994.058394] usb 1-5: pl2303 converter now attached to ttyUSB0
[187112.762898] usb 1-5: USB disconnect, device number 4
[238693.541633] usb 1-5: new full-speed USB device number 5 using xhci_hcd
[238693.690784] usb 1-5: New USB device found, idVendor=056e, idProduct=5004, bcdDevice= 3.00
[238693.690804] usb 1-5: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[238693.690811] usb 1-5: Product: USB-Serial Controller
[238693.690817] usb 1-5: Manufacturer: Prolific Technology Inc.
[238693.696024] usb 1-5: pl2303 converter now attached to ttyUSB0

Ubuntu機がない場合はどうやって対応するドライバを見つけるのかというと、それは私にはわかりませんでした。
Elecom UC-SGT のドライバをググるWindows用のドライバの記事ばかり出てきます。
どうしても見つけられないなら、正解のUSBシリアルドライバを見つけられるまで手当たり次第にドライバをインストールして確認、正解のドライバ以外は後でアンインストールする、という策でもいいかもしれませんね。
それか、WSLでの環境構築は諦めてVMなどでやることになると思います。


2-4. USBシリアル関連の情報確認のためのコマンドなど(before/after)

USBシリアルのデバイスファイルを表示するために色々と探っていた時に試したことを紹介します。
バイスファイルを表示できる前後の比較をしました。


(1) $ brltty アンインストール

brlttyをアンインストールすると良いと書いている記事がありましたが、元々インストールされておらず空振りでした。

$ sudo apt autoremove brltty
(抜粋)
パッケージ 'brltty' はインストールされていないため削除もされません


(2) $ python3 -m serial.tools.list_ports -v

before

$ python3 -m serial.tools.list_ports -v
no ports found

after

$ python3 -m serial.tools.list_ports -v
/dev/ttyUSB0
    desc: USB-Serial Controller
    hwid: USB VID:PID=056E:5004 LOCATION=1-1
1 ports found


(3) $ usbip port

ドライバインストールの前後で出力に変化はありませんでした。

$ usbip port
Imported USB devices
====================
Port 00: <Port in Use> at Full Speed(12Mbps)
       Elecom Co., Ltd : UC-SGT (056e:5004)
       1-1 -> usbip://172.31.176.1:3240/2-2
           -> remote bus/dev 002/002

usbipのインストールに苦戦しました。
参考記事:WSL2のUbuntuにperfをインストールする #WSL2 - Qiita

当記事の記載順に実行されている場合は、2-2で既にWSL2-Linux-Kernelをクローンしていると思います。
usbipは以下のパスにあります。
WSL2-Linux-Kernel/tools/usb/usbip/

READMEに次の記載があります。

[Install]
0. Generate configuration scripts.
$ ./autogen.sh

1. Compile & install the userspace utilities.
$ ./configure [--with-tcp-wrappers=no] [--with-usbids-dir=

] $ make install 2. Compile & install USB/IP drivers.

記載の通りに ./autogen.sh, ./configure, make install を実行します。
途中でコマンドが足りなくてエラーが出る場合は足りないものをインストール、./cleanup.sh を実行して ./autogen.sh からやり直します。
私の環境では autoconf, automake, libtool, libudev-dev が足りなかったため、追加でインストールしました。


(4) $ setserial

ドライバインストール前は ttyS* を、インストール後は ttyUSB0 の結果を表示しています。

before

$ setserial -g /dev/ttyS*
/dev/ttyS0, UART: unknown, Port: 0x03f8, IRQ: 4
/dev/ttyS1, UART: unknown, Port: 0x02f8, IRQ: 3
/dev/ttyS2, UART: unknown, Port: 0x03e8, IRQ: 4
/dev/ttyS3, UART: unknown, Port: 0x02e8, IRQ: 3
$ setserial -a /dev/ttyS3
/dev/ttyS3, Line 3, UART: unknown, Port: 0x02e8, IRQ: 3
        Baud_base: 115200, close_delay: 50, divisor: 0
        closing_wait: 3000
        Flags: spd_normal

after

$ setserial -v /dev/ttyUSB0
/dev/ttyUSB0, UART: unknown, Port: 0x0000, IRQ: 0
$ setserial -a /dev/ttyUSB0
/dev/ttyUSB0, Line 0, UART: unknown, Port: 0x0000, IRQ: 0
        Baud_base: 0, close_delay: 50, divisor: 0
        closing_wait: 3000
        Flags: spd_normal


(5) $ lsusb -v

ドライバインストールの前後でMaxPowerだけ変化がありました。
before: MaxPower 500mA
after: MaxPower 100mA

ちなみにUbuntu機との差異はbmAttributesのみでした。
bmAttributes 0xa0
MaxPower 500mA

ドライバインストール後のコマンド実行結果は以下の通りです。

$ lsusb -v
(抜粋)
Bus 001 Device 002: ID 056e:5004 Elecom Co., Ltd UC-SGT
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x056e Elecom Co., Ltd
  idProduct          0x5004 UC-SGT
  bcdDevice            3.00
  iManufacturer           1 Prolific Technology Inc.
  iProduct                2 USB-Serial Controller
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x0027
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           3
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      0
      bInterfaceProtocol      0
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x000a  1x 10 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
Device Status:     0x0000
  (Bus Powered)


(6) ダウンロード済みドライバ(?)の確認

before

$  ls /lib/modules/5.15.153.1-microsoft-standard-WSL2/kernel/drivers/usb/serial/
ch341.ko  cp210x.ko  ftdi_sio.ko  usbserial.ko

after
/lib/modules/ 以下が消失。原因・解決方法不明。


2-5. デバイスファイルの表示に失敗した方法

成功例としている記事があるものの、私の環境ではデバイスファイルの表示ができなかった例を紹介します。

(1) 「Windows側の COM1 はWSL側の /dev/ttyS1 に対応」

私の環境では ttyS0,1,2,3 がデバイスファイルとして存在しますが、そのいずれを指定してもH8マイコンにデータを書き込むことはできませんでした。

$ ll /dev/ttyS*
crw-rw---- 1 root dialout 4, 64  7月  4 23:21 /dev/ttyS0
crw-rw---- 1 root dialout 4, 65  7月  4 23:21 /dev/ttyS1
crw-rw---- 1 root dialout 4, 66  7月  4 23:21 /dev/ttyS2
crw-rw---- 1 root dialout 4, 67  7月  4 23:21 /dev/ttyS3

出典:
2020年4月、Ubuntu18.04だったので古い情報だったようです。
WSLで「12ステップで作る組み込みOS自作入門」の環境構築をしてHello World!してみる - Toson blog


(2) /dev/ttyS* のパーミッション変更

/lib/udev/rules.d/50-udev-default.rules 内の

KERNEL=="tty[A-Z]*[0-9]|ttymxc[0-9]*|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout"

の末尾に

, MODE="0666"

をつけてパーミッション変更しようというもの。

実行したものの変化なしでした。

記事内で紹介されている記事には自らをdialoutグループに入れる手順も記載されていましたが、私の環境ではデフォルトでdialoutグループに入っていました。

出典:
2022年8月、Ubuntu16.04、WSLではなくVirtualBox
12ステップで作る組込みOS自作入門 環境構築 後編(2022年8月) #自作OS - Qiita

上記記事内で紹介されている記事:
Ubuntuでminicom起動すると/dev/ttyUSB0のパーミッションがないと言われる - kinneko@転職先募集中の日記


ちなみに以下のアクセス権変更も効果なしでした。

sudo chmod 666 /dev/ttyS0


(3) mknodコマンドで /dev/ttyUSB0 を作成
$ sudo mknod /dev/ttyUSB0 c 188 0

上記のコマンドでデバイスファイルを作成します。
参考記事には次のように記載されています。

標準状態でのパリティやボーレートの変更はsttyコマンドなどを使用してください。

しかし、やり方がわかりませんでした。

$ stty -F /dev/ttyUSB0
stty: /dev/ttyUSB0: そのようなデバイスやアドレスはありません

出典:
2010年8月
シリアルUSBアダプターをLinuxで使うには | 近藤科学



〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜

以上がUSBシリアル接続とデバイスファイルの表示までの確認でした。

次の記事ではSTEP1で Hello World を出力するまでを記載しようと思います。

次の記事:
hayariapp.hatenablog.com