STM32F4 USB VCP, PC erhalten alle 0x00

Ich bin ein Anfänger in STM32F4 und lerne, wie man den USB Virtual COM Port ("VCP") verwendet, um Daten vom Mikrocontroller an einen PC zu übertragen.

Der virtuelle Port wird als "STMicroelectronics Virtual COM Port" erkannt, und ich verwende eine serielle Überwachungssoftware, um die vom PC empfangenen Daten anzuzeigen.

Der PC empfängt alle 0x00, egal was ich in meinem Code sende.

Ich habe die Funktion VCP_DataTx() aufgerufen, um Daten zu senden.

Irgendwelche Ideen, was falsch ist?

ps in meiner main()-Funktion habe ich nur USBD_Init() aufgerufen, um das USB-Gerät zu initialisieren, reicht das? Habe ich etwas übersehen, das konfiguriert werden sollte? Ich sehe jemanden, der USART sagt, wenn er über VCP spricht. Gibt es eine Beziehung zwischen ihnen?

Danke.

Das ist meine main.cpp. Ich habe nichts weiter getan, als das USB-Gerät initialisiert und Daten gesendet.

#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++;
      }
  }
} 

Um VCP_DataTx() in main aufzurufen, habe ich das statische Schlüsselwort in usbd_cdc_vcp.h und usbd_cdc.vcp.c gelöscht

pps Ich wusste nicht, dass usbd_cdc_vcp.c nicht in der STM USB-Bibliothek ist. Es stammt aus dem VCP-Beispiel in STM32_USB-Host-Device_Lib_V2.1.0, und die Funktion VCP_DataTx() sieht so aus:

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;
}
Erhalten Sie die "richtige" Anzahl von 0x00? Das heißt, wenn Sie versuchen, 5 Bytes zu senden, erhalten Sie 5 Null-Bytes?
Zeigen Sie Ihren Teil des Codes, in dem Sie VCP_DataTX() aufrufen
@bitsmack: ja, die nummer stimmt. Aber es ist nur richtig, wenn ich mal VCP_DataTx() aufrufe. Wenn ich diese Funktion 10 Mal aufrufe und bei jedem Aufruf 6 Bytes übertrage, erhalte ich 10 0x00 statt 60.
Ihre Funktion "uint16_t VCP_DataTx (uint8_t* Buf, uint32_t Len)" verwendet weder Buf noch Len.
@Tut: Ja, ich habe nicht bemerkt, dass diese Funktion weder Buf noch Len verwendet. Ich dachte, es sei ein offizielles Beispiel, ignorierte aber, dass die Daten von USART stammen, nicht von Buf.

Antworten (1)

Ich verwende die ST-USB-Bibliothek für einen anderen ST-ARM-Mikrocontroller (STM32F105), aber die Struktur sieht gleich aus. Auch ich habe meinen Code auf dem VCP-Beispiel basiert.

Zunächst ist eine zusätzliche Initialisierung erforderlich, damit der USB funktioniert. Es folgt eine Liste der Dinge, die überprüft werden müssen. Sie können einige dieser Beispiele neu anpassen, um mit Ihrem Mikrocontroller zu arbeiten:

  1. Sie müssen den OTG_FS_IRQHandlerInterrupt aktiviert haben:

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

    Folgendes ist in meiner Interrupt-Vektordatei:

    #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. Sie müssen eine 48-MHz-Taktquelle für das OTG/USB-Modell auswählen und aktivieren, bevor Sie anrufen USBD_Init. In meinem Fall wurde dies abgeleitet, indem der 144-MHz-PLLVCO durch 3 dividiert wurde. Der Taktbaum kann schwierig sein; Stellen Sie sicher, dass Sie diesen Abschnitt des Referenzhandbuchs verstanden haben.

    // Configure USB Clock Source
    RCC_OTGFSCLKConfig(RCC_OTGFSCLKSource_PLLVCO_Div3);
    
    // Enable USB Clock
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_OTG_FS, ENABLE);
    
  3. In der USB-Bibliothek ist die usb_conf.hDatei. Dies ist ein Gewirr von bedingten Definitionen. Stellen Sie sicher, dass diese tatsächlich definiert werden (falls sie für Ihre Anwendung geeignet sind):

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

Als nächstes muss, wie @Tut in den Kommentaren betonte, Ihre VCP_DataTXFunktion geändert werden. Es verwendet derzeit das USART-Peripheriegerät als Quelle der USB-Daten. Sie möchten es so ändern, dass es Bufund verwendet Len. Obwohl der Funktionsaufruf die Argumente Bufund enthält Len, werden diese nicht wirklich in der Funktion verwendet.

Der VCP_DataTxstopft Daten, ein Byte nach dem anderen, in das APP_Rx_BufferArray. Jedes Mal, wenn es ein Byte in das Array schreibt, erhöht es auch den APP_Rx_ptr_inWert. Dieser Puffer wird regelmäßig vom Code der OTG/USB-Bibliothek überprüft und verarbeitet.

Meine Funktion sieht so aus:

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;
}

Schließlich gibt es noch ein paar andere Probleme in Ihrem Code. Ich nehme an, Sie kennen einige davon, aber ich werde sie nur für den Fall auflisten:

  1. Die Anweisung uint8_t Buf[6] = "A";initialisiert nur den ersten Wert auf 'A'. Die restlichen fünf Werte sind '\0'. Weitere Informationen finden Sie hier .

  2. Wenn die Zählervariable iIhre Verzögerungsgrenze überschreitet, sollte sie auf Null zurückgesetzt werden. Dies könnte ein primäres Problem sein . Wenn die Verzögerung das erste Mal endet, verzögert sie sich derzeit nie wieder. Die äußere whileSchleife beginnt VCP_DataTx(Buf, 6);kontinuierlich zu rufen. Dies wird den USB-Puffer überlaufen lassen und zu allen möglichen Problemen führen.

  3. Sobald Sie das Verzögerungsproblem behoben haben, erhalten Sie immer noch zwei Anrufe hintereinander VCP_DataTx(Buf, 6);ohne Verzögerungen. Einmal vor der Verzögerungsschleife und sofort noch einmal vor der ersten Verzögerung. Dies sollte kein Problem darstellen, aber ich wollte darauf hinweisen.


Zu Ihrer Information, wenn Sie nur versuchen, Daten über USB an einen PC hin und her zu senden, müssen Sie keine USART-Funktionalität im Mikrocontroller aktivieren. Das VCP-Beispiel verwendet den USART als Datenquelle (und Ziel), aber das versuchen Sie nicht. Ihre Datenquelle ist Ihr Buf[]Array.

Ich habe die Funktion nur als offizielles Beispiel verwendet, aber ignoriert, was sie tatsächlich tat. Vielen Dank auch für Ihre drei Probleme, ich habe möglicherweise mehr Fehler aufgrund dieser gemacht.
Großartig, @AlexanderZhang, ich helfe gerne :)