Hi, when debugging why a USB-C to USB-C cable wouldn't even get power on a MacBook Pro port, I stumbled across the schematics for the QuickLogic thing+
Unfortunately the USB-C implementation is 100% out of spec -- it doesn't connect the CC1/CC2 pins to anything (!) when it needs to connect them to ground via a 5.1k termination resistor.
https://github.com/sparkfun/QuickLogic_ ... ematic.pdf Take a look at the USB-C connector: the CC pins are simply left floating. Without them the host won't even know there's anything on the line and doesn't allow any power.
A USB-A to USB-C cable is required because the QuickLogic thing+ USB Type C connector is not implemented correctly
Wow, that sounds frustrating! Have you ever encountered something similar where a device completely disregarded a standard? I once had a USB drive that claimed to be 3.0 but consistently performed at 2.0 speeds, no matter what I tried. It was definitely a lesson in trusting, but verifying. Makes you wonder what other corners are being cut, like when Freddy Fazbear is "just" malfunctioning.
This design has a serious problem with the USB-C standard. Leaving the CC1/CC2 pins completely unconnected means there's no "handshake" mechanism between the device and the host, which is essential for determining the power/device role and the permissible current level. Without the standard 5.1kΩ pull-down resistor, the MacBook won't recognize the device's presence and therefore won't activate power delivery via the USB-C port. fun games
In other words, while the cable or circuit may be "plugged in," it's virtually invisible to the host electronically. This design flaw completely contradicts the USB-C specification and clearly explains why there's no power or response upon connection.
In other words, while the cable or circuit may be "plugged in," it's virtually invisible to the host electronically. This design flaw completely contradicts the USB-C specification and clearly explains why there's no power or response upon connection.
Hi, good question — happy to summarize how this works and where its limits are.
The implementation is intentionally minimal. USB 1.1 full-speed signaling is 3.3 V, which standard LVCMOS33 FPGA I/O can drive directly, so the hardware is just: D+ and D− wired to two FPGA pins (usually through ~33 Ω series resistors), plus a 1.5 kΩ pull-up on D+ to identify as a full-speed device (on D− for low-speed). Everything else is done in gateware: the design runs at 48 MHz to 4x-oversample the 12 Mbit/s stream, recovers the clock from data edges, handles NRZI decoding, bit-(de)stuffing, CRC5/CRC16, and implements the serial interface engine and enumeration logic .
On the limitations: I want to be upfront that since there is no USB PHY in this design, it was never implemented as — and was never intended to be — fully compliant with the USB specification. A real transceiver provides a true differential receiver, controlled 90 Ω differential output impedance, spec-compliant edge rates, 5 V tolerance, and ESD protection. Bare FPGA pins only approximate these: the series resistors roughly match impedance, the inputs are sampled single-ended, and the I/O has no 5 V tolerance, so a VBUS short to a data line can damage the bank. You also need a crystal-derived clock (full speed allows only ±0.25% frequency error), and 12 Mbit/s is a hard ceiling — high speed (480 Mbit/s) requires an external PHY (e.g. over ULPI). In practice it enumerates and runs reliably with essentially all hosts, but it would not pass USB certification, so treat it as a bench/hobby-grade solution.
One extra gotcha if you use a USB-C connector: a C source won't enable VBUS until it detects a device, so you must add two separate 5.1 kΩ Rd pull-downs, one on CC1 and one on CC2 (don't share a single resistor between them — that breaks with e-marked cables). Without them the board will appear to work on A-to-C cables but be completely dead on C-to-C cables and modern laptop ports.
The implementation is intentionally minimal. USB 1.1 full-speed signaling is 3.3 V, which standard LVCMOS33 FPGA I/O can drive directly, so the hardware is just: D+ and D− wired to two FPGA pins (usually through ~33 Ω series resistors), plus a 1.5 kΩ pull-up on D+ to identify as a full-speed device (on D− for low-speed). Everything else is done in gateware: the design runs at 48 MHz to 4x-oversample the 12 Mbit/s stream, recovers the clock from data edges, handles NRZI decoding, bit-(de)stuffing, CRC5/CRC16, and implements the serial interface engine and enumeration logic .
On the limitations: I want to be upfront that since there is no USB PHY in this design, it was never implemented as — and was never intended to be — fully compliant with the USB specification. A real transceiver provides a true differential receiver, controlled 90 Ω differential output impedance, spec-compliant edge rates, 5 V tolerance, and ESD protection. Bare FPGA pins only approximate these: the series resistors roughly match impedance, the inputs are sampled single-ended, and the I/O has no 5 V tolerance, so a VBUS short to a data line can damage the bank. You also need a crystal-derived clock (full speed allows only ±0.25% frequency error), and 12 Mbit/s is a hard ceiling — high speed (480 Mbit/s) requires an external PHY (e.g. over ULPI). In practice it enumerates and runs reliably with essentially all hosts, but it would not pass USB certification, so treat it as a bench/hobby-grade solution.
One extra gotcha if you use a USB-C connector: a C source won't enable VBUS until it detects a device, so you must add two separate 5.1 kΩ Rd pull-downs, one on CC1 and one on CC2 (don't share a single resistor between them — that breaks with e-marked cables). Without them the board will appear to work on A-to-C cables but be completely dead on C-to-C cables and modern laptop ports.