STM32F4 USB VCP, PC recibe todo 0x00

Soy un principiante en STM32F4 y estoy aprendiendo a usar el puerto COM virtual USB ("VCP") para transmitir datos desde el microcontrolador a una PC.

El puerto virtual se detecta como "Puerto COM virtual de STMicroelectronics", y utilizo un software de monitoreo en serie para ver los datos recibidos por la PC.

La PC está recibiendo todos los 0x00 sin importar lo que envíe en mi código.

Llamé a la función VCP_DataTx() para enviar datos.

¿Alguna idea sobre lo que está mal?

ps en mi función principal (), solo llamé a USBD_Init () para inicializar el dispositivo USB, ¿es eso suficiente? ¿Me perdí algo que debería configurarse? Veo que alguien dice USART cuando habla de VCP, ¿hay alguna relación entre ellos?

Gracias.

Este es mi main.cpp. No hice nada más que inicializar el dispositivo USB y enviar datos.

#include "usbd_cdc_core.h"
#include "usbd_usr.h"
#include "usb_conf.h"
#include "usbd_desc.h"

#include "usbd_cdc_vcp.h"

USB_OTG_CORE_HANDLE    USB_OTG_dev;
uint8_t Buf[6] = "A";

int main(void)
{
  __IO uint32_t i = 0;  

  USBD_Init(&USB_OTG_dev,         
            USB_OTG_FS_CORE_ID,
            &USR_desc, 
            &USBD_CDC_cb, 
            &USR_cb);

    VCP_DataTx(Buf, 6);

  /* Main loop */
  while (1)
  {
      VCP_DataTx(Buf, 6);
      while (i < 0x77ffff)
      {
          i++;
      }
  }
} 

Para llamar a VCP_DataTx() en main, eliminé la palabra clave estática en usbd_cdc_vcp.h y usbd_cdc.vcp.c

pps No me di cuenta de que usbd_cdc_vcp.c no está en la biblioteca USB de STM. Viene del ejemplo de VCP en STM32_USB-Host-Device_Lib_V2.1.0, y la función VCP_DataTx() se ve así:

uint16_t VCP_DataTx (uint8_t* Buf, uint32_t Len)
{
  if (linecoding.datatype == 7)
  {
    APP_Rx_Buffer[APP_Rx_ptr_in] = USART_ReceiveData(EVAL_COM1) & 0x7F;
  }
  else if (linecoding.datatype == 8)
  {
    APP_Rx_Buffer[APP_Rx_ptr_in] = USART_ReceiveData(EVAL_COM1);
  }

  APP_Rx_ptr_in++;

  /* To avoid buffer overflow */
  if(APP_Rx_ptr_in == APP_RX_DATA_SIZE)
  {
    APP_Rx_ptr_in = 0;
  }  

  return USBD_OK;
}
¿Recibes el número "correcto" de 0x00? Es decir, si intenta enviar 5 bytes, ¿recibe 5 bytes cero?
Muestra tu parte del código donde llamas a VCP_DataTX()
@bitsmack: sí, el número es correcto. Pero solo es correcto con las veces que llamo a VCP_DataTx(). Si llamo a esa función 10 veces y transmito 6 bytes cada vez que la llamo, obtengo 10 0x00 en lugar de 60.
Su función "uint16_t VCP_DataTx (uint8_t* Buf, uint32_t Len)" no usa Buf ni Len.
@Tut: Sí, no me di cuenta de que esta función no usa Buf ni Len. Pensé que era un ejemplo oficial, pero ignoré que los datos provienen de USART, no de Buf.

Respuestas (1)

Estoy usando la biblioteca ST USB para un microcontrolador ST ARM diferente (STM32F105), pero la estructura se ve igual. Yo también he basado mi código en el ejemplo de VCP.

