Back to Technology

USB Part 2: Electrical & Hardware Layer

March 31, 2026 Wasil Zafar 20 min read

Master USB electrical specifications — differential signaling on D+ and D- lines, speed detection via pull-up resistors, VBUS power management, ESD protection circuits, and PCB layout rules for reliable USB hardware design.

Table of Contents

  1. USB Electrical Basics
  2. Speed Detection via Pull-up Resistors
  3. VBUS Power Management
  4. ESD Protection
  5. USB Cable & Connector Types
  6. PCB Layout Rules for USB
  7. STM32 USB Hardware Initialization
  8. Hardware Validation Checklist
  9. Practical Exercises
  10. USB Hardware Checklist Generator
  11. Conclusion & Next Steps
Series Context: This is Part 2 of the 17-part USB Development Mastery series. In Part 1 we built the conceptual model of USB as a system. Now we descend to the physical layer — the electrons, resistors, capacitors, and copper traces that make USB work in hardware.

USB Development Mastery

Your 17-step learning path • Currently on Step 2

USB Electrical Basics

USB signaling uses differential signaling — the same fundamental technique used in RS-485, CAN bus, and Ethernet. Instead of measuring the voltage on a single wire relative to ground, the USB receiver measures the difference in voltage between two wires: D+ (Data Plus) and D- (Data Minus). This gives USB two critical properties that a single-ended interface like UART cannot offer at speed:

  • Common-mode noise rejection: Any noise that couples equally onto both D+ and D- lines — from nearby switching power supplies, motor drives, or radio-frequency interference — is cancelled out by the differential receiver. The signal is only in the difference between the two lines.
  • Reduced EMI emissions: Because D+ and D- carry complementary signals, their electromagnetic fields partially cancel each other. A properly routed differential pair emits far less radiated noise than two single-ended signals carrying the same data rate.

Signal States: SE0, J, K

USB defines its logical states in terms of the differential voltage between D+ and D-, plus a special "both lines low" state. Understanding these three states is essential before you can interpret oscilloscope traces or understand reset and speed detection:

State D+ Voltage D- Voltage FS Meaning LS Meaning HS Meaning
SE0 (Single-Ended Zero) < 0.3 V < 0.3 V Reset / End-of-Packet Reset / End-of-Packet Chirp (HS negotiation)
J State > 2.8 V < 0.3 V Idle / Logic 1 Idle / Logic 0 (inverted) HS idle (0 differential)
K State < 0.3 V > 2.8 V Logic 0 / Start-of-Packet Logic 1 / Start-of-Packet Chirp K (HS capable device)
Differential 1 D+ > D- + 200 mV Logic 1
Differential 0 D- > D+ + 200 mV Logic 0
Key Insight: Low Speed USB has J and K states inverted relative to Full Speed. This is not a typo — it is a deliberate design choice that lets the host hub distinguish LS devices from FS devices based on which data line has the pull-up resistor.

NRZI Encoding and Bit Stuffing

USB uses NRZI encoding (Non-Return-to-Zero Inverted). In NRZI, a logic 0 is represented by a transition of the signal (J to K or K to J), and a logic 1 is represented by no transition (the line stays in the same state). This is the opposite of what many developers intuitively expect coming from UART experience.

Because a long run of 1s produces no transitions, and the USB receiver uses clock recovery from transitions, USB mandates bit stuffing: after any six consecutive 1-bits in the encoded data stream, a 0-bit is forcibly inserted. The receiver knows to strip this extra bit. This ensures transitions occur frequently enough for the receiver's PLL to stay locked. When you see a 0-bit appearing at a position that doesn't match the expected data pattern in a protocol analyser trace, bit stuffing is the explanation.

Speed Detection via Pull-up Resistors

When a USB device is connected to a host port, no firmware has run and no enumeration has started. The host needs to determine the device's speed before it can even send a reset. It does this entirely in hardware, by detecting which data line has a pull-up resistor:

