STM32F4 USB VCP, PC recibe todos los 0x00

4

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

El puerto virtual se detecta como "Puerto COM virtual de STMicroelectronics", y uso 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?

p.s. en mi función principal (), solo llamé a USBD_Init () para inicializar el dispositivo USB, ¿es eso suficiente? ¿Me perdí algo que debería estar configurado? Veo a alguien decir USART cuando se 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 static en usbd_cdc_vcp.h y usbd_cdc.vcp.c

p.p.s. 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 parece a:

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;
}
    
pregunta Alexander Zhang

1 respuesta

4

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

Primero, se requiere una inicialización adicional para que funcione el USB. A continuación hay una lista de cosas para verificar. Quizás deba ajustar algunos de estos ejemplos para que funcionen con su microcontrolador:

  1. Debe haber habilitado la interrupción OTG_FS_IRQHandler :

    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 a USBD_Init . En mi caso, esto se derivó dividiendo el PLLVCO de 144 MHz por 3. El árbol del reloj puede ser complicado; Asegúrate de que entiendes 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 archivo usb_conf.h . Esta es una maraña de definiciones condicionales. Asegúrese de que estos se estén definiendo realmente (si son adecuados 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 @Tut señaló en los comentarios, su función VCP_DataTX necesita modificaciones. Actualmente está utilizando el periférico USART como fuente de los datos USB. Desea cambiarlo para que use Buf y Len . Aunque la llamada a la función incluye los argumentos Buf y Len , estos no se utilizan realmente en la función.

El VCP_DataTx rellena los datos, un byte a la vez, en la matriz APP_Rx_Buffer . Cada vez que escribe un byte en la matriz también incrementa el valor APP_Rx_ptr_in . Este búfer es regularmente verificado y procesado 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 conozca algunos de estos, pero los enumeraré por si acaso:

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

  2. Cuando la variable de contador i excede su límite de demora, debe volver a cero. Este podría ser un problema principal . Actualmente, cuando el retraso finaliza la primera vez, nunca más se retrasa. El bucle while externo comienza a llamar a VCP_DataTx(Buf, 6); continuamente. Esto desbordará el búfer USB y dará lugar a todo tipo de problemas.

  3. Una vez que solucione el problema de demora, todavía recibirá dos llamadas a VCP_DataTx(Buf, 6); back-to-back sin demoras. Una vez antes del bucle de retardo, e inmediatamente antes del primer retardo. Esto no debería causar un problema, pero quería señalarlo.

Para su información, si solo está intentando enviar datos de un PC a otro mediante USB, 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á intentando hacerlo. Su fuente de datos es su matriz Buf[] .

    
respondido por el bitsmack

Lea otras preguntas en las etiquetas