Linux USB Gadget シリアル接続を Raspberry pi で使う備忘録

Gadget
Photo by hyt.

Linux の USB Gadget シリアル接続を Raspberry pi で使う備忘録です.

動作確認したデバイスとOS

動作することを確認した環境は以下の通りですが,USB Gadget に対応した SBC なら恐らく動くと思います.

  • DEVICE: Raspberry pi4
  • OS: Raspberry pi OS (64bit)
Bitly

Raspberry pi OS への書き込みは Raspberry pi OS imager for Linux を使ったのですが,さいきんの ver. だと,Media Player OS の一つとして Volumio とか moOde audio player とかも選べるんですね.なお,導入後の最低限の設定(アップデートなど)については,

【2024年最新版】OSインストールから初期設定まで|ラズベリーパイ セットアップ手順のすべて | sozorablog
ラズベリーパイOSをインストールしたい方は必見!この記事ではOSのインストールから初期設定方法までを知ることができます。実はOSの仕様が2022年4月に変更されました。この記事を読めば最新の設定方法がわかります。

辺りをご覧ください.

Linux Gadget USB CDC-ACM の有効化

過ネールモジュール g_serial.ko を読み込んで有効化する方法もあるのですが,今回は将来的に拡張性を持たせるため Multifunction Composite Gadget として有効化します.

まず,行わなければならないのは USB gadget の有効化とカーネルモジュールの読み込みです./boot/config.txt と /etc/modules に以下を追加します.

$ sudo vi /boot/config.txt
....
# Enable DWC2 USB Driver
dtoverlay=dwc2
....
$ sudo vi /etc/modules
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
dwc2
libcomposite
....

次に /sys/kernel/config/usb_gadget 以下に USB CDC-ACM の設定を書き込み,有効化します.この部分の詳しい解説は,

Linux USB gadget configured through configfs — The Linux Kernel documentation

やその周辺の資料をご覧ください.なお,今回はこの部分を on.CDC-ACM-gadget というファイル名のシェルスクリプトとしています.

$ sudo vi /usr/local/bin/on.CDC-ACM-gadget
#!/bin/sh

cd /sys/kernel/config/usb_gadget
/usr/bin/mkdir g1
cd g1
/bin/echo 0x1d6b > idVendor
/bin/echo 0x0104 > idProduct
/usr/bin/mkdir strings/0x409
/bin/echo "23081301"> strings/0x409/serialnumber
/bin/echo "Labohyt" > strings/0x409/manufacturer
/bin/echo "CDC-ACM Gadget" > strings/0x409/product
/usr/bin/mkdir configs/c.1
/usr/bin/mkdir configs/c.1/strings/0x409
/usr/bin/mkdir functions/acm.GS0
/usr/bin/ln -s functions/acm.GS0 configs/c.1/
/usr/bin/ls /sys/class/udc > UDC

$ sudo chmod +x /usr/local/bin/on.CDC-ACM-gadget

このシェルスクリプトを実行すれば Raspberry pi OS に /dev/ttyGS0 が現れるはずです.

$ ls -alF /dev/ttyGS0 
crw------- 1 hyt tty 236, 0 Aug 14 10:48 /dev/ttyGS0

また,適当なPCとRaspberry pi4のUSB-Cポートを接続すると,Linux Foundation Multifunction Composite Gadget というデバイスが出来ます.なお,PCのOSが Linux の場合は,/dev/ttyACM0 というデバイスが新たに現れるはずです.以下は私の使っている elementary os 7 (ubuntu 22.04) での認識の様子です.

$ lsusb
...
Bus 001 Device 046: ID 1d6b:0104 Linux Foundation Multifunction Composite Gadget
...

$ ls -alF /dev/ttyACM0
crw-rw---- 1 root dialout 166, 0  8月 14 11:04 /dev/ttyACM0

