Was kann man tun, wenn man den PL-R5 als USB-Gerät betreibt?Ethernet, serielle Kommunikation und Speicher über OTG

Einige industrielle Raspberry-Pi-Geräte wie der PL-R5 unterstützen USB OTG. Auch der in diesem Artikel verwendete PL-R5 ist OTG-fähig.

USB OTG (On-The-Go) ist eine Funktion, bei der ein einzelner USB-Port sowohl als Host als auch als Gerät fungieren kann.

Ein OTG-fähiger Port zeichnet sich dadurch aus, dass er seine Rolle je nach Situation wechseln kann.

  • USB-Ethernet-Adapter
  • USB-Serielle Schnittstelle
  • USB-Massenspeicher
  • Composite (Kombination mehrerer Funktionen)

Die Nutzung von USB OTG bei einem industriellen Raspberry Pi ermöglicht beispielsweise folgende Anwendungsfälle:

  • Durchführung der Erstkonfiguration über eine Verbindung mit einem PC
  • Zugriff über eine serielle Schnittstelle für Wartungszwecke
  • Nutzung zur Protokollierung (Logging)
  • Bereitstellung einer Web-basierten Verwaltungsoberfläche

Linux verfügt über einen Mechanismus namens USB Gadget Framework, sodass diese Funktionen standardmäßig unterstützt werden.

GadgetInhalt
g_etherUSB Ethernet
g_serialUSB-Serielle Schnittstelle
g_mass_storageUSB-Massenspeicher
g_hidTastatur und Maus
CompositeBereitstellung mehrerer Funktionen gleichzeitig

Unter Linux ist heute die Konfiguration von USB-Gadgets auf Basis von ConfigFS der Standard (Konfiguration unter /sys/kernel/config/usb_gadget/).

Einzelne Module wie g_ether können einfach verwendet werden, da sie vom Kernel automatisch geladen werden können. Allerdings ist es mit den g_-Modulen nicht möglich, mehrere Funktionen gleichzeitig zu konfigurieren.

Daher wird in der Praxis meist eine Composite-Konfiguration verwendet, auch wenn diese mehr Konfigurationsaufwand erfordert.

In diesem Artikel beginnen wir mit der Aktivierung von USB OTG und konfigurieren schließlich eine Composite-Konfiguration, bei der drei Funktionen gleichzeitig bereitgestellt werden.

Hinweise zum Zeitpunkt der Erstellung dieses Artikels

In dieser Umgebung wurde der industrielle Raspberry Pi „PL-R5“, basierend auf dem CM5, verwendet. Als Betriebssystem kam Raspberry Pi OS (Bookworm) zum Einsatz. Der Host-PC wurde unter Linux und macOS getestet.

Testumgebung

  • Modell: Industrieller Raspberry Pi „PL-R5“ (Raspberry Pi Compute Module 5 Rev 1.0)
  • OS: Debian GNU/Linux 12 (Bookworm)
  • Kernel: 6.12.62+rpt-rpi-v8
  • macOS: Tahoe 26.3

Wenn Windows als Host-PC verwendet wird, ist ein Treiber für RNDIS (Remote Network Driver Interface Specification) erforderlich, da ECM (Ethernet Control Model) nicht unterstützt wird.

Außerdem wird hier nicht im Detail darauf eingegangen, aber ab Raspberry Pi OS Trixie ist das Paket rpi-usb-gadget enthalten. Wenn dieses aktiviert wird, wird das Gerät automatisch als USB-Ethernet-Gerät erkannt, sodass eine SSH-Verbindung sofort möglich ist, ohne Wi-Fi oder kabelgebundenes LAN konfigurieren zu müssen.

Im Folgenden ein Zitat von der offiziellen Website:

“Starting with Raspberry Pi OS Trixie images dated 20.10.2025 or later, a new package called rpi-usb-gadget is included by default. Once activated, the Raspberry Pi presents itself as a USB Ethernet device, and you can connect via SSH immediately, without configuring Wi-Fi or Ethernet.”
https://www.raspberrypi.com/news/usb-gadget-mode-in-raspberry-pi-os-ssh-over-usb/

Auch wenn man allgemein von USB OTG spricht, gibt es verschiedene Methoden und Konfigurationsmöglichkeiten. Daher kann es zunächst etwas komplex erscheinen.

Wenn es jedoch nur um USB-Ethernet geht, wurde inzwischen ein Mechanismus hinzugefügt, der eine deutlich einfachere Einrichtung ermöglicht.