USB Speed Pull-up Line Resistor Value Voltage Level Seen by Host
Low Speed (1.5 Mbit/s) D- 1.5 kΩ to 3.3 V D- pulled high, D+ pulled low by hub
Full Speed (12 Mbit/s) D+ 1.5 kΩ to 3.3 V D+ pulled high, D- pulled low by hub
High Speed (480 Mbit/s) D+ (starts as FS) 1.5 kΩ to 3.3 V initially FS detected, then Chirp K negotiation

The host port has 15 kΩ pull-down resistors on both D+ and D-. These create a voltage divider with the device's pull-up: a 1.5 kΩ pull-up on D+ into a 15 kΩ pull-down results in approximately 2.9 V on D+, which the host interprets as a Full Speed device attached. The pull-down resistors also ensure that D+ and D- are at a defined low voltage when no device is connected.

High Speed Chirp Negotiation

High Speed devices begin life as Full Speed — they assert the 1.5 kΩ pull-up on D+, just like any FS device. Once the host detects the FS device and issues a USB Reset (SE0 for at least 10 ms), the device signals that it supports High Speed by driving a Chirp K on the bus: it removes the pull-up resistor and drives D- high (K state) for at least 2.5 µs. The host responds with alternating Chirp K / Chirp J pulses. If the device detects four or more Chirp K–J pairs, both sides switch to the HS electrical signaling mode (400 mV differential, terminated with 45 Ω to ground on each line).

TinyUSB Pull-up Configuration

In TinyUSB with STM32 HAL, the USB pull-up is controlled by the USB peripheral hardware — not by a GPIO you manually set. The OTG_FS peripheral controls the pull-up through its internal register. However, some STM32 designs use a discrete external pull-up transistor controlled by a GPIO pin. Here is how both cases are handled:

/* ---------------------------------------------------------------
 * Case 1: OTG_FS peripheral with internal pull-up (most STM32s)
 * The pull-up is enabled automatically when USB_OTG_DCTL SDIS bit
 * is cleared — TinyUSB / HAL does this for you inside tusb_init().
 * ---------------------------------------------------------------*/

/* In tusb_config.h — no manual pull-up needed */
#define CFG_TUSB_RHPORT0_MODE   OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED
#define CFG_TUSB_OS             OPT_OS_NONE

/* ---------------------------------------------------------------
 * Case 2: External pull-up transistor on a GPIO (some custom boards)
 * e.g., PB12 = low → Q1 NPN pulls D+ high via 1.5 kΩ
 * ---------------------------------------------------------------*/
void usb_pullup_enable(bool enable)
{
    /* PA8 used as USB_DP_PULLUP on a custom board */
    GPIO_InitTypeDef gpio = {0};
    gpio.Pin   = GPIO_PIN_8;
    gpio.Mode  = GPIO_MODE_OUTPUT_PP;
    gpio.Pull  = GPIO_NOPULL;
    gpio.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &gpio);

    /* Active-high: set PA8 HIGH to enable pull-up via transistor */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8,
                      enable ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

/* Call before tusb_init() to ensure pull-up is driven correctly */
int main(void)
{
    HAL_Init();
    SystemClock_Config();    /* must reach 48 MHz USB clock first */
    usb_pullup_enable(true);
    tusb_init();
    while (1) {
        tud_task();
    }
}
Common Mistake: Enabling the USB pull-up before the 48 MHz USB clock is running causes the device to appear at the wrong speed or fail enumeration entirely. Always configure the system clock and ensure the USB clock is running before enabling the pull-up.

VBUS Power Management

VBUS is the 5 V power supply that the USB host provides to bus-powered devices. It is supplied on pin 1 of every USB connector (Micro-B pin 1, Type-C VBUS pins A4/A9/B4/B9). The USB specification defines tight voltage and current limits that your hardware must meet to pass compliance testing and work reliably across all hosts.

VBUS Voltage Specification

The USB 2.0 specification defines VBUS at the device's cable plug as:

  • Nominal: 5.0 V
  • Minimum (at device receptacle): 4.75 V (accounting for cable drop)
  • Maximum (at device receptacle): 5.25 V
  • Absolute maximum (device must survive): 6.0 V (with ESD or surge)

