Generated with Claude Opus 5 (Claude Code), September 2026. Verify commands against your own hardware and campus policy before relying on them.
This is relevant because some high ranking pages will suggest using USB gadget mode.
The Pi 3 B+ is one of the models that physically cannot do gadget mode. Its micro-USB port is
wired to the power input only, and the SoC’s OTG-capable USB port is hard-wired to the LAN7515
hub/Ethernet chip, which strips OTG and leaves the board host-only. The dwc2/g_ether steps in
the Raspberry Pi USB gadget mode article
apply to the Zero, Zero 2 W, Pi 4, Pi 5, Pi 400, and CM4 — boards with a data-capable USB-C or
micro-USB port. No amount of config.txt editing will make a 3 B+ enumerate as a device.
So the answer isn’t “USB gadget mode,” it’s “something else over the USB port you already have.”
The Lab 1 kit already issues exactly the hardware for this — the Trendnet USB 2.0 Ethernet adapter (or similar device such as Realtek USB GbE) and an ethernet patch cable. From the laptop’s point of view this is a USB connection; the laptop has no built-in NIC, so the adapter is the port. The Pi 3 B+’s Ethernet is Auto-MDIX, so a straight patch cable works — no crossover needed, no switch, no Wi-Fi.
Which adapter, on which machine. Two show up in this course and they are not interchangeable for these purposes:
| Adapter | Used by | Notes |
|---|---|---|
| Realtek USB GbE | instructor demos | RTL8153 class. In-box drivers on both Windows 11 and macOS, Apple Silicon included. This is the one to use from a MacBook. |
| Trendnet USB 2.0 10/100 | students | ASIX AX88772 class. Fine on Windows, which carries an in-box driver. Do not assume it works on macOS — that generation is not covered in-box on Apple Silicon and wants an ASIX DriverKit package. |
Since the student labs run on Windows laptops with the Trendnet, and the Mac path is an instructor demo with the Realtek, that split is normally invisible. It only matters if someone tries to run the Mac instructions with a student’s Trendnet adapter, which is worth knowing before standing in front of a class.
On an Apple Silicon MacBook there are no USB-A ports either way, so a USB-A dongle needs a USB-C
adapter or hub in front of it; a native USB-C Gigabit adapter is tidier. Confirm the adapter
enumerated, and learn its BSD name (en5, en6, …) and its exact port name:
networksetup -listallhardwareports
If the adapter never appears there, its chipset wants a third-party kext — and on Apple Silicon that means lowering Startup Security, which is not worth doing for a demo. Borrow the Realtek instead.
ICS gives the Pi a real DHCP lease and internet through the laptop’s Wi-Fi (handy for apt
during a demo):
ncpa.cpl → right-click Wi-Fi → Properties → Sharing tab → check
Allow other network users to connect… and pick the USB Ethernet adapter below it.192.168.137.1/24 and runs a DHCP server on it. The Pi picks up
192.168.137.x in about 30 s.arp -a -N 192.168.137.1 to see the lease, or just
ssh pi@<your-hostname>.local — Windows 11 resolves mDNS natively and the Imager set that
hostname.Bonus for the labs: since the VM is already bridged to the USB Ethernet adapter (Lab 1, Figure 3),
the VM lands on the same 192.168.137.0/24 and can reach the Pi for scp/gdbserver without
changing anything.
On an MSOE-managed laptop this step usually fails with that message, even from an elevated
ncpa.cpl. It is not an ACL problem, so elevating does not help. The cause is a domain Group
Policy:
HKLM\SOFTWARE\Policies\Microsoft\Windows\Network Connections
NC_ShowSharedAccessUI = 0
That is Prohibit use of Internet Connection Sharing on your DNS domain network. The Sharing tab still renders, but the enable call is refused.
To confirm this is what you are hitting (the other ICS prerequisites — SharedAccess, MpsSvc,
BFE, Netman — should all be running):
Get-Service SharedAccess,MpsSvc,BFE,Netman | Select-Object Name,Status,StartType
Get-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Network Connections'
From an administrative PowerShell prompt:
Set-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Network Connections' -Name NC_ShowSharedAccessUI -Value 1
Restart-Service SharedAccess
Then reopen ncpa.cpl and enable sharing again. To put it back:
Set-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Network Connections' `
-Name NC_ShowSharedAccessUI -Value 0
This is a temporary override. The value is pushed by domain Group Policy and will be rewritten
at the next policy refresh — background refresh runs roughly every 90 minutes, and always at reboot
or on gpupdate /force. This can reset at any time, and it appears MSOE
laptops do not allow this setting.
No ICS, no policy exception, no DHCP, no mDNS. This is the one to rely on in front of a class.
Attach the USB ethernet adapter with cable and a second USB cable from the laptop to the micro-USB connector on the Pi. Let the operating system boot.
On the laptop, in an administrative PowerShell prompt (substitute the adapter’s own name — check
Get-NetAdapter; it shows up as something like Ethernet 7 for a Realtek USB GbE dongle):
Set-NetConnectionProfile -InterfaceAlias "Ethernet 7" -NetworkCategory Private
New-NetIPAddress -InterfaceAlias "Ethernet 7" -IPAddress 192.168.50.1 -PrefixLength 24
Setting the profile to Private is not just tidiness: a fresh USB adapter lands in Public, where
the firewall drops inbound mDNS, and that is what breaks <hostname>.local resolution.
On the Pi — do this while it is still on the classroom network, so you do not lock yourself out:
sudo nmcli con mod "Wired connection 1" +ipv4.addresses 192.168.50.2/24
sudo nmcli con up "Wired connection 1"
Using +ipv4.addresses instead of ipv4.method manual keeps DHCP working and adds the fixed
address, so the Pi answers at 192.168.50.2 on any network — including a bare cable to the laptop —
while still behaving normally on classroom Ethernet. Nothing to reconfigure between the two. If the
Pi is not reachable to set this up, use the serial console below.
To undo the laptop side:
Remove-NetIPAddress -InterfaceAlias "Ethernet 7" -IPAddress 192.168.50.1 -Confirm:$false
Set-NetIPInterface -InterfaceAlias "Ethernet 7" -Dhcp Enabled
This assumes you are using a Mac (with administrative status) that is not managed by MSOE.
networksetup -listallhardwareports).macOS puts the adapter on 192.168.2.1/24 and runs bootpd as a DHCP server on it, so the Pi
picks up a 192.168.2.x lease in about 30 seconds. Note the subnet differs from the Windows ICS
192.168.137.x — if you have written 192.168.137.2 on a sticky note, it does not apply here.
Finding the Pi is genuinely easier than on Windows, because Bonjour is native rather than bolted on:
ssh pi@<your-hostname>.local # hostname you set in the Imager
dns-sd -B _ssh._tcp # or browse for it
arp -an | grep 192.168.2 # or read the lease table
Recent macOS gates LAN access per application. If ssh to a .local name or a 192.168.2.x
address hangs and then times out — with no error that explains itself — the terminal app has not
been granted access. Go to System Settings → Privacy & Security → Local Network and enable
Terminal (or iTerm, or VS Code if you are sshing from its integrated terminal). The first
attempt normally raises the prompt itself, but it is easy to dismiss by reflex and then spend
twenty minutes blaming the cable.
Same reasoning as the Windows static setup — no DHCP, no mDNS, nothing to fail in front of a class.
Use the exact port name from networksetup -listallhardwareports, quoted:
sudo networksetup -setmanual "USB 10/100/1000 LAN" 192.168.50.1 255.255.255.0
Leave the router/gateway field empty; there is nothing to route to. The GUI equivalent is System Settings → Network → [the adapter] → Details… → TCP/IP → Configure IPv4: Manually.
To undo:
sudo networksetup -setdhcp "USB 10/100/1000 LAN"
The Pi side is identical to the Windows case — the nmcli command above is what it is regardless of
what is on the other end of the cable.
Over a static point-to-point link the Pi cannot reach the outside world, so apt will not work
during a demo. (macOS Internet Sharing does not have this problem — it NATs for you.) New-NetNat -Name PiNat -InternalIPInterfaceAddressPrefix 192.168.50.0/24 is the
WinNAT equivalent and is not covered by the ICS policy — but Windows permits only one NAT
instance and the Hyper-V Default Switch already holds one, so it may refuse. Simplest is to do
package installs on classroom Ethernet beforehand.
Worth having in the bag regardless — it works with no networking at all, which is what you want when the demo is about the network being broken.
bootfs partition in Windows, add enable_uart=1
to config.txt. (cmdline.txt already has console=serial0,115200.) On the Pi 3 this matters
because the good PL011 UART is assigned to Bluetooth and the mini-UART’s clock follows the core
frequency — enable_uart=1 pins it.Plug the cable into the laptop first. Windows 11 ships inbox drivers for FTDI and CP210x parts, so the adapter should enumerate on its own; a CH340 clone may need the vendor driver.
Device Manager hides the Ports node entirely when the class is empty. If you do not see Ports (COM & LPT) at all, that is not a fault to troubleshoot — it means no serial device is attached, which is the normal state of a laptop with no USB-to-TTL cable plugged in. For the same reason the PowerShell commands below return nothing rather than an error. Both are working; there is simply nothing to list.
With the cable attached, either open Device Manager (devmgmt.msc) and expand
Ports (COM & LPT), or ask PowerShell:
Get-PnpDevice -Class Ports | Select-Object Status,FriendlyName
You are looking for something like USB Serial Port (COM5) or Silicon Labs CP210x USB to UART
Bridge (COM5). Note the number. It is a property of the USB port you plugged into, not of the
cable, so it will change if you move to a different port — worth plugging into the same port every
time and writing the number on the cable.
A quick way to tell “no cable” from “bad driver” without opening Device Manager:
Get-PnpDevice -PresentOnly | Where-Object { $_.Status -ne 'OK' }
A cable that is plugged in but lacking a driver shows up here (and under Other devices with a yellow triangle in Device Manager). An empty result with no COM ports means nothing is attached.
PuTTY is a separate download (choco install putty, or putty.org). Windows has no built-in
serial terminal, so you do need it or an equivalent. On the opening Session screen:
| Setting | Value |
|---|---|
| Connection type | Serial (this swaps the Host Name box for Serial line/Speed) |
| Serial line | COM5 — whatever number you found above |
| Speed | 115200 |
Then open the Connection → Serial category in the left-hand tree and confirm the rest:
| Setting | Value |
|---|---|
| Speed (baud) | 115200 |
| Data bits | 8 |
| Stop bits | 1 |
| Parity | None |
| Flow control | None |
Flow control is the one that actually bites. PuTTY defaults to XON/XOFF, and the three-wire
hookup above has no RTS/CTS lines at all — leave either hardware or software flow control on and
the session will look connected but hang, or swallow keystrokes after the first screenful of
output. Set it to None explicitly.
Two optional settings that make the session much nicer to live in:
xterm. Without it nano, vim, and
htop draw badly and arrow keys may emit junk.Go back to Session, type a name such as pi-serial under Saved Sessions, and click Save.
Reconnecting later is then a double-click, which is what you want mid-demo. Remember to re-save if
the COM number changes.
Click Open.
There is no PuTTY here and none is needed — screen is preinstalled and its defaults are already
8N1 with no flow control, so the entire settings table above collapses into one command.
Enabling the UART from macOS. Put the SD card in a reader; the FAT bootfs partition
automounts:
echo 'enable_uart=1' >> /Volumes/bootfs/config.txt
diskutil eject /Volumes/bootfs
Eject properly rather than pulling the card — a half-flushed config.txt is a confusing way to
lose an afternoon. macOS also scatters ._* AppleDouble files and a .Spotlight-V100 directory
onto the FAT volume; these are harmless to the Pi’s boot, but dot_clean /Volumes/bootfs tidies
them if they bother you.
Drivers. FTDI cables work with no install at all. For CP210x, check first and install Silicon Labs' DriverKit package only if nothing shows up — do not install a kext preemptively on Apple Silicon. PL2303 remains the one to avoid.
Finding the node. List the callout devices before and after plugging the cable in:
ls /dev/cu.*
You are looking for a new entry such as /dev/cu.usbserial-A50285BI or /dev/cu.SLAB_USBtoUART.
Use cu.*, never tty.*. Both nodes exist for the same cable, and this is the single most
common way to lose time on macOS: opening /dev/tty.usbserial-… blocks waiting for carrier detect,
which a three-wire hookup never asserts, so the command just sits there looking like dead hardware.
The cu. (“callout”) node does not wait.
Connect:
screen /dev/cu.usbserial-A50285BI 115200
Exiting screen is the other thing worth knowing before you start rather than after: Ctrl-A
then K, then y to confirm. Note that Ctrl-A is also “beginning of line” in the remote shell —
to send a literal one through to the Pi, press Ctrl-A then A.
If you would rather not fight screen’s key bindings, brew install picocom and then
picocom -b 115200 /dev/cu.usbserial-A50285BI; it exits with Ctrl-A Ctrl-X and survives the cable
being unplugged and replugged more gracefully.
login: prompt appears.sshd
would ever start.Closing the PuTTY window, or killing screen, does not log you out — the getty session stays
open on the Pi. Type exit first, or the next person to connect lands in your shell.
| Symptom | Likely cause |
|---|---|
| Nothing at all, even on boot | enable_uart=1 missing from config.txt, or TX/RX not swapped between cable and Pi |
| Garbage or random high-bit characters | Wrong speed — confirm 115200, not 9600 |
| Text appears but typing does nothing | Cable TX not landing on pin 10, or flow control left on |
| Session freezes after a screen of output | Flow control — set it to None |
Unable to open connection to COM5 |
Another program holds the port, or the cable was unplugged and re-enumerated on a new number |
| macOS: blank window, unresponsive, no boot log | Opened /dev/tty.* instead of /dev/cu.* |
macOS: Resource busy |
An earlier screen still holds the port — screen -ls, then screen -X -S <id> quit |
macOS: ssh to .local hangs then times out |
Terminal lacks Local Network permission (Privacy & Security → Local Network) |
This gets a console but not scp or gdbserver, so it complements the Ethernet route rather than
replacing it.