この段階では単にシリアル通信ができるだけの状態で,Raspberry pi OS のシェルにアクセス(ログイン)はできません.シリアル通信が正常に行えるかどうかを試したい場合は,minicom を Raspberry pi OS 側は /dev/ttyGS0 に接続し,PC側から適当なシリアル通信に対応したターミナル(Windows なら TeraTerem など)を使って接続してみてください.また,詳細については以下をご覧ください.

Linux Gadget Serial Driver v2.0 — The Linux Kernel documentation

なお,いくつかの Linux 用のターミナルの使い方のヒントをこの記事の後半に記しています.

agetty の設定

前の節に記したとおり,単に USB CDC-ACM を有効化しただけではシェルにアクセスできません.Linux の場合,ログインプロンプトの表示やシェルの起動は getty 系のプログラムで行われますが,今回はその実装の一つである agetty を使います.

と言っても,実は Raspberry pi OS の場合は,systemd を使ってこれを以下のように簡単に設定できます.

$ sudo systemctl enable [email protected]
$ sudo systemctl start

ただし,このままだと再起動すると USB CDC-ACM が有効になっていないことから,依存関係のエラーでサービスが起動してきてくれません.このため,再起動したら自動的に USB CDC-ACM が有効化されるよう /etc/rc.local に以下の記述を付け加えます.

$ sudo vi /etc/rc.local
.....
/usr/local/bin/on.CDC-ACM-gadget

exit 0

よりスマートな方法として,systemd の ExecStartPre の利用も試してみましたが,/etc/ttyGS0 がない場合は ExecStartPre に記したコマンドが実行されないようで,結果的に USB CDC-ACM が自動的に有効になってくれません.仕方ないので rc.local を使っていますが,最初の接続にかなり時間がかかったり,接続はされるがなぜかいつまでたってもプロンプトが出てこなかったりすることがあるので,どなたかより良い方法をご存知の方がおられたらコメントして頂けると助かります.

デフォルトの systemd の設定だと login と password を聞いてきますが,これが面倒な場合は,

$ sudo systemctl edit [email protected]
### Editing /etc/systemd/system/[email protected]/override.conf
### Anything between here and the comment below will become the new contents of the file