The cable resistance plus connector contact resistance can drop up to 250 mV at the maximum 500 mA bus current, which is why the floor is 4.75 V rather than exactly 5.0 V. Your LDO or DCDC converter input range must accommodate the full 4.75–5.25 V range.

Power States and Current Limits

State Device Type Max Current Draw Notes
Unconfigured Bus-powered 100 mA Before SET_CONFIGURATION completes
Configured (low power) Bus-powered 100 mA bMaxPower = 50 in descriptor (units of 2 mA)
Configured (high power) Bus-powered 500 mA bMaxPower = 250 in descriptor (units of 2 mA)
USB Suspend Bus-powered 2.5 mA Mandatory — host may cut power to non-compliant devices
Any state Self-powered 0 mA (from VBUS) Device provides its own power; bmAttributes bit 6 set

Inrush Current and Soft-Start

Large input capacitors on your 3.3 V rail charge through the cable's resistance when VBUS first appears. This inrush current spike can exceed the host's overcurrent limit and cause it to disconnect your device before enumeration begins. The USB specification limits the maximum inrush charge to 50 µC. For a 5 V to 3.3 V LDO with a 100 µF output capacitor, the inrush charge is approximately:

Q = C × ΔV = 100 µF × (5.0 − 0) = 500 µC — ten times the limit.

Solutions include: (1) use a smaller input capacitor (4.7–10 µF is acceptable if your regulator is stable), (2) add an NTC thermistor in series with VBUS for passive inrush limiting, or (3) use a dedicated soft-start circuit or an ideal diode / MOSFET controller with programmable slew rate.

VBUS Detection on STM32

/* ---------------------------------------------------------------
 * VBUS detection using STM32 OTG_FS VBUS sensing
 * Enabled via GPIOA pin 9 in analog mode (USB_OTG_FS VBUS pin)
 * ---------------------------------------------------------------*/

/* In MX_USB_OTG_FS_PCD_Init() — generated by CubeMX */
static void MX_USB_OTG_FS_PCD_Init(void)
{
    hpcd_USB_OTG_FS.Instance                 = USB_OTG_FS;
    hpcd_USB_OTG_FS.Init.dev_endpoints       = 4;
    hpcd_USB_OTG_FS.Init.speed               = PCD_SPEED_FULL;
    hpcd_USB_OTG_FS.Init.phy_itface          = PCD_PHY_EMBEDDED;
    hpcd_USB_OTG_FS.Init.Sof_enable          = DISABLE;
    hpcd_USB_OTG_FS.Init.low_power_enable    = DISABLE;
    hpcd_USB_OTG_FS.Init.lpm_enable          = DISABLE;
    hpcd_USB_OTG_FS.Init.vbus_sensing_enable = ENABLE; /* VBUS sensing ON */
    hpcd_USB_OTG_FS.Init.use_dedicated_ep1   = DISABLE;
    if (HAL_PCD_Init(&hpcd_USB_OTG_FS) != HAL_OK) {
        Error_Handler();
    }
}

/* PA9 must be configured as analog input for VBUS sensing */
static void USB_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOA_CLK_ENABLE();

    /* PA9 = USB_OTG_FS_VBUS — must be analog, NOT alternate function */
    GPIO_InitStruct.Pin  = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* PA11 = USB_OTG_FS_DM, PA12 = USB_OTG_FS_DP */
    GPIO_InitStruct.Pin       = GPIO_PIN_11 | GPIO_PIN_12;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull      = GPIO_NOPULL;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

/* TinyUSB callback: called when VBUS rises above threshold */
void tud_mount_cb(void)
{
    /* Device has been enumerated and configured by host */
    /* Safe to begin USB-dependent tasks */
    led_set(LED_USB_ACTIVE);
}