Vorbereitung: USB-OTG-Port in den Gerätemodus (Device-Modus) versetzen (manuell)

In diesem Abschnitt wird die USB-OTG-Konfiguration vollständig manuell durchgeführt.

Um den USB-2.0-OTG-Port des PL-R5 im Gerätemodus zu verwenden, muss der USB-Controller zunächst beim Systemstart im Peripheral-Modus aktiviert werden.

Da später drei Funktionen über eine Composite-Konfiguration mit ConfigFS eingerichtet werden, ist es erforderlich, die Datei cmdline.txt erneut zu bearbeiten. Bitte beachten Sie dies.

Fügen Sie die folgende Einstellung in /boot/firmware/config.txt hinzu:

dtoverlay=dwc2,dr_mode=peripheral

Da bei CM5-Systemen häufig dir_mode=host standardmäßig gesetzt ist, sollte die ursprüngliche Einstellung zunächst auskommentiert und anschließend die neue Konfiguration hinzugefügt werden.

[cm5]
#dtoverlay=dwc2,dr_mode=host
dtoverlay=dwc2,dr_mode=peripheral

Auch in der Datei /boot/firmware/cmdline.txt muss eine zusätzliche Einstellung vorgenommen werden.

Fügen Sie den folgenden Eintrag am Ende der Zeile hinzu, getrennt durch ein Leerzeichen.

Beachten Sie, dass cmdline.txt in einer einzigen Zeile geschrieben werden muss. Zeilenumbrüche sind nicht zulässig.

modules-load=dwc2

Nach einem Neustart wird der USB-OTG-Gerätemodus aktiviert.

USB Composite (Konfiguration mit ConfigFS)

Bei der Nutzung von USB OTG ist es in der Praxis sinnvoll, nicht nur eine einzelne Funktion zu konfigurieren, sondern beispielsweise Ethernet und serielle Kommunikation kombiniert zu verwenden.

Da mehrere Funktionen nicht gleichzeitig mit den g_-Modulen konfiguriert werden können, erfolgt die Konfiguration in diesem Fall über ConfigFS. Dies wird als USB Composite bezeichnet.

  • Einzelne Funktion (Ethernet / Serial / Mass Storage) → keine gleichzeitige Nutzung mehrerer Funktionen möglich, automatischer Start durch den Kernel (kein systemd erforderlich)
  • Kombinierte Funktionen (z. B. Mass Storage + Ethernet) → Konfiguration über ConfigFS + Erstellung eines systemd-Dienstes

Ein wichtiger Hinweis: Die gleichzeitige Verwendung von g_ether (und anderen g_-Modulen) zusammen mit einer ConfigFS-Konfiguration führt zu Konflikten. Verwenden Sie daher immer nur eine der beiden Methoden.

In diesem Beispiel wird eine Composite-Konfiguration verwendet, sodass Ethernet + Serial + Mass Storage gleichzeitig über ein einziges USB-Kabel bereitgestellt werden können.

Es ist auch möglich, einzelne Funktionen ausschließlich über ConfigFS zu konfigurieren.

Ein weiterer wichtiger Punkt: Wenn später Änderungen oder Erweiterungen vorgenommen werden, muss der aktivierte UDC zunächst deaktiviert und anschließend erneut aktiviert werden. Andernfalls kann es zu Fehlfunktionen kommen.

Dies ist auch während eines Tests einmal aufgetreten. Solche Probleme können entstehen, wenn die Schritte nicht korrekt ausgeführt werden.

In diesem Beispiel wird ein Skript verwendet, mit dem alle drei Funktionen in einem Schritt konfiguriert werden.

Konfiguration von USB Composite

Fügen Sie zunächst die folgende Einstellung in die zuvor bearbeitete Datei /boot/firmware/cmdline.txt hinzu.

Starten Sie anschließend das System neu, um die Änderungen zu aktivieren.

modules-load=dwc2,libcomposite

Nachdem libcomposite geladen wurde, werden die erforderlichen Konfigurationsdateien unter /sys/kernel/config/usb_gadget/ erstellt.

In diesem Beispiel wurde ein Verzeichnis mit dem Namen CM5 erstellt. Der Name ist frei wählbar, sollte jedoch konsistent mit den anderen Einstellungen verwendet werden.

Wenn Sie unter diesem Verzeichnis weitere Unterverzeichnisse erstellen, werden automatisch die entsprechenden Dateien wie folgt angelegt.

