Hello everyone,
I’m debugging an intermittent USB CDC issue on an STM32F103C8T6 development board after waking from stop mode. After waking, the computer sometimes loses the virtual serial port (it won’t re-enumerate unless a hard reset is performed). I’d appreciate help checking whether my clock/USB initialization sequence is reasonable, and whether there are proven solutions.
Hardware and Components
- MCU: STM32F103C8T6 running at 72MHz (8MHz HSE multiplied by 9 through PLL).
- Board: “Blue Pill” form factor; LDO converts 5V to 3.3V, with 0.1µF + 1µF decoupling capacitors near VDD pins, 8MHz HC-49 crystal with 22pF load capacitors.
- USB: Full-speed device, D+ pulled up to 3.3V through a 1.5kΩ resistor; D+/D- lines have 22Ω series resistors.
Problem Symptoms
- First power-on: USB CDC enumerates normally on both Windows 10 and Ubuntu 22.
- After waking from stop mode (after ~5-30 seconds), the host sometimes fails to recognize the CDC device (no new PID/VID events, serial port disappears). USB cable replugging may not work, but pressing the NRST reset pin always recovers. Reproducibility rate ~10%-30%.
Tried Solutions
- Re-enable HSE/PLL after waking from stop mode, then restart USB clock.
- Switch USB peripheral clock and execute USBD_DeInit() → USBD_Init() sequence.
- Ensure SystemCoreClockUpdate() is called after clock switching.
- Add 1-10ms delay between RCC and USB initialization steps.
- Oscilloscope measurement of 3.3V power ripple: <20mVpp during wake-up; D+ idle state ~3.3V.
Clock/RCC Configuration Sequence (HAL Library)
// Wake from stop mode: re-enable HSE/PLL and switch SYSCLK back to PLL
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
HAL_RCC_OscConfig(&(RCC_OscInitTypeDef){
.OscillatorType = RCC_OSCILLATORTYPE_HSE,
.HSEState = RCC_HSE_ON,
.PLL.PLLState = RCC_PLL_ON,
.PLL.PLLSource = RCC_PLLSOURCE_HSE,
.PLL.PLLMUL = RCC_PLL_MUL9
});
HAL_RCC_ClockConfig(&(RCC_ClkInitTypeDef){
.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2,
.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK,
.AHBCLKDivider = RCC_SYSCLK_DIV1,
.APB1CLKDivider = RCC_HCLK_DIV2,
.APB2CLKDivider = RCC_HCLK_DIV1
}, FLASH_LATENCY_2);
SystemCoreClockUpdate();
USB Reinitialization Code Snippet
// Fully restart device stack after clock stabilization
USBD_DeInit(&hUsbDeviceFS);
__HAL_RCC_USB_FORCE_RESET();
HAL_Delay(2);
__HAL_RCC_USB_RELEASE_RESET();
__HAL_RCC_USB_CLK_ENABLE();
USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS);
USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC);
USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS);
USBD_Start(&hUsbDeviceFS);
Observations
- System remains stable if stop mode is skipped (switching only between run/sleep modes).
- Stability improves when keeping SYSCLK at HSI (without PLL) after wake-up, but I need 72MHz for timing requirements.
- Pulling D+ low for ~10ms via GPIO (simulating disconnection) improves recovery probability but not 100% reliable.
Questions
- For F103 chips, is there a standard enable sequence/timing (HSE→PLL→USBFS) after waking from stop mode to avoid CDC device anomalies?
- Is forcing USB “soft disconnect” (pulling D+ low) considered best practice for F1 series, or are there better protocol stack-level reset methods?
- Are there known errata about HSE startup + PLL lock affecting USB SOF (frame synchronization) or 48MHz clock domain after stop mode?
- Recommended practice: Should USB clock recovery first use HSI then switch to PLL, or prioritize PLL stabilization first?
- What board-level issues might cause this: D+ resistor tolerance, ESD diode/leakage, crystal load capacitance issues, LDO transient response problems?