/* TinyUSB callback: called when VBUS drops (cable unplugged) */
void tud_umount_cb(void)
{
    /* Device disconnected — clean up USB-dependent state */
    led_set(LED_USB_INACTIVE);
}
Design Tip: If your board disables VBUS sensing (vbus_sensing_enable = DISABLE), the OTG core assumes VBUS is always present. This works on boards where VBUS is always available (self-powered or dedicated USB power), but will cause enumeration failures on hosts that monitor VBUS current.

ESD Protection

USB connectors are directly handled by users and are exposed to electrostatic discharge events of up to ±15 kV (Human Body Model). Your MCU's USB pins typically tolerate ±2 kV at best. An unprotected USB port is therefore a reliability time bomb — it may survive 1,000 plug cycles in the lab but fail on the first plug in a static-charged user's hands in a dry winter environment.

TVS Diode Requirements for USB

A Transient Voltage Suppressor (TVS) diode clamps voltage spikes to a safe level by becoming a low-impedance path to ground when the voltage exceeds its breakdown voltage. For USB protection, you need a bi-directional TVS diode (to handle both positive and negative transients) or a TVS diode array designed specifically for USB lines. The key specification constraints are:

  • Clamping voltage: Must clamp below the MCU's absolute maximum voltage on the USB pins (typically 3.6–4.0 V for 3.3 V GPIO). Choose a part with Vclamp ≤ 3.6 V at the rated transient current.
  • Standoff voltage: Must be above 3.3 V so the TVS doesn't conduct during normal operation. 5.0 V or 5.5 V standoff is typical for VBUS; 3.3 V standoff for D+ and D- lines.
  • Capacitance: This is the critical constraint for High Speed USB. Every picofarad of parasitic capacitance from the protection device degrades signal integrity. For FS (12 Mbit/s), <100 pF is acceptable. For HS (480 Mbit/s), each protection element must be <1 pF.
  • Leakage current: Must be negligible at 3.3 V standby voltage — keep <1 µA to avoid pulling D+ or D- below the threshold that the host needs to see for speed detection.
Vendor Part Number Lines Protected Capacitance Clamping Voltage USB Speed
Nexperia PRTR5V0U2X D+, D- 0.45 pF per line 6.0 V @ 10 mA FS and HS
STMicroelectronics USBLC6-2SC6 D+, D-, VBUS 0.5 pF (D+/D-) 6.5 V @ 5 mA FS and HS
Littelfuse SP0504BAHTG D+, D- 0.35 pF per line 7.0 V @ 1 A FS and HS
ON Semiconductor ESD7L5.0DT5G Single line 0.5 pF 8.5 V @ 1 A FS only
Vishay VESD05C2-02V-GS08 D+, D- 0.8 pF per line 7.0 V @ 1 A FS (marginal for HS)

ESD Protection Placement Rules

Placement is as important as part selection. An ESD protection device placed far from the connector — even with the right electrical specifications — provides degraded protection because the trace from the connector to the protection device acts as an antenna that couples transients directly into the board. Follow these rules:

  • Place the TVS diode array within 500 µm of the USB connector pins. The exact distance depends on trace width and layer stack, but "right next to the connector" is the correct mental model.
  • Connect the TVS ground pin to the PCB ground plane directly below the device via a low-inductance via — use multiple small vias in parallel rather than a single via.
  • Route the protected trace from the TVS device to the MCU — never route the unprotected trace from the connector past the TVS to the MCU. The trace before the TVS is the "dirty" side; the trace after is the "clean" side.
  • Keep the D+ and D- trace lengths from the TVS to the MCU as short as possible — every millimeter of trace adds inductance and capacitance.

USB Cable & Connector Types

Choosing the right connector is not just a mechanical decision — connector type determines the pinout, the mechanical mating force, the expected mating cycles, and whether your device can support USB Power Delivery. Here is the complete picture:

