Error de STM32 USB VCP

8

He estado trabajando en un proyecto durante las últimas dos semanas y la depuración de este problema ha ocupado toda esta semana. Preguntándome si alguien puede ayudar, intentaré ser lo más explícito y claro posible.

Estoy tratando de implementar un puerto de comunicación virtual USB en un microcontrolador basado en el STM32F302K8 (Cortex M4). He usado STM32CubMX para generar el código necesario para configurar un dispositivo USB de velocidad completa que implemente una clase CDC. Mi dispositivo aparece tanto en Windows (Administrador de dispositivos) como en Linux. Puedo implementar una función de eco simple basada en el código de ejemplo, pero cuando trato de usar la función USBD_CDC_SetTxBuffer para enviar datos a la PC, esto activa un controlador de fallas duras. Lo he reducido al hecho de que el campo UsbDeviceFS.pClass (que es necesario para USBD_CDC_SetTxBuffer) nunca se inicializa porque USBD_CDC_Init () nunca se llama en la inicialización del dispositivo USB.

He implementado correcciones a varios errores (incluido el cambio del tamaño del almacenamiento dinámico, la fijación de la bandera de transmisión en USBD_CDC_TransmitPacket y el cambio del tamaño de CDC_DATA_HS_MAX_PACKET_SIZE a 256 desde 512) en el código de ejemplo como se documenta en el foro ST, pero sigue obteniendo el mismo error.

El código de configuración de mi dispositivo es

* 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);

}
Galaxia
fuente
Ha pasado un tiempo desde la última vez que trabajé con USB en un STM, pero creo que USBD_CDC_Init () intenta hacer un malloc. El problema fue que no hay suficiente espacio en el montón en la configuración predeterminada y necesita aumentarlo.
Brhans
Hola, he aumentado el tamaño del montón a 0x600 y no pasa nada. Qué función llama a malloc porque cuando le pongo un punto de interrupción, parece que nunca se llama.
Galaxy

Respuestas:

6

Para responder a mi propia pregunta, el problema es que mi código no esperó a que el USB termine la inicialización e inmediatamente comenzó a enviar datos. Insertar una espera activa en un booleano o agregar un retraso (como lo señaló @ramez) resuelve el problema.

ACTUALIZACIÓN Este error se ha corregido en versiones posteriores del controlador USB CDC de ST. Ahora hay un HAL_Delay en la configuración. La advertencia es que si por alguna razón Sys_Tick no funciona / está desactivado / aún no se ha inicializado, su código se bloqueará.

Galaxia
fuente
1
Sí, debe publicar esto como una pregunta separada. Mantenga en esta respuesta solo la información relevante para la pregunta original.
m.Alin
2

Usé CubeMX para generar código para el descubrimiento de STM32F4. Lo usé como puerto COM virtual como tú. No utilicé la función USBD_CDC_SetTxBuffer () directamente. En el archivo usbd_cdc_if.c hay una función llamada CDC_Transmit_FS () . Hubo un error en el código generado, la función tomó un búfer como parámetro y no hizo nada con él. El código de función corregido es el siguiente:

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  memcpy(UserTxBufferFS, Buf, sizeof(char) * Len);
  USBD_CDC_SetTxBuffer(hUsbDevice_0, UserTxBufferFS, Len);   
  result = USBD_CDC_TransmitPacket(hUsbDevice_0);
  return result;
}

En realidad, tuve que agregar la memoria al código. Después de esta corrección, podría enviar datos desde el microcotroller a la PC con esta función de transmisión. Por ejemplo:

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_USB_DEVICE_Init();
  configureGPIOs();

  uint8_t Buf[] = "Test";

  HAL_Delay(1000);

  while (1)
  {
      CDC_Transmit_FS(Buf, 4);
      HAL_Delay(1000);
  }
}

La inicialización en MX_USB_DEVICE_Init () es la misma para mí que la tuya.

diezkmilan
fuente
1
Gracias ramez. Encontré el problema, tuve que probar si el puerto de comunicación virtual había finalizado la inicialización, utilicé un booleano en CDC_Init_FS que el bucle principal esperaba para ser verdadero antes de llamar a CDC_Transmit_FS. Creo que HAL_DELAY en su código logra el mismo efecto. Gracias por la ayuda.
Galaxy
1

Primero, verifique si hUsbDevice_0 es nulo (falta un elemento en su solución):

    if (hUsbDevice_0 == NULL)
            return USBD_FAIL;

Esto evitará que cuelgue su uC y no necesita estar ocupado esperando con demoras.

Puede colocarlo en algún lugar en CDC_Transmit_FS:

USBD_StatusTypeDef CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) {

    if (hUsbDevice_0 == NULL)
        return USBD_FAIL;

    USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) hUsbDevice_0->pClassData;

    if (hcdc->TxState != 0)
        return USBD_BUSY;

    uint8_t result = USBD_OK;

    USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf, Len);
    result = USBD_CDC_TransmitPacket(hUsbDevice_0);

    return result;
}
jemdream
fuente
0

Tuve el mismo problema, pero resultó que lo único que tenía que hacer era volver a enchufar la conexión USB a la computadora. La mayoría de las veces, actualiza el código y reinicia el microcontrolador, pero en el lado de la PC, la enumeración no se actualiza. Se llama a USBD_CDC_Init cuando el host comienza a sondear su dispositivo y es por eso que pClassData es NULL.

Yuanyi Wu
fuente
1
También puede forzar la reenumeración en el software. La segunda forma más tonta después de volver a enchufar es deshabilitar / habilitar su puerto en el administrador de dispositivos, si no tiene un controlador personalizado que maneje esto de una manera más elegante
stiebrs