Błąd STM32 USB VCP

8

Pracuję nad projektem przez ostatnie dwa tygodnie i debugowanie tego jednego problemu zajęło cały tydzień. Zastanawiam się, czy ktokolwiek może pomóc, postaram się wyrazić jak najlepiej.

Usiłuję zaimplementować port USB Virtual Comm na mikrokontrolerze opartym na STM32F302K8 (Cortex M4). Użyłem STM32CubMX do wygenerowania kodu potrzebnego do skonfigurowania urządzenia USB Full Speed ​​USB implementującego klasę CDC. Moje urządzenie wyświetla się zarówno w systemie Windows (Menedżer urządzeń), jak i Linux. Jestem w stanie zaimplementować prostą funkcję echa opartą na przykładowym kodzie, ale kiedy teraz próbuję użyć funkcji USBD_CDC_SetTxBuffer do wysyłania danych do komputera, uruchamia się Hard Fault Handler. Zawęziłem to do faktu, że pole UsbDeviceFS.pClass (które jest wymagane przez USBD_CDC_SetTxBuffer) nigdy nie jest inicjalizowane, ponieważ USBD_CDC_Init () nigdy nie jest wywoływane podczas inicjalizacji urządzenia USB.

Zaimplementowałem poprawki do kilku błędów (w tym zmianę wielkości sterty, naprawienie flagi transmisji w USBD_CDC_TransmitPacket i zmianę rozmiaru CDC_DATA_HS_MAX_PACKET_SIZE na 256 z 512) w przykładowym kodzie, jak udokumentowano na forum ST, ale wciąż otrzymuję ten sam błąd.

Mój kod konfiguracji urządzenia to

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

}
Galaktyka
źródło
Minęło trochę czasu, odkąd ostatnio pracowałem z USB na STM, ale myślę, że USBD_CDC_Init () próbuje zrobić Malloc. Problem polegał na tym, że w domyślnej konfiguracji nie ma wystarczającej ilości miejsca na stercie i należy ją zwiększyć.
brhans
Cześć, zwiększyłem rozmiar sterty do 0x600 i nic się nie dzieje. Która funkcja wywołuje malloc, ponieważ kiedy umieszczam na niej punkt przerwania, wydaje się, że nigdy nie jest wywoływana.
Galaxy

Odpowiedzi:

6

Aby odpowiedzieć na moje pytanie, problem polega na tym, że mój kod nie czekał na zakończenie inicjalizacji USB i natychmiast zaczął wysyłać dane. Wstawienie aktywnego oczekiwania na wartość logiczną lub dodanie opóźnienia (jak wskazał @ramez) rozwiązuje problem.

AKTUALIZACJA Ten błąd został naprawiony w kolejnych wersjach sterownika CDC USB od ST. W konfiguracji jest teraz HAL_Delay. Zastrzeżenie polega na tym, że jeśli z jakiegokolwiek powodu Sys_Tick nie działa / jest dezaktywowany / jeszcze nie zainicjowany, kod się zawiesi.

Galaktyka
źródło
1
Tak, powinieneś opublikować to jako osobne pytanie. Zachowaj w tej odpowiedzi tylko informacje istotne dla pierwotnego pytania.
m.Alin
2

Użyłem CubeMX do wygenerowania kodu do wykrywania STM32F4. Użyłem go jako wirtualnego portu COM tak jak ty. Nie korzystałem bezpośrednio z funkcji USBD_CDC_SetTxBuffer () . W pliku usbd_cdc_if.c znajduje się funkcja o nazwie CDC_Transmit_FS () . W wygenerowanym kodzie był błąd, funkcja przyjęła bufor jako parametr i nic z tym nie zrobiła. Poprawiony kod funkcji jest następujący:

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

Właściwie musiałem dodać memcpy do kodu. Po tej korekcie mogłem przesłać dane z mikrokotrolera do komputera z tą funkcją transmisji. Na przykład:

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

Inicjalizacja w MX_USB_DEVICE_Init () jest dla mnie taka sama jak twoja.

tenkmilan
źródło
1
Dziękuję Ramez. Znalazłem problem, musiałem sprawdzić, czy wirtualny port komunikacyjny zakończył inicjalizację, użyłem wartości logicznej w CDC_Init_FS, którą główna pętla czekała na prawdziwość przed wywołaniem CDC_Transmit_FS. Myślę, że HAL_DELAY w twoim kodzie osiąga ten sam efekt. Dziękuję za pomoc.
Galaxy
1

Najpierw sprawdź, czy hUsbDevice_0 ma wartość NULL (brak elementu w twoim rozwiązaniu):

    if (hUsbDevice_0 == NULL)
            return USBD_FAIL;

Zapobiegnie to zawieszeniu twojego komputera i nie będzie wymagało zajętego oczekiwania w opóźnieniu.

Możesz umieścić go gdzieś w 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
źródło
0

Miałem ten sam problem, ale okazało się, że jedyne, co muszę zrobić, to ponownie podłączyć połączenie USB do komputera. Najczęściej flashujesz kod i resetujesz mikrokontroler, ale po stronie komputera wyliczenie nie jest aktualizowane. USBD_CDC_Init jest wywoływany, gdy host zaczyna sondować twoje urządzenie i dlatego pClassData ma wartość NULL.

Yuanyi Wu
źródło
1
Możesz również wymusić ponowne wyliczenie w oprogramowaniu. Drugi najgłupszy sposób po ponownym podłączeniu to wyłączenie / włączenie portu w menedżerze urządzeń, jeśli nie masz niestandardowego sterownika obsługującego to w bardziej fantazyjny sposób
stiebrs