Connector Pins Mating Cycles Max Current Typical Use
Type-A Plug VBUS, D-, D+, GND 1,500 500 mA (2.0) / 900 mA (3.0) Host side (computer, hub)
Type-B Plug VBUS, D-, D+, GND 1,500 500 mA Printers, USB hubs (device side)
Mini-B (5-pin) VBUS, D-, D+, ID, GND 5,000 500 mA Older cameras, GPS units
Micro-B (5-pin) VBUS, D-, D+, ID, GND 10,000 1.8 A (USB BC 1.2) Phones, dev boards (Arduino, STM32)
USB-C (24-pin) VBUS ×4, D+/D- ×2, CC1/CC2, SBU1/SBU2, GND ×4, TX/RX ×4 10,000 3 A (5 V) / 5 A with E-marker Modern devices, laptops, dev boards

USB-C CC Pin Orientation Detection

USB-C is rotationally symmetric — the connector can be inserted in either orientation. The CC1 and CC2 (Configuration Channel) pins are the mechanism by which the device detects cable orientation and negotiates power roles. In a basic USB 2.0 device (no Power Delivery):

  • The device places a 5.1 kΩ resistor from each CC pin to GND (Rd pull-down).
  • The host places a current source (80 µA for 500 mA, 180 µA for 1.5 A, 330 µA for 3 A) on both CC1 and CC2 pins.
  • When the cable is inserted, only one CC pin connects to the host's CC pin (the other connects to VCONN, which powers active cables). The voltage on the connected CC pin tells the device how much current the host is advertising.
  • The orientation is determined by which CC pin has the host's current source active — this tells the device (or mux IC) which orientation the cable was inserted in, so it can route the D+/D- lines correctly through a multiplexer if necessary.

For a simple USB 2.0 device, you only need the two 5.1 kΩ resistors on CC1 and CC2. No firmware is required for basic cable orientation — the USB 2.0 D+/D- signals are on both sides of the USB-C connector symmetrically (pins A6/B6 for D+, pins A7/B7 for D-).

Cable Impedance Requirements

USB cables must maintain 90 Ω ± 15% differential impedance. This is the same impedance your PCB traces must be designed for. At Full Speed, cable impedance mismatch causes signal reflections that increase the bit error rate. At High Speed (480 Mbit/s), impedance mismatch creates pre-shoot and overshoot that can cause the eye diagram to fail the USB 2.0 compliance mask.

PCB Layout Rules for USB

USB signal integrity is heavily dependent on PCB layout quality. A well-chosen MCU with excellent USB hardware will fail compliance tests if the PCB layout violates the fundamental rules. These rules are not guidelines — they are requirements from the USB specification's signal integrity sections.

Differential Pair Routing

  • Length matching: D+ and D- traces must be matched in length to within ±5 mil (0.127 mm) of each other. Unequal lengths cause the common-mode component of the differential signal to increase, degrading noise immunity.
  • Spacing: Keep the two traces of a differential pair as close together as practicable — the gap between D+ and D- should be approximately equal to the trace width (typically 4–6 mil for 90 Ω controlled impedance on a typical 4-layer FR-4 board). The closer the traces, the tighter the coupling and the lower the emissions.
  • No sharp corners: Route differential pairs with 45° bends or smooth curves. Sharp 90° corners cause impedance discontinuities.
  • Avoid vias if possible: Each via in a differential pair adds parasitic inductance and capacitance. Route on a single layer where possible. If vias are unavoidable, use matched pairs of vias placed symmetrically.

Impedance Control

The target differential impedance for USB 2.0 is 90 Ω ± 10% (i.e., 81–99 Ω). Your PCB manufacturer must be asked to control impedance, and your stackup must be designed appropriately. For a typical 4-layer 1.6 mm FR-4 board:

Trace Width Trace Gap Layer Dielectric to Ground Plane Approx Zdiff
8 mil (0.20 mm) 8 mil (0.20 mm) Top (L1) 100 µm to L2 GND plane ~90 Ω
6 mil (0.15 mm) 6 mil (0.15 mm) Inner (L2 or L3) 130 µm to adjacent GND plane ~90 Ω