UDC           bDeviceProtocol  bMaxPacketSize0  bcdUSB   functions  idVendor   os_desc  webusb
bDeviceClass  bDeviceSubClass  bcdDevice        configs  idProduct  max_speed  strings

Diese Dateien werden nun entsprechend angepasst.

Beispiel für die Konfiguration von usb_gadget

Im Folgenden wird die Konfiguration des USB-Gadgets beschrieben, das verbunden werden soll.
Zunächst zeigen wir die Einstellungen, die in diesem Beispiel verwendet werden.

Später werden diese Einstellungen gesammelt als Skript ausgeführt, hier erläutern wir jedoch zunächst Schritt für Schritt, welche Angaben jeweils vorgenommen werden.

echo 0x1d6b | sudo tee idVendor      # Linux Foundation
echo 0x0104 | sudo tee idProduct     # Multifunktionales Composite-Gerät
echo 0x0100 | sudo tee bcdDevice     # Geräterevisionsnummer v1.0.0
echo 0x0200 | sudo tee bcdUSB        # USB 2.0

sudo mkdir strings/0x409             # en-US (englische Spracheinstellungen)
echo "0001" | sudo tee strings/0x409/serialnumber
echo "RaspberryPi" | sudo tee strings/0x409/manufacturer
echo "CM5 Composite" | sudo tee strings/0x409/product

Zunächst wird libcomposite mit sudo modprobe libcomposite geladen. Dieser Schritt sollte vorsorglich einmal vor dem Erstellen und Ausführen des Skripts durchgeführt werden.

Die Vendor-ID und Product-ID werden normalerweise von den jeweiligen Herstellern festgelegt. In diesem Fall wurden zu Testzwecken jedoch die Vendor-ID der Linux Foundation sowie die Product-ID für ein Multifunction Composite verwendet.
Der Wert bcdDevice gibt die Versionsnummer an (hier v1.0.0), und bcdUSB wurde auf den Wert für USB 2.0 gesetzt.

Außerdem gibt strings/0x409 die Spracheinstellung für Englisch (en-US) an. Die Werte für serialnumber, manufacturer und product sind frei wählbar, sollten jedoch möglichst verständlich gewählt werden.

Insbesondere der product-Name wird auf der Host-Seite angezeigt, daher empfiehlt sich eine klare und aussagekräftige Bezeichnung.

Auf Grundlage dieser Überlegungen wurden die entsprechenden Einstellungen im Skript festgelegt.

Skriptdatei für die Composite-Konfiguration

Skriptdatei für die Composite-Konfiguration

Im Folgenden wird ein Skript vorgestellt, mit dem für den CM5 ein zusammengesetztes USB-Gadget (ECM + ACM + Mass Storage) in einem Schritt konfiguriert werden kann.

Voraussetzungen:
dwc2 und libcomposite sind bereits über config.txt und cmdline.txt geladen.

Der grundlegende Ablauf des Skripts ist wie folgt:

  • UDC deaktivieren
  • Gadget erstellen
  • ECM / ACM / Mass Storage anlegen
  • Mit der Konfiguration verknüpfen
  • UDC erneut binden
  • USB-Ethernet konfigurieren

cm5-usb-gadget.sh

#!/bin/bash
set -euo pipefail

G=/sys/kernel/config/usb_gadget/cm5
UDC_DEV=$(ls /sys/class/udc | head -n 1)
[ -z "$UDC_DEV" ] && exit 1

# Vorhandene Konfiguration entfernen (für erneute Ausführung)
if [ -d "$G" ]; then
    echo "" > "$G/UDC" || true
    rm -rf "$G"
fi

mkdir -p "$G"
cd "$G"

# ===== Gerätebeschreibung (Device Descriptor) =====
echo 0x1d6b > idVendor      # Linux Foundation
echo 0x0104 > idProduct     # Multifunktionales Composite-Gadget
echo 0x0200 > bcdUSB
echo 0x0100 > bcdDevice

mkdir -p strings/0x409
echo "0123456789" > strings/0x409/serialnumber
echo "Raspberry Pi" > strings/0x409/manufacturer
echo "CM5 USB Gadget" > strings/0x409/product

# ===== Konfiguration =====
mkdir -p configs/c.1
mkdir -p configs/c.1/strings/0x409
echo "ECM + ACM + MassStorage" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower

# ===== ECM (USB-Ethernet) =====
mkdir -p functions/ecm.usb0
echo "02:00:00:00:00:01" > functions/ecm.usb0/dev_addr
echo "02:00:00:00:00:02" > functions/ecm.usb0/host_addr
ln -s functions/ecm.usb0 configs/c.1/

