STM32F070: conexión USB controlada por firmware y activación HSE

Estoy desarrollando firmware para un dispositivo USB 2.0 Full Speed ​​de baja potencia (12 Mbps) que utiliza un microcontrolador STM32F070CB . La fuente de reloj para el módulo USB será el oscilador externo de alta velocidad (HSE). Estoy usando STM32CubeMX con la versión 1.7.0 de STM32CubeF0 para generar el código base.

Para conservar nuestro presupuesto de energía, debemos apagar el HSE cuando el USB no está conectado. Estoy pensando que deberíamos hacer que el firmware retrase la detección de USB por parte del host hasta que el dispositivo esté listo, para que los eventos en el firmware sean más o menos así:

  • Evento - Detectar conexión USB física
    • Habilitar HSE
    • Inicializar USB
    • Connect Data+ pull-up ( DPPU) para activar la enumeración USB por parte del host
  • Evento - Detectar desconexión USB física
    • Desconectar DPPU(simular la desconexión física del host)
    • Desinicializar USB
    • Deshabilitar HSE (unidad PF0-OSC_INbaja)

Preguntas

  1. ¿Es lo anterior la forma correcta de hacerlo? ¿Todas las acciones son necesarias? ¿Están en el orden correcto?

  2. ¿ Necesito llamar a alguna función además USBD_DeInit()de desactivar el USB?

  3. ¿Cómo puedo hacer que el dispositivo parezca desconectado en el host mientras está físicamente conectado? (es decir, debería desaparecer del Administrador de dispositivos de Windows). ¿Por qué las llamadas no HAL_PCD_DevDisconnect()hacen que eso suceda?

Detalles

En los siguientes párrafos, "conectar físicamente" significa conectar el cable USB al dispositivo y la PC host.

Esperaría que todas las llamadas MX_USB_DEVICE_Init()tuvieran MX_USB_DEVICE_DeInit()efecto de inmediato, es decir, que vería aparecer/desaparecer el dispositivo en el Administrador de dispositivos de Windows si se llamó a la función mientras el dispositivo está conectado físicamente. Sin embargo, he observado esto solo en la primera llamada a MX_USB_DEVICE_Init(). Todas las llamadas a MX_USB_DEVICE_DeInit()y las llamadas subsiguientes a MX_USB_DEVICE_Init()no hacen que el dispositivo aparezca o desaparezca del Administrador de dispositivos de Windows hasta después de la reconexión física. (es decir, si está conectado, cuando se llama a la función, no hay cambios en el Administrador de dispositivos hasta después de desconectar/reconectar).

Código

Según lo generado por STM32CubeMX:

/* USB Device Core handle declaration */
USBD_HandleTypeDef hUsbDeviceFS;

/* init function */                     
void MX_USB_DEVICE_Init(void)
{
  /* Init Device Library,Add Supported Class and Start the library*/
  USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS);

  USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC);

  USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS);

  USBD_Start(&hUsbDeviceFS);
}

Yo creé:

void MX_USB_DEVICE_DeInit(void)
{
   HAL_PCD_DevDisconnect((PCD_HandleTypeDef *)&hUsbDeviceFS.pData);
   USBD_Stop  (&hUsbDeviceFS);
   USBD_DeInit(&hUsbDeviceFS);
}

No importa si llamo o cuándo HAL_PCD_DevDisconnect(). Nunca he observado que el dispositivo desaparezca del Administrador de dispositivos de Windows mientras está conectado físicamente.

Respuestas (1)

  1. ¿Cómo puedo hacer que el dispositivo parezca desconectado en el host mientras está físicamente conectado? (es decir, debería desaparecer del Administrador de dispositivos de Windows). ¿Por qué las llamadas no HAL_PCD_DevDisconnect()hacen que eso suceda?

Llamar HAL_PCD_DevDisconnect()con los parámetros adecuados desconecta DPPU, por lo que el dispositivo desaparece del Administrador de dispositivos de Windows. El error en la pregunta es que en MX_USB_DEVICE_DeInit(),

HAL_PCD_DevDisconnect((PCD_HandleTypeDef *)&hUsbDeviceFS.pData);

debiera ser

HAL_PCD_DevDisconnect((PCD_HandleTypeDef *)hUsbDeviceFS.pData);

(sin el operador de dirección &).

Aquí hay una versión revisada de la función USB de-init:

void MX_USB_DEVICE_DeInit(void)
{
   PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef *)hUsbDeviceFS.pData;

   if (hpcd != NULL)
   {
      HAL_PCD_DevDisconnect(hpcd);
      USBD_DeInit(&hUsbDeviceFS);
   }
}
  1. ¿Es lo anterior la forma correcta de hacerlo? ¿Todas las acciones son necesarias? ¿Están en el orden correcto?

Cerca. Hay más en la configuración del reloj que simplemente activar o desactivar HSE.

STM32CubeMX genera SystemClock_Config(). Puede usarlo como modelo para los pasos "Configurar los relojes del sistema" en la lista a continuación.

  • Evento - Detectar conexión USB física
    • Configurar los relojes del sistema
      • Habilitar HSE
      • Activar PLL
      • Establecer SYSCLKSOURCEenPLLCLK
      • Establecer UsbClockSelectionen PLL
      • Configurar palo de sistema
    • Inicializar USB y conectar Data+ pull-up ( DPPU) para activar la enumeración de USB por host - MX_USB_DEVICE_Init()hace todo esto
  • Evento - Detectar desconexión USB física
    • Desconectar DPPU( HAL_PCD_DevDisconnect())
    • Desinicializar USB ( USBD_DeInit())
    • Configure los relojes del sistema (tenga en cuenta muchos pasos en orden inverso al anterior)
      • Apague el periférico USB
      • Cambiar sysclk de nuevo a HSI
      • Deshabilite HSE (no estoy seguro si PF0-OSC_INes necesario conducir bajo)
      • Desactivar PLL
      • Configurar palo de sistema
  1. ¿ Necesito llamar a alguna función además USBD_DeInit()de desactivar el USB?

No, eso lo hace. Explore las pilas de llamadas y encontrará que USBD_DeInit()llama todo lo que USBD_Stop()hace y más.