Ground Plane and Keep-out Rules

  • Maintain a continuous ground plane directly beneath the USB differential pair traces. Splits or cutouts in the ground plane below the traces create impedance discontinuities and increase loop area (and therefore EMI).
  • Establish a keep-out zone of at least 20 mil on each side of the differential pair — no power planes, no unrelated signals, no copper fills in this zone.
  • Route the USB traces away from clock signals, especially the 48 MHz USB clock, high-speed SPI clocks, or SDIO clocks. Crosstalk from adjacent clock traces can increase USB jitter above the compliance limit.
  • Add a ferrite bead on VBUS between the connector and your onboard filtering capacitors. This reduces conducted EMI from your board back onto the host's power rail. A 600 Ω @ 100 MHz ferrite (e.g., Murata BLM18AG601SN1D) in series with VBUS is a good starting point.

Reference Designator Checklist

Every USB hardware design should include these components. Missing any of them is a common cause of EMC test failures or field reliability problems:

Ref Des Component Value / Part Purpose
D1 TVS diode array PRTR5V0U2X or USBLC6-2 ESD protection on D+, D-, VBUS
FB1 Ferrite bead 600 Ω @ 100 MHz VBUS EMI filtering
C1 Decoupling capacitor 4.7 µF / 10 V ceramic VBUS bulk decoupling after ferrite
C2 Decoupling capacitor 100 nF / 10 V ceramic VBUS high-frequency decoupling
R1 Pull-up resistor (if external) 1.5 kΩ 1% D+ speed detection (FS)
R2, R3 CC pull-down resistors (USB-C) 5.1 kΩ 1% USB-C device role indication

STM32 USB Hardware Initialization

STM32 microcontrollers offer two USB peripheral variants with very different characteristics. Choosing incorrectly early in your design can result in a hardware redesign:

Peripheral Max Speed PHY External Components Typical MCUs
USB_FS (non-OTG) Full Speed (12 Mbit/s) Internal None STM32F1, STM32F3, STM32L4
USB_OTG_FS Full Speed (12 Mbit/s) Internal None (except pull-up on some variants) STM32F2, STM32F4, STM32F7, STM32H7
USB_OTG_HS (internal PHY) Full Speed (12 Mbit/s) Internal FS PHY None STM32F4, STM32H7
USB_OTG_HS (external ULPI) High Speed (480 Mbit/s) External ULPI (e.g., USB3300) ULPI PHY chip, 20–30 Ω series resistors STM32F4, STM32F7, STM32H7

48 MHz USB Clock Configuration

The USB peripheral requires an exactly 48 MHz clock. On STM32F4/F7, this is derived from the main PLL or a dedicated PLLSAI. Common configurations:

  • HSE 8 MHz → PLL → 48 MHz: PLL_M=8, PLL_N=336, PLL_P=4 gives a 168 MHz system clock and PLL_Q=7 gives 48 MHz for USB. This is the most common STM32F407 configuration.
  • HSI48 (STM32L4, STM32G4): Some STM32 variants have a dedicated 48 MHz RC oscillator that feeds USB directly, with CRS (Clock Recovery System) to trim it against USB SOF packets for <500 ppm accuracy.
/* ---------------------------------------------------------------
 * USB GPIO initialization for STM32F407 OTG_FS
 * PA11 = OTG_FS_DM  (D-)
 * PA12 = OTG_FS_DP  (D+)
 * PA9  = OTG_FS_VBUS (analog input for VBUS sensing)
 * ---------------------------------------------------------------*/

void USB_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* Enable GPIO clocks */
    __HAL_RCC_GPIOA_CLK_ENABLE();

    /* ---- PA9: VBUS sensing (analog, no pull) ---- */
    GPIO_InitStruct.Pin  = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* ---- PA11, PA12: D- and D+ (alternate function) ---- */
    GPIO_InitStruct.Pin       = GPIO_PIN_11 | GPIO_PIN_12;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull      = GPIO_NOPULL;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* Enable OTG_FS peripheral clock */
    __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
}

/* ---------------------------------------------------------------
 * System clock configuration — STM32F407, HSE 8 MHz, 168 MHz AHB
 * USB clock derived from PLL_Q = 48 MHz
 * ---------------------------------------------------------------*/