# ===== ACM (USB-Seriell) =====
mkdir -p functions/acm.usb0
ln -s functions/acm.usb0 configs/c.1/

# ===== Massenspeicher =====
IMG="/opt/usb/piusb.bin"
LABEL="CM5USB"
mkdir -p /opt/usb

if [ ! -f "$IMG" ]; then
    dd if=/dev/zero of="$IMG" bs=1M count=128
    mkfs.vfat -n "$LABEL" "$IMG"
fi

fatlabel "$IMG" "$LABEL" || true

mkdir -p functions/mass_storage.usb0
echo 1 > functions/mass_storage.usb0/stall
echo 0 > functions/mass_storage.usb0/lun.0/removable
echo 0 > functions/mass_storage.usb0/lun.0/ro
echo "$IMG" > functions/mass_storage.usb0/lun.0/file
ln -s functions/mass_storage.usb0 configs/c.1/

# ===== Binden (UDC aktivieren) =====
echo "$UDC_DEV" > UDC

# ====== Feste IP-Konfiguration für USB-Ethernet ======
sleep 1

if ip link show usb0 >/dev/null 2>&1; then
    ip addr flush dev usb0 || true
    ip addr add 192.168.7.2/24 dev usb0 || true
    ip link set usb0 up || true
fi

Je nach Umgebung können einige Details variieren, jedoch sollte diese Konfiguration in der Regel problemlos funktionieren.

In diesem Beispiel wird zu Beginn eine „Bereinigung vorhandener Einstellungen (für erneute Ausführung)“ durchgeführt.
Der Grund dafür ist, dass das Skript bei jedem Systemstart ausgeführt wird. Selbst wenn einzelne Konfigurationswerte geändert und das System neu gestartet wird, wird sichergestellt, dass die Änderungen korrekt übernommen werden.

Im Abschnitt Mass Storage werden der Speicherort und der Name der Image-Datei sowie ein Label festgelegt, das beim Verbinden angezeigt wird, um die Identifikation zu erleichtern.

Wenn Sie diese Angaben anpassen möchten, können Sie die entsprechenden Werte an dieser Stelle beliebig ändern.

IMG="/opt/usb/piusb.bin"
LABEL="CM5USB"

Im Abschnitt Bind wird der UDC durch das Schreiben des Werts mit
echo $UDC_DEV > UDC aktiviert.

Abschließend wurde eine feste IP-Adresse konfiguriert.
Es ist zwar auch möglich, keine feste IP zu setzen, jedoch kann dies zu Unklarheiten führen, weshalb hier bewusst eine statische Adresse verwendet wird (ansonsten wird typischerweise ein Bereich wie 169.254.x.x/16 verwendet).

Da USB-Ethernet als unabhängiges Netzwerk betrieben werden soll, ist es erforderlich, einen anderen dritten Oktettwert als im Heimnetzwerk zu wählen.

Das Netzwerk 192.168.7.0/24 ist in der Praxis geeignet, da es sich nur selten mit typischen Heimnetzwerken überschneidet.

192.168.7.1  # Host-PC
192.168.7.2  # Raspberry Pi

Zusätzlich wird im Zuge der statischen IP-Konfiguration auch das Interface usb0 aktiviert (up), sodass zwei Schritte gleichzeitig erledigt werden.

Nach dem Erstellen des Skripts sollten Sie die Ausführungsberechtigung vergeben.

sudo chmod +x /usr/local/sbin/cm5-usb-gadget.sh

Als systemd-Dienst einrichten (Autostart aktivieren)

Erstellen Sie einen Dienst, damit die Konfiguration automatisch angewendet wird.

sudo nano /etc/systemd/system/cm5-usb-gadget.service

[Unit]
Description=CM5 USB Composite Gadget
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/cm5-usb-gadget.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Diese Konfiguration wird als oneshot-Service ausgeführt, sodass cm5-usb-gadget.sh beim Systemstart nur einmal ausgeführt wird.
Das bedeutet, dass configfs bei jedem Start neu aufgebaut wird.

Wie bereits erwähnt, reicht ein Neustart aus, wenn Sie Änderungen an der USB-OTG-Konfiguration vornehmen und diese aktivieren möchten.
Dies ist möglich, da zu Beginn des Skripts der UDC deaktiviert wird.

Durch die Option RemainAfterExit=yes bleibt der Dienst im Zustand active (exited), was für konfigurationsbasierte Dienste sinnvoll ist, die ihren Zustand beibehalten sollen. Es handelt sich jedoch nicht um einen dauerhaft laufenden Dienst.

