書籍『12ステップで作る 組込みOS自作入門』をWSL2で環境構築しようとしたところ、詰まったところがいくつかあったので手順を書き残しておこうと思います。
以下は2年ほど前にVirtualBoxを使って環境構築をした際の記事ですが、全く同じコマンドでできた訳ではありませんでした。
今回は特にUSBシリアルの認識に手こずりました。
hayariapp.hatenablog.com
長くなったため、記事を2つに分けました。
この記事ではUSBシリアルを認識させてデバイスファイル(/dev/ttyUSB0)を表示するまで、
次の記事で binutilsやgccのインストールから Hello World を出力するまでを扱いたいと思います。
次の記事:
hayariapp.hatenablog.com
目次
- 環境
- 1. USBシリアルをWindowsから認識させる
- 2. USBシリアルをWSLから認識させる
環境
- Windows11 Pro
- WSL2
- USB to シリアルケーブル
- ELECOM UC-SGT1 [ ELECOM USBtoシリアルケーブル モデム用 USBオス-RS-232C用 UC-SGT1 ]
- (2021年11月に1827円で購入しましたが、2024年7月現在で4280円になっています。高すぎますね...)
- ELECOM UC-SGT1 [ ELECOM USBtoシリアルケーブル モデム用 USBオス-RS-232C用 UC-SGT1 ]
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.sh1. 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