[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin hyt


 --keep-baud 115200,57600,38400,9600 %I $TERM

.....

のようにしてください.なお,systemctl edit についてのわかり易い解説は,

辺りをご覧いただければと思います.また,上を見ると ExeStart の後ろに実行するものを何も記していない行がありますが,このように記さないとなぜかうまく行きません.この部分についてもなぜなのかご存知のかたがおられましたらコメントに記していただければと思います.

Linux でシリアル接続する備忘録

最後に Linux でシリアル接続するときに覚えておかないといけない(覚えておいた方が良い)ことをいくつか記しておきます.

まず,上記の設定をしただけだと,Linux 系の PC から接続するときにルート権限が必要になってしまいます.一般ユーザー権限で接続したい場合は,

$ sudo gpasswd -a $USER dialout

として dialout グループにユーザーを追加する必要があります.

次に Linux でシリアル接続するアプリは調べてみると,

  • minicom
  • cu
  • screen

などがあるようです(Ubuntu だとどれも apt で入ります).このうち,多分最も高機能なのが minicom ですが,使い方に癖があり個人的にはかなり使いにくいです.また,screen も同様です(screen は有名なターミナルマルチプレクサですが,私の場合は tmux に慣れてしまったのでいまさら使い方覚える気はない).ということで,結局 cu を普通は使うことが多いのですが,動作確認などのために,以下簡単な使い方を示しておきます.

minicom

  • minicom -s で起動すると設定画面が出てくる
  • メニューから Serial port setup を選び /dev/ttyACM0 を入力
  • Exit を選びしばらく待つと接続
  • 終了したい場合は CTRL + a のあとに z, x の順で選択
### minicom の設定
$ LANG=C minicom -s

# minicom の設定メニュー

            ┌─────[configuration]──────┐
            │ Filenames and paths      │
            │ File transfer protocols  │
            │ Serial port setup        │
            │ Modem and dialing        │
            │ Screen and keyboard      │
            │ Save setup as dfl        │
            │ Save setup as..          │
            │ Exit                     │
            │ Exit from Minicom        │
            └──────────────────────────┘

### minicom の Serial port setup のメニュー
    ┌───────────────────────────────────────────────────────────────────────┐
    │ A -    Serial Device      : /dev/ttyACM0                              │
    │ B - Lockfile Location     : /var/lock                                 │
    │ C -   Callin Program      :                                           │
    │ D -  Callout Program      :                                           │
    │ E -    Bps/Par/Bits       : 115200 8N1                                │
    │ F - Hardware Flow Control : Yes                                       │
    │ G - Software Flow Control : No                                        │
    │ H -     RS485 Enable      : No                                        │
    │ I -   RS485 Rts On Send   : No                                        │
    │ J -  RS485 Rts After Send : No                                        │
    │ K -  RS485 Rx During Tx   : No                                        │
    │ L -  RS485 Terminate Bus  : No                                        │
    │ M - RS485 Delay Rts Before: 0                                         │
    │ N - RS485 Delay Rts After : 0                                         │
    │                                                                       │
    │    Change which setting?                                              │
    └───────────────────────────────────────────────────────────────────────┘

### minicom でシリアル接続直後の様子
Welcome to minicom 2.8

OPTIONS: I18n                                                                
Port /dev/ttyACM0, 11:54:55                                                  
                                                                             
Press CTRL-A Z for help on special keys                                      
                                                                             
Linux rbp41 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr  3 17:24:16 BST 2023 aarch64
                                                                             
The programs included with the Debian GNU/Linux system are free software;    
the exact distribution terms for each program are described in the           
individual files in /usr/share/doc/*/copyright.                              
                                                                             
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent            
permitted by applicable law.                                                 
Last login: Mon Aug 14 11:33:06 JST 2023 on ttyGS0                           
hyt@rbp41:~$

### minicom で CTRL+a のあとに z を入力した様子
### コピーして適当なターミナルに貼り付けてみてください
Welcome to minicom 2.8  ┌───────────────────────────────────────────────────────────────────┐
                        │                      Minicom Command Summary                      │
OPTIONS: I18n           │                                                                   │
Port /dev/ttyACM0, 11:54│              Commands can be called by CTRL-A <key>               │
                        │                                                                   │
Press CTRL-A Z for help │               Main Functions                  Other Functions     │
                        │                                                                   │
Linux rbp41 6.1.21-v8+ #│ Dialing directory..D  run script (Go)....G | Clear Screen.......C │
                        │ Send files.........S  Receive files......R | cOnfigure Minicom..O │
The programs included wi│ comm Parameters....P  Add linefeed.......A | Suspend minicom....J │
the exact distribution t│ Capture on/off.....L  Hangup.............H | eXit and reset.....X │
individual files in /usr│ send break.........F  initialize Modem...M | Quit with no reset.Q │
                        │ Terminal settings..T  run Kermit.........K | Cursor key mode....I │
Debian GNU/Linux comes w│ lineWrap on/off....W  local Echo on/off..E | Help screen........Z │
permitted by applicable │ Paste file.........Y  Timestamp toggle...N | scroll Back........B │
Last login: Mon Aug 14 1│ Add Carriage Ret...U                                              │
hyt@rbp41:~$     │                                                                   │
                        │             Select function or press Enter for none.              │
                        └───────────────────────────────────────────────────────────────────┘

cu

  • cu -s 9600 -l /dev/ttyACM0 で接続できます.
### cu で実際に接続してみた様子
$ cu -s 115200 -l /dev/ttyACM0
Connected.

hyt@rbp41:~$

screen

  • screen /dev/ttyACM0 9600 で接続できます.
  • CTRL + a のあとに k と入力

以上!

タイトルとURLをコピーしました