Skip to the content
4 layers65 × 40 mmUsb passthrough, the printed circuit board in 3D

A USB 2.0 (480 Mbit/s) passthrough board that can electrically "unplug" a USB connection under software control — used for Hardware-in-the-Loop (HIL) testing.

Size
65 × 40 mm
Copper layers
4
Thickness
1.61 mm
Parts
57
Nets
56
Pads
205
Tracks, vias
347, 138
Pours
63
Routed
Yes
KiCad
KiCad 10.0 (file 20260206)
Created
10 Jul 2026
Updated
21 Aug 2026

Overview

Usb passthrough is an open-source printed circuit board by fgihl, from the fgihl/usb-c-passthrough repository on GitHub, published under the MIT licence. It is a 4-layer board of 65 × 40 mm with 57 parts on 56 nets, routed with 347 tracks and 138 vias.

It is built around the CP2102N-A02-GQFN24R, TMUX1574PW and TS3USB221RSER-TP, with the AO3400A, SMF24CA and BZT52C4V7 among its other parts. Its parts include 13 resistors, 11 capacitors, 11 diodes, 4 ICs and 3 connectors.

Main components

6

README

README.md

USB Passthrough — HIL Test Disconnect Device

A USB 2.0 (480 Mbit/s) passthrough board that can electrically "unplug" a USB connection under software control — used for Hardware-in-the-Loop (HIL) testing. A control port drives GPIO lines to disconnect or reconnect the D+/D− data lines, the CC lines, and VBUS independently.

USB 3.x SuperSpeed lanes are intentionally not routed — this revision targets USB 2.0 High-Speed only, which covers the vast majority of HIL test cases while keeping the BOM and routing simple. USB Power Delivery up to 20 V / 3 A (60 W) and BC 1.2 charging are supported.

⚠️ USB-C Orientation Limitation: The CC1/CC2 lines are routed straight through (CC1 → CC1, CC2 → CC2) with a single switch. The board does not include orientation detection or lane flipping, so the cable must be inserted in the same orientation at both J1 and J2. A flipped cable breaks the CC connection and PD negotiation.


System Concept

text
                        ┌─────────────────────────────────────────────┐
                        │               USB Passthrough              │
                        │                                             │
 USB Host ──[IN J1]────►│  D+/D− ─► TS3USB221 ─► ESD ─► [J2 OUT]────►│────► DUT
 USB Host ──[IN J1]────►│  CC1/CC2 ─► TMUX1574 ─► [J2 OUT]           │
 USB Host ──[IN J1]────►│  VBUS ─► TPS259470 eFuse ─► [J2 OUT]       │
                        │                                             │
 Host PC ──[J3 USB-A]──►│  CP2102N (USB-UART) ─► GPIO ─► switches    │
                        └─────────────────────────────────────────────┘

Each switch function is controlled by its own GPIO, so the data path, CC negotiation, and VBUS can be cut and restored independently:

GPIOControlsLogic
GPIO.0CC_EN — TMUX1574 enableHIGH = CC connected (inverted on v1.1)
GPIO.1USB_SEL — TS3USB221 selectHIGH = Port 2 (connected), LOW = floating (disconnect)
GPIO.2VBUS_EN — TPS259470 enableHIGH = VBUS on
GPIO.3FLT — eFuse fault status (input)Read overcurrent/thermal fault

All control lines default to the connected state via 10 kΩ pull-ups, so the board is fully pass-through on power-up with no host software running.

Typical use cases

  • Power-cycle the DUT — drop VBUS while keeping the data path alive
  • Test USB enumeration / re-enumeration — reconnect the D+/D− path without power cycling
  • Simulate cable unplug — cut everything at once (USB 2.0 + CC + VBUS)
  • PD fault injection — break the CC lines to kill PD negotiation while VBUS remains present

The Board

KiCad project under pcb/, revision v1.1 (v1.0 boards supported in software via -b 1).

