Hola a todos,
Estoy depurando un problema intermitente con USB CDC en una placa de desarrollo STM32F103C8T6. Después de despertar desde el modo de parada, la computadora a veces pierde el puerto serial virtual (no se vuelve a enumerar a menos que se haga un reinicio forzado). Espero que puedan ayudarme a revisar si mi secuencia de inicialización de relojes/USB es adecuada, y si existen soluciones verificadas.
Hardware y componentes
- MCU: STM32F103C8T6, operando a 72MHz mediante PLL multiplicado por 9 desde un HSE de 8MHz.
- Placa: Diseño “Blue Pill” (pequeña placa azul); LDO convierte 5V a 3.3V, capacitores de desacoplamiento de 0.1µF+1µF cerca del pin VDD, cristal HC-49 de 8MHz con capacitores de carga de 22pF.
- USB: Dispositivo de velocidad completa, D+ tiene una resistencia de pull-up de 1.5kΩ a 3.3V; líneas D+/D- con resistencias en serie de 22Ω.
Síntomas del fallo
- Al primer encendido: USB CDC se enumera correctamente en Windows 10 y Ubuntu 22.
- Después de despertar tras 5-30 segundos en modo de parada, el host a veces no reconoce el dispositivo CDC (sin eventos de nuevo PID/VID, el puerto serial desaparece). Reconectar el cable USB no siempre funciona, pero presionar el pin de reinicio NRST siempre lo recupera. Tasa de reproducción aproximada: 10%-30%.
Acciones intentadas
- Después de despertar del modo de parada, reactivar HSE/PLL y reiniciar el reloj USB.
- Alternar el reloj del periférico USB y ejecutar la secuencia USBD_DeInit() → USBD_Init().
- Asegurar la llamada a SystemCoreClockUpdate() después del cambio de reloj.
- Añadir retardos de 1-10ms entre los pasos de inicialización de RCC y USB.
- Medir rizado de la fuente de 3.3V con osciloscopio: durante el despertar el rizado es <20mVpp; D+ en estado inactivo muestra ~3.3V.
Secuencia de configuración de reloj/RCC (biblioteca HAL)
// Al despertar del modo de parada: volver a habilitar HSE/PLL y cambiar SYSCLK de vuelta al reloj 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();
Fragmento de código para reinicialización USB
// Reiniciar completamente la pila del dispositivo después de que el reloj se estabilice
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);
Resultados observados
- Si se salta el modo de parada y solo se cambia entre modo de ejecución ↔ modo de espera, el sistema es estable.
- Al mantener SYSCLK en HSI (sin activar PLL) después del despertar, el sistema parece más estable, pero necesito el reloj de 72MHz para cumplir requisitos temporales.
- Forzar D+ a nivel bajo durante ~10ms mediante GPIO (simulando desconexión) mejora la probabilidad de recuperación, pero no garantiza el 100%.
Preguntas específicas
- ¿Existe una secuencia estándar de habilitación/temporización (HSE→PLL→USBFS) después del despertar desde stop mode en chips F103 para evitar anomalías en CDC?
- ¿Es una práctica recomendada en la serie F1 forzar un “desconexión suave” USB (poner D+ a nivel bajo) después del despertar, o hay mejores métodos de reinicio a nivel de protocolo?
- ¿Hay erratas conocidas relacionadas con la interacción entre inicio de HSE + bloqueo de PLL y la señal SOF (señal de sincronización de trama) o dominio de reloj de 48MHz después de stop mode?
- ¿Se recomienda usar HSI temporalmente antes de estabilizar PLL al recuperar el reloj USB, o siempre priorizar estabilizar PLL primero?
- ¿Han encontrado problemas en el diseño de la placa que podrían causar esto: tolerancia de resistencia D+, diodos ESD/fugas, carga excesiva en el cristal, respuesta transitoria deficiente en LDO, etc.?