Vergessen Sie abschließend nicht, den erstellten Dienst zu aktivieren (enable).
Ein manuelles start ist hier nicht erforderlich, da das Skript automatisch ausgeführt wird.

sudo systemctl enable cm5-usb-gadget.service

Nach einem Neustart wird USB OTG mit den drei aktivierten Funktionen ausgeführt.

Nützliche Hinweise für den Einzelbetrieb

Im Folgenden werden einige Methoden aufgeführt, die in der Praxis hilfreich sein können.

UDC deaktivieren / aktivieren

Der bereits mehrfach erwähnte UDC ist zunächst eine leere Datei ohne Inhalt.
Bei der ConfigFS-Methode wird der UDC erst aktiv, nachdem der Gerätename des eigenen UDC (z. B. 1000480000.usb) in die entsprechende Datei geschrieben wurde.

Daher sollte dieser Wert bei jeder Änderung oder Erweiterung der Konfiguration erneut geschrieben werden.
Ist der UDC jedoch bereits aktiv, muss er zunächst deaktiviert (Wert löschen) und anschließend erneut aktiviert werden.

Da es bei diesem Vorgang zu Problemen kommen kann, werden hier die entsprechenden Befehle für die manuelle Ausführung aufgeführt.

Verwenden Sie dabei den UDC-Namen, der mit folgendem Befehl angezeigt wird (z. B. 1000480000.usb):

ls /sys/class/udc

Befehl zum Schreiben des Werts:

echo "1000480000.usb" | sudo tee /sys/kernel/config/usb_gadget/cm5/UDC > /dev/null

Beim Deaktivieren des UDC wird der aktuell gesetzte Wert gelöscht und die Datei geleert.

Wenn Änderungen vorgenommen werden, beispielsweise durch das Hinzufügen neuer Funktionen zum UDC, muss dieser ebenfalls zunächst geleert, anschließend neu konfiguriert und danach wieder aktiviert werden.。

Befehl zum Leeren des Werts:

echo "" | sudo tee /sys/kernel/config/usb_gadget/cm5/UDC > /dev/null

Nachdem der UDC deaktiviert und die einzelnen Funktionen angepasst wurden, wird er wie zuvor erneut aktiviert.

Beachten Sie, dass die einzelnen Funktionen anhand des Skripts konfiguriert werden müssen, indem die entsprechenden Befehle ausgeführt werden.

echo "1000480000.usb" | sudo tee /sys/kernel/config/usb_gadget/cm5/UDC > /dev/null

Fehlersuche

Eine ausführliche Erklärung wird hier ausgelassen, jedoch werden einige Befehle aufgeführt, die bei Problemen hilfreich sein können.

journalctl -u cm5-usb-gadget.service

Befehle zur Analyse der Kommunikation
Alle Befehle werden auf der Pi-Seite ausgeführt.

ip route
ip route | grep usb0
ip addr show usb0
cat /sys/class/net/usb0/carrier
ip link show
systemctl status cm5-usb-gadget.service
nmcli dev status

Einzelfunktion vs. Composite-Funktion

Wenn nur eine einzelne Funktion benötigt wird, sind die hier nicht näher behandelten Module wie g_ether oder g_serial am einfachsten zu verwenden.

Wenn jedoch detailliertere Einstellungen erforderlich sind oder mehrere Funktionen gleichzeitig genutzt werden sollen, empfiehlt sich die Konfiguration über die ConfigFS-Methode.

Da dabei mehrere Einstellungen erforderlich sind, kann die manuelle Konfiguration etwas aufwendig sein.

Ein Skript ist hier besonders praktisch: Es muss nur einmal erstellt werden, reduziert den Aufwand und erleichtert durch seine Übersichtlichkeit die Verwaltung.

Wenn Sie USB OTG schnell ausprobieren möchten, können Sie einfach das Skript kopieren und verwenden.


Gastbeitrag: Raspida

Betreiber der Raspberry-Pi-Informationsseite raspida.com, die sowohl für Nicht-Ingenieure als auch für Einsteiger verständlich und interessant ist.

Basierend auf langjähriger Erfahrung mit dem Raspberry Pi werden zahlreiche hilfreiche Informationen und Themen sowohl für erfahrene Nutzer als auch für Interessierte bereitgestellt.

Für die PiLink-Website werden technische Blogartikel zum Thema industrieller Raspberry Pi beigetragen.