void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /* Enable HSE oscillator */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState       = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource  = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM       = 8;   /* HSE 8 MHz / 8 = 1 MHz VCO input */
    RCC_OscInitStruct.PLL.PLLN       = 336; /* 1 MHz × 336 = 336 MHz VCO output */
    RCC_OscInitStruct.PLL.PLLP       = RCC_PLLP_DIV2; /* 336 / 2 = 168 MHz system */
    RCC_OscInitStruct.PLL.PLLQ       = 7;  /* 336 / 7 = 48 MHz USB clock */
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    /* Set AHB, APB1, APB2 clocks */
    RCC_ClkInitStruct.ClockType      = RCC_CLOCKTYPE_HCLK  |
                                       RCC_CLOCKTYPE_SYSCLK |
                                       RCC_CLOCKTYPE_PCLK1  |
                                       RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource   = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider  = RCC_SYSCLK_DIV1;   /* 168 MHz AHB */
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;     /* 42 MHz APB1 */
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;     /* 84 MHz APB2 */
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
}
Clock Accuracy Requirement: The USB specification requires the bit clock to be within ±500 ppm (0.05%) of 12 MHz (FS) or 480 MHz (HS). Internal RC oscillators typically have ±1–2% tolerance — they are NOT suitable as USB clocks without CRS hardware trimming. Always use an HSE crystal or the STM32's CRS-trimmed HSI48 for USB clocking.

Hardware Validation Checklist

Before committing a hardware design to production, run through this systematic hardware validation process. Each item requires specific equipment and produces a definitive pass/fail result.

Oscilloscope Eye Diagram Check

An eye diagram is the gold-standard test for USB signal integrity. To create one:

  1. Connect a differential probe to D+ and D- at the device connector pins (not at the MCU pads — the connector is the compliance test point).
  2. Trigger the oscilloscope on the USB bit clock (use the frame sync output from a protocol analyser if available).
  3. Enable infinite persistence mode and accumulate at least 1,000 transitions.
  4. Overlay the USB compliance eye mask template for your speed (available from the USB-IF compliance test specification documents).
  5. For Full Speed (12 Mbit/s), the mask requires minimum eye opening of ≥ 300 mV (differential) and the timing margin at the mask crossing point.
  6. For High Speed (480 Mbit/s), the eye mask is far tighter: minimum 200 mV amplitude, very tight timing margins.
Validation Item Pass Criterion Tool Required
D+ and D- idle voltage (FS device) D+ ≥ 2.8 V, D- < 0.3 V when connected to host Digital multimeter or scope
Pull-up resistor value 1.5 kΩ ± 5% on D+ LCR meter or resistance measurement
VBUS voltage at device connector 4.75 V – 5.25 V under rated load Digital multimeter
VBUS inrush current Peak charge < 50 µC within first 10 ms Current probe + oscilloscope, integrate i(t)
Differential impedance of D+/D- traces 90 Ω ± 10% (81–99 Ω) TDR (Time Domain Reflectometry) or impedance analyser
Eye diagram (Full Speed) All transitions within USB FS eye mask, no violations Differential oscilloscope probe + USB eye mask template
ESD protection clamping voltage V_clamp ≤ 3.6 V at rated transient current (8 × 20 µs pulse) ESD simulator + oscilloscope
Enumeration on Windows, Linux, macOS Device appears in device manager / lsusb / System Information with correct VID/PID PC with each OS + USB protocol analyser
USB suspend current < 2.5 mA total from VBUS during suspend Precision ammeter in series with VBUS
Cable hot-plug 100 times Device enumerates correctly on every plug cycle, no hangs Automated test rig or manual testing

Practical Exercises

These exercises reinforce the electrical and hardware concepts from this article. Work through them in order — each builds on the previous.

Exercise 1 Beginner

Measure USB Idle Voltages

