

Usb passthrough
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
6CP2102N-A02-GQFN24R
QFN-24-EP(4x4)-40℃~+85℃@(Ta) 1.3uA 3V~3.6V 9.5mA USB 2.0 USB to UART QFN-24-EP(4x4) USB Converters ROHSSilicon LabsUSB ConvertersTMUX1574PW
TSSOP-16-40℃~+125℃ 1.5V~5.5V 2:1 2GHz 2Ω 3.5pC 35ns 4 7.5pF 95ns 95ps Bidirectional analog channel、Fault protection、Power-off isolation、Fail-safe disconnect TSSOP-16 Analog Switches, Multiplexers ROHSTexas InstrumentsAnalog Switches, MultiplexersTS3USB221RSER-TP
QFN-10L(1.5x2)-40℃~+85℃ 13uA 2.5V~5.5V 2/4 200ps@3.3V,0pF Power-off protection、Break-before-make function、Overcurrent Protection Single Supply QFN-10L(1.5x2) Signal Switches, Multiplexers, Decoders ROHSTECH PUBLICSignal Switches, Multiplexers, DecodersAO3400A
SOT-23-55℃~+150℃ 1 N-channel 1.45V 1.4W 30V 48mΩ@2.5V 5.7A 50pF 630pF 75pF 7nC@10V N-Channel SOT-23 MOSFETs ROHSAlpha & Omega SemiconductorMOSFETsSMF24CA
SOD-123FLESD And Surge Protection (TVS/ESD)hongjiachengBZT52C4V7
SOD-123Zener Diodeshongjiacheng
README
README.mdUSB 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
┌─────────────────────────────────────────────┐
│ 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:
| GPIO | Controls | Logic |
|---|---|---|
| GPIO.0 | CC_EN — TMUX1574 enable | HIGH = CC connected (inverted on v1.1) |
| GPIO.1 | USB_SEL — TS3USB221 select | HIGH = Port 2 (connected), LOW = floating (disconnect) |
| GPIO.2 | VBUS_EN — TPS259470 enable | HIGH = VBUS on |
| GPIO.3 | FLT — 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
| Parameter | Value |
|---|---|
| Layers | 4 (F.Cu / GND / PWR / B.Cu) |
| Thickness | 1.6 mm (prepreg 7628) |
| Board size | 65 mm × 40 mm |
| Manufacturer | JLCPCB Economic |
| USB 2.0 diff pair (90 Ω) | 0.247 mm width / 0.15 mm gap |
| Min track / spacing | 0.24 mm / 0.15 mm |
| Min via | 0.4 mm / 0.3 mm drill |
Signal path
| Signal | Path | Switch IC |
|---|---|---|
| D+ / D− | J1 → ESD (D6/D7) → U2 Port 2 → ESD (D8/D9) → J2 | TS3USB221RSER |
| CC1 / CC2 | J1 → U5 → J2 | TMUX1574PW (2 of 4 channels) |
| VBUS | J1 → U4 → J2 | TPS259470ARPWR eFuse |
| SSTX± / SSRX± / SBU1/2 | not routed | — |
| SHIELD | GND | — |
Key active components
| Ref | Part | Package | Function |
|---|---|---|---|
| U2 | TS3USB221RSER | UQFN-10 | USB 2.0 D+/D− switch (S = select, OE = GND) |
| U3 | CP2102N-A02-GQFN24R | QFN-24 | USB-UART bridge + 4 GPIO for control |
| U4 | TPS259470ARPWR | QFN-10 | eFuse VBUS switch, 2.7–23 V, OCP/OVP, ~4.3 A limit |
| U5 | TMUX1574PW | TSSOP-16 | 4-ch SPDT for CC1/CC2 (breaks PD negotiation when open) |
| Q1, Q2 | AO3400A | SOT-23 | MOSFETs driving the status LEDs |
| D1, D2 | SMF24CA | SOD-123F | 24 V TVS on VBUS_IN / VBUS_OUT |
| D6–D12 | ESD9B3.3ST5G | SOD-923 | ESD protection on D+/D− and control port (0.5 pF) |
| J1, J2 | Molex 1054500101 | SMD | USB-C 2.0 receptacles (IN / OUT) |
| J3 | USB-B (RA) | THT | Control 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
| Ref | Color | Meaning |
|---|---|---|
| LED2 (green) | Driven by Q1, switched by USB_SEL | Data path active (D+/D− connected) |
| LED_FLT (red) | Driven by Q2, follows U4 FLT | eFuse 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.
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_ctrlHow it works
usb-pass.pybuildsusb_ctrlon first use if necessary, then forwards the board selector (--list, a port id, or an index) to it.usb_ctrlopens 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.- 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:
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 optionsMultiple 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:
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
# macOS (Xcode CLT only — no extra dependencies)
make macos
# Linux (requires libusb-1.0)
apt install libusb-1.0-0-dev # Debian/Ubuntu
make linuxEquivalent 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:
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
├── 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 importsLicense
MIT — see LICENSE.
Parts
57| Qty | Value | Footprint | References |
|---|---|---|---|
| 7 | TestPoint | TestPoint:TestPoint_Pad_D1.5mm | TP2, TP3, TP4, TP5, TP6, TP7, TP8 |
| 7 | ~ | Diode_SMD:D_0402_1005Metric | D6, D7, D8, D9, D10, D11, D12 |
| 5 | 100nF | Capacitor_SMD:C_0402_1005Metric | C4, C6, C7, C9, C10 |
| 4 | 10k | Resistor_SMD:R_0805_2012Metric | R5, R8, R9, R11 |
| 4 | MountingHole | MountingHole:MountingHole_2.2mm_M2 | H1, H2, H3, H4 |
| 3 | 12k | Resistor_SMD:R_0603_1608Metric | R12, R13, R14 |
| 2 | 10nF | Capacitor_SMD:C_0402_1005Metric | C11, C12 |
| 2 | 1uF | Capacitor_SMD:C_1206_3216Metric | C2, C8 |
| 2 | 470 | Resistor_SMD:R_0603_1608Metric | R2, R4 |
| 2 | AO3400A | Package_TO_SOT_SMD:SOT-23 | Q1, Q2 |
| 2 | SMF24CA | Diode_SMD:D_SOD-123F | D1, D2 |
| 2 | USB_C_16_FEMALE | Connector_USB:USB_C_Receptacle_HCTL_HC-TYPE-C-16P-01A | J1, J2 |
| 1 | 1K | Resistor_SMD:R_0603_1608Metric | R1 |
| 1 | 1µF | Capacitor_SMD:C_0402_1005Metric | C3 |
| 1 | 22k | Resistor_SMD:R_0603_1608Metric | R6 |
| 1 | 4.7µF | Capacitor_SMD:C_0603_1608Metric | C5 |
| 1 | 47k | Resistor_SMD:R_0603_1608Metric | R7 |
| 1 | 820 | Resistor_SMD:R_0603_1608Metric | R3 |
| 1 | BZT52C4V7 | Diode_SMD:D_SOD-323 | D3 |
| 1 | CP2102N-A02-GQFN24R | Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.65x2.65mm | U3 |
| 1 | GREEN | LED_SMD:LED_0805_2012Metric | LED2 |
| 1 | RED | LED_SMD:LED_0603_1608Metric | LED_FLT1 |
| 1 | TMUX1574PW | Package_SO:TSSOP-16_4.4x5mm_P0.65mm | U5 |
| 1 | TPS259470ARPWR | TPS259470ARPWR:IC_TPS25974ARPWR | U4 |
| 1 | TS3USB221RSER | S3USB221:RSE10 | U2 |
| 1 | TestPoint | TestPoint:TestPoint_Pad_2.5x2.5mm | TP9 |
| 1 | USB_B | Connector_USB:USB_B_Lumberg_2411_02_Horizontal | J3 |
Similar boards
- 4 layers99.9 × 99.9 mm

- 4 layers65 × 56 mm

- 4 layers99.5 × 65 mm

- 4 layers130 × 105 mm

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 mm

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 mm

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 mm

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 mm

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).