Primero, se requiere una inicialización adicional para que el USB funcione. La siguiente es una lista de cosas para verificar. Es posible que desee ajustar algunos de estos ejemplos para que funcionen con su microcontrolador:

  1. Necesitas haber habilitado la OTG_FS_IRQHandlerinterrupción:

    NVIC_InitStructure.NVIC_IRQChannel = OTG_FS_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 7;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    

    Lo siguiente está en mi archivo de vector de interrupción:

    #include "usb_core.h"
    #include "usbd_core.h"
    #include "usbd_cdc_core.h"
    
    extern USB_OTG_CORE_HANDLE USB_OTG_dev;
    extern uint32_t USBD_OTG_ISR_Handler (USB_OTG_CORE_HANDLE *pdev);
    
    void OTG_FS_IRQHandler(void)
    {
        USBD_OTG_ISR_Handler (&USB_OTG_dev);
    } // end OTG_FS_IRQHandler()
    
  2. Debe seleccionar y habilitar una fuente de reloj de 48 MHz para el modelo OTG/USB antes de llamar USBD_Init. En mi caso, esto se obtuvo dividiendo el PLLVCO de 144 MHz por 3. El árbol del reloj puede ser complicado; asegúrese de comprender esa sección del Manual de referencia.

    // Configure USB Clock Source
    RCC_OTGFSCLKConfig(RCC_OTGFSCLKSource_PLLVCO_Div3);
    
    // Enable USB Clock
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_OTG_FS, ENABLE);
    
  3. En la Biblioteca USB está el usb_conf.harchivo. Esta es una maraña de definiciones condicionales. Asegúrese de que estos se estén definiendo (si son apropiados para su aplicación):

    #define USE_USB_OTG_FS
    #define USB_OTG_FS_CORE
    #define USE_EMBEDDED_PHY
    #define VBUS_SENSING_ENABLED
    #define USE_DEVICE_MODE
    

A continuación, como señaló @Tut en los comentarios, su VCP_DataTXfunción necesita modificaciones. Actualmente está utilizando el periférico USART como fuente de datos USB. Desea cambiarlo para que use Bufy Len. Aunque la llamada a la función incluye los argumentos Bufy Len, en realidad no se usan en la función.

Los VCP_DataTxdatos de relleno, un byte a la vez, en la APP_Rx_Buffermatriz. Cada vez que escribe un byte en la matriz, también incrementa el APP_Rx_ptr_invalor. Este búfer es revisado y procesado regularmente por el código de la biblioteca OTG/USB.

Mi función se ve así:

uint16_t VCP_DataTx(uint8_t *Buf, uint32_t Len)
{
    uint32_t i;

    // Put the data into the buffer. It will be processed by the USB stack.
    for (i=0; i<Len; i++)
    {
        // Add a byte to the buffer
        APP_Rx_Buffer[APP_Rx_ptr_in] = Buf[i];

        // Update the circular buffer index
        APP_Rx_ptr_in++;

        // Loop the index if necessary
        if (APP_Rx_ptr_in == APP_RX_DATA_SIZE)
        {
            APP_Rx_ptr_in = 0;
        }
    }
    return USB_SUCCESS;
}

Finalmente, hay algunos otros problemas en su código. Espero que esté al tanto de algunos de estos, pero los enumeraré por si acaso:

  1. La instrucción uint8_t Buf[6] = "A";solo inicializa el primer valor en 'A'. Los cinco valores restantes son '\0'. Consulte aquí para obtener más información.

  2. Cuando la variable del contador iexcede su límite de demora, debe volver a cero. Esto podría ser un problema principal . Actualmente, cuando el retraso finaliza la primera vez, nunca vuelve a retrasarse. El whilebucle exterior comienza a llamar VCP_DataTx(Buf, 6);continuamente. Esto desbordará el búfer USB y provocará todo tipo de problemas.

  3. Una vez que solucione el problema de la demora, seguirá recibiendo dos llamadas consecutivas VCP_DataTx(Buf, 6);sin demoras. Una vez antes del bucle de retraso e inmediatamente antes del primer retraso. Esto no debería causar un problema, pero quería señalarlo.


FYI, si solo está tratando de enviar datos de un lado a otro a una PC a través de USB, entonces no necesita habilitar ninguna funcionalidad USART en el microcontrolador. El ejemplo de VCP usa el USART como fuente de datos (y destino), pero no está tratando de hacer eso. Su fuente de datos es su Buf[]matriz.

Solo usé la función como un ejemplo oficial pero ignoré lo que realmente hizo. También gracias por sus tres problemas, es posible que haya cometido más errores debido a ellos.
Genial, @AlexanderZhang, encantado de ayudar :)