PCB specifications

ParameterValue
Layers4 (F.Cu / GND / PWR / B.Cu)
Thickness1.6 mm (prepreg 7628)
Board size65 mm × 40 mm
ManufacturerJLCPCB Economic
USB 2.0 diff pair (90 Ω)0.247 mm width / 0.15 mm gap
Min track / spacing0.24 mm / 0.15 mm
Min via0.4 mm / 0.3 mm drill

Signal path

SignalPathSwitch IC
D+ / D−J1 → ESD (D6/D7) → U2 Port 2 → ESD (D8/D9) → J2TS3USB221RSER
CC1 / CC2J1 → U5 → J2TMUX1574PW (2 of 4 channels)
VBUSJ1 → U4 → J2TPS259470ARPWR eFuse
SSTX± / SSRX± / SBU1/2not routed—
SHIELDGND—

Key active components

RefPartPackageFunction
U2TS3USB221RSERUQFN-10USB 2.0 D+/D− switch (S = select, OE = GND)
U3CP2102N-A02-GQFN24RQFN-24USB-UART bridge + 4 GPIO for control
U4TPS259470ARPWRQFN-10eFuse VBUS switch, 2.7–23 V, OCP/OVP, ~4.3 A limit
U5TMUX1574PWTSSOP-164-ch SPDT for CC1/CC2 (breaks PD negotiation when open)
Q1, Q2AO3400ASOT-23MOSFETs driving the status LEDs
D1, D2SMF24CASOD-123F24 V TVS on VBUS_IN / VBUS_OUT
D6–D12ESD9B3.3ST5GSOD-923ESD protection on D+/D− and control port (0.5 pF)
J1, J2Molex 1054500101SMDUSB-C 2.0 receptacles (IN / OUT)
J3USB-B (RA)THTControl port for the CP2102N