Take a Micro-B or USB-C development board (Arduino, STM32 Nucleo, or similar), connect it to a powered USB hub, and use a multimeter to measure the voltage on D+ and D- relative to GND while the device is idle (not sending or receiving data). Verify that D+ is approximately 2.9 V (pulled up through the 1.5 kΩ device pull-up against the 15 kΩ host pull-down), and D- is close to 0 V. Calculate the theoretical voltage using the voltage divider formula: V = 3.3 × (15 / (1.5 + 15)).

Measurement Pull-up Resistors Voltage Divider
Exercise 2 Intermediate

Capture USB Reset Waveform on an Oscilloscope

Connect an oscilloscope (any bandwidth ≥ 100 MHz is sufficient for FS USB) to D+ and D- on a USB device's connector pins. Set the trigger to trigger on both channels going below 300 mV simultaneously (the SE0 condition). Plug in a Full Speed USB device. Capture and measure the USB reset: (a) verify the SE0 duration is ≥ 10 ms, (b) identify the J state before and after the reset, (c) measure the D+ rise time and verify it is within the USB 2.0 specification of ≤ 18 ns for FS. If your scope has a differential mode, use it to view the differential signal directly.

Oscilloscope USB Reset SE0 State
Exercise 3 Advanced

Design a USB Connector Front-End for High Speed Operation

Design the complete PCB front-end for a High Speed USB device using a USB-C connector. Your design must include: (a) a USB-C receptacle with correct pinout assignment, (b) 5.1 kΩ pull-down resistors on CC1 and CC2 for device role detection, (c) an ESD protection array with <1 pF capacitance per D+/D- line, (d) a ferrite bead and dual-capacitor pi-filter on VBUS, (e) impedance-controlled routing plan (90 Ω differential) with trace widths and gaps for your chosen PCB stackup. Document each design choice with reference to the USB specification section that mandates or recommends it. Calculate whether your VBUS decoupling capacitance exceeds the 50 µC inrush charge limit.

PCB Design USB-C High Speed ESD Impedance Control

USB Hardware Design Checklist Generator

Use this tool to document your USB hardware design — target MCU, USB speed, connector type, VBUS protection scheme, ESD components, and PCB notes. Download as Word, Excel, PDF, or PowerPoint for design review or project documentation.

USB Hardware Checklist Generator

Document your USB hardware design for review and export.

Draft auto-saved

All data stays in your browser. Nothing is sent to or stored on any server.

Conclusion & Next Steps

In this article we covered the complete USB electrical and hardware layer:

  • Differential signaling with D+ and D- gives USB its noise immunity and low emissions. Understanding the J, K, and SE0 states is foundational to reading oscilloscope traces and protocol analyser output.
  • Speed detection via pull-up resistor position is entirely passive and happens before any firmware runs. A 1.5 kΩ pull-up on D+ signals Full Speed; on D- signals Low Speed. High Speed devices start as FS and upgrade via the Chirp K negotiation sequence.
  • VBUS management requires attention to voltage range (4.75–5.25 V), inrush current limits (50 µC), and power state transitions (100 mA unconfigured, 500 mA configured, 2.5 mA suspend).
  • ESD protection is mandatory for production hardware. Choose a TVS array with <1 pF capacitance for HS USB, place it directly adjacent to the connector, and route the clean (protected) side to the MCU.
  • PCB layout is not optional detail — 90 Ω ± 10% differential impedance, matched trace lengths to ±5 mil, continuous ground plane beneath the traces, and a ferrite-filtered VBUS supply are required for reliable hardware.
  • The STM32 USB peripheral requires the 48 MHz clock to be running before the pull-up is enabled, and VBUS sensing to be correctly configured for the host to properly manage power.

Next in the Series

In Part 3: Protocol & Enumeration, we ascend from the hardware layer to the protocol layer. We'll examine USB packet structure (SYNC, PID, DATA, CRC fields), the four transaction types (IN, OUT, SETUP, SOF), and — most importantly — the complete nine-step USB enumeration sequence that every device must execute correctly from the first millisecond after attach. You'll see exactly what bytes the host sends and what your device must reply with, with annotated TinyUSB code for each step.

Technology