Power

  • 3.3 V comes from the CP2102N internal LDO (fed from J3's 5 V) and supplies U2, U5, and the LED drivers — total load is under 1 mA, so no external LDO is needed.
  • VBUS is switched by U4 directly (2.7–23 V), with the current limit set by R3 (820 Ω ⇒ ~4.3 A, covering all PD modes up to 20 V / 3 A; swap to 680 Ω for 5 A).

LED indicators

RefColorMeaning
LED2 (green)Driven by Q1, switched by USB_SELData path active (D+/D− connected)
LED_FLT (red)Driven by Q2, follows U4 FLTeFuse overcurrent/thermal fault

Revisions & errata

  • v1.0 — initial hardware. Errata: wrong R3 value, U4 pin-10 fix, U5 CC swing limited to 3.3 V, green LED loading USB2_SEL.
  • v1.1 — fixed R3 = 1 kΩ, U4 pin-10 corrected, U5 → TMUX1574PWR. Note: CC_EN logic is inverted on v1.1 (HIGH = CC cut), which the software handles automatically.

The Code

Located under code/. A small two-part control stack: a thin Python CLI that wraps a compiled C binary speaking raw USB control transfers to the CP2102N.

text
code/
├── Makefile        Build targets: all / macos / linux / clean
├── usb_ctrl.c      C binary — sends the GPIO latch write via USB control transfer
├── usb_ctrl        (built artifact)
└── usb-pass.py     Python CLI — builds if needed, lists/selects a board, calls usb_ctrl

How it works

  1. usb-pass.py builds usb_ctrl on first use if necessary, then forwards the board selector (--list, a port id, or an index) to it.
  2. usb_ctrl opens the device by VID/PID (10C4:EA60) directly — via IOKit on macOS or libusb-1.0 on Linux — and issues a vendor control transfer (WRITE_LATCH_CMD 0x37E1) that sets the GPIO output latch.
  3. GPIO.0/1/2 are driven to the appropriate state for on / off; GPIO.3 (FLT) is never driven (input only).

Usage

With a single board connected, on/off/toggle work without specifying which board:

bash
python3 usb-pass.py on          # connect the DUT (board v1.1, default)
python3 usb-pass.py off         # electrically unplug the DUT
python3 usb-pass.py toggle      # flip the current state
python3 usb-pass.py -b 1 on     # board v1.0 (CC_EN follows on/off)
python3 usb-pass.py --help      # all options
Multiple boards (Linux)

When more than one board is connected, pick which one to control by its USB port id or list index, or use all-on/all-off/all-toggle to control every connected board at once. status always reports every connected board and can't be combined with a port/index:

bash
python3 usb-pass.py --list       # IDX  PORT       BUS  DEVICE
python3 usb-pass.py 0 on         # select by index (row from --list)
python3 usb-pass.py 1-9.1.2 off  # select by port id (stable across replugs of other boards)
python3 usb-pass.py all-off      # turn off every connected board
python3 usb-pass.py status       # print GPIO state (CC_EN, USB_SEL, VBUS_EN, FLT) of every board

<port> (e.g. 1-9.1.2) identifies the physical hub port the board is plugged into and stays the same regardless of what else is connected or the order boards enumerate in. <index> is just the row number from --list — convenient, but it can shift if a lower-indexed board is unplugged, so prefer <port> in scripts/automation. Board selection by port/index is currently Linux-only; on macOS, usb_ctrl always targets the first CP2102N it finds.

Building manually

bash
# macOS (Xcode CLT only — no extra dependencies)
make macos

# Linux (requires libusb-1.0)
apt install libusb-1.0-0-dev   # Debian/Ubuntu
make linux

Equivalent direct commands: clang -framework IOKit -framework CoreFoundation -o usb_ctrl usb_ctrl.c (macOS) or gcc $(pkg-config --cflags --libs libusb-1.0) -o usb_ctrl usb_ctrl.c (Linux).

Linux udev rule

For non-root access on Linux, create /etc/udev/rules.d/99-cp2102n.rules:

text
SUBSYSTEM=="usb", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE="0666"

Board version handling

The v1.0 and v1.1 boards differ in the CC_EN polarity. usb-pass.py/usb_ctrl default to v1.1; pass -b 1 (or -b 1.0) to target a v1.0 board.


Repository layout

text
├── LICENSE                     MIT license
├── README.md                   This file
├── code/                       Host control software (Python + C)
├── doc/
│   └── chip-selection/         Design rationale and chip-selection notes
└── pcb/                        KiCad project (schematic, layout, production files)
    ├── production/             BOM, positions, designators, IPC netlist
    └── symbol/                 Vendor symbol/footprint imports

License

MIT — see LICENSE.

Parts

57
QtyValueFootprintReferences
7TestPointTestPoint:TestPoint_Pad_D1.5mmTP2, TP3, TP4, TP5, TP6, TP7, TP8
7~Diode_SMD:D_0402_1005MetricD6, D7, D8, D9, D10, D11, D12
5100nFCapacitor_SMD:C_0402_1005MetricC4, C6, C7, C9, C10
410kResistor_SMD:R_0805_2012MetricR5, R8, R9, R11
4MountingHoleMountingHole:MountingHole_2.2mm_M2H1, H2, H3, H4
312kResistor_SMD:R_0603_1608MetricR12, R13, R14
210nFCapacitor_SMD:C_0402_1005MetricC11, C12
21uFCapacitor_SMD:C_1206_3216MetricC2, C8
2470Resistor_SMD:R_0603_1608MetricR2, R4
2AO3400APackage_TO_SOT_SMD:SOT-23Q1, Q2
2SMF24CADiode_SMD:D_SOD-123FD1, D2
2USB_C_16_FEMALEConnector_USB:USB_C_Receptacle_HCTL_HC-TYPE-C-16P-01AJ1, J2
11KResistor_SMD:R_0603_1608MetricR1
11µFCapacitor_SMD:C_0402_1005MetricC3
122kResistor_SMD:R_0603_1608MetricR6
14.7µFCapacitor_SMD:C_0603_1608MetricC5
147kResistor_SMD:R_0603_1608MetricR7
1820Resistor_SMD:R_0603_1608MetricR3
1BZT52C4V7Diode_SMD:D_SOD-323D3
1CP2102N-A02-GQFN24RPackage_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.65x2.65mmU3
1GREENLED_SMD:LED_0805_2012MetricLED2
1REDLED_SMD:LED_0603_1608MetricLED_FLT1
1TMUX1574PWPackage_SO:TSSOP-16_4.4x5mm_P0.65mmU5
1TPS259470ARPWRTPS259470ARPWR:IC_TPS25974ARPWRU4
1TS3USB221RSERS3USB221:RSE10U2
1TestPointTestPoint:TestPoint_Pad_2.5x2.5mmTP9
1USB_BConnector_USB:USB_B_Lumberg_2411_02_HorizontalJ3

Similar boards

  • 4 layers99.9 × 99.9 mmEcu dev board, the printed circuit board in 3D

    Ecu dev board

    D3stan/ecu-dev-board

    265 parts1
  • 4 layers65 × 56 mmEWS, the printed circuit board in 3D

    EWS

    eiten/EWS

    Universal 3D-Printer HAT for SBC with CAN-Interface and USB Hub

    124 parts1
  • 4 layers99.5 × 65 mmEcho, the printed circuit board in 3D

    Echo

    rh1tech/echo

    Echo: ESP32-Based VGA Board

    181 parts4
  • 4 layers130 × 105 mmHomeDeck, the printed circuit board in 3D

    HomeDeck

    Kilan777/HomeDeck

    Jarvis HomeDeck: a Raspberry Pi CM4 carrier board and voice-assistant software for a 7-inch smart display (KiCad hardware, generated from Python, plus the Python/JS assistant)

    228 parts1
  • 4 layers107.5 × 56 mmOutput panel, the printed circuit board in 3D

    Output panel

    gustebeast/public-steel-guitar

    A pedal steel guitar you can build yourself, from parts anyone can buy.

    179 partsCERN-OHL-S-2.0
  • 4 layers80 × 73.8 mmESP32-Bit Pirate Dock, the printed circuit board in 3D

    ESP32-Bit Pirate Dock

    AndreiVladescu/ESP32-Bit-Pirate-Hardware

    Carrier breaker-board for the ESP32-S3 Devkit. Works great with the ESP32-Bit-Pirate firmware.

    49 parts85CERN-OHL-W-2.0
  • 2 layers109.5 × 51 mmCANBOB (MAGE CANBOB-003), the printed circuit board in 3D

    CANBOB (MAGE CANBOB-003)

    Mage-Control-Systems-Ltd/CANBOB

    A breakout board that enables USB or SPI to CAN communication using the MCP2515.

    98 parts8CC-BY-4.0
  • 4 layers65 × 56.5 mmQSPIBuddy, the printed circuit board in 3D

    QSPIBuddy

    Manawyrm/QSPIBuddy

    SPI NOR Flash mux - Raspberry Pi for embedded firmware development - Mux between DUT and Flasher

    46 parts4MIT

Questions

How big is the Usb passthrough PCB?

It measures 65 × 40 mm and has 4 copper layers, 1.61 mm thick.

What parts does the Usb passthrough use?

57 parts, built around the CP2102N-A02-GQFN24R, TMUX1574PW, TS3USB221RSER-TP and AO3400A. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Usb passthrough KiCad files?

From the fgihl/usb-c-passthrough repository on GitHub, at the commit this page was made from: the board is pcb/usb-passthrough.kicad_pcb and its schematic pcb/connectors.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Usb passthrough design in my own project?

Its repository publishes it under the MIT licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).