Bogue VCM USB STM32

8

Je travaille sur un projet depuis deux semaines maintenant et le débogage de ce problème a pris toute la semaine. Vous vous demandez si quelqu'un peut m'aider, je vais essayer d'être aussi explicite et clair que possible.

J'essaie d'implémenter un port de communication virtuel USB sur un MicroController basé sur le STM32F302K8 (Cortex M4). J'ai utilisé STM32CubMX pour générer le code nécessaire à la configuration d'un périphérique USB pleine vitesse implémentant une classe CDC. Mon appareil apparaît à la fois sous Windows (Gestionnaire de périphériques) et Linux. Je suis en mesure d'implémenter une fonction d'écho simple basée sur l'exemple de code mais lorsque j'essaie maintenant d'utiliser la fonction USBD_CDC_SetTxBuffer pour envoyer des données au PC, cela déclenche un gestionnaire de pannes matérielles. J'ai réduit cela au fait que le champ UsbDeviceFS.pClass (qui est requis par USBD_CDC_SetTxBuffer) n'est jamais initialisé car USBD_CDC_Init () n'est jamais appelé dans l'initialisation du périphérique USB.

J'ai implémenté des correctifs pour plusieurs bogues (y compris la modification de la taille du segment de mémoire , la correction de l'indicateur de transmission dans USBD_CDC_TransmitPacket et la modification de la taille de CDC_DATA_HS_MAX_PACKET_SIZE à 256 contre 512) dans l'exemple de code tel que documenté sur le forum ST mais toujours avec la même erreur.

Le code de configuration de mon appareil est

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

}
Galaxie
la source
Cela fait un moment que je n'ai pas travaillé pour la dernière fois avec USB sur une STM, mais je pense que USBD_CDC_Init () essaie de faire un malloc. Le problème était qu'il n'y a pas assez d'espace sur le tas dans la configuration par défaut et que vous devez l'augmenter.
brhans
Salut, j'ai augmenté la taille du tas à 0x600 et rien ne se passe. Quelle fonction appelle malloc parce que lorsque j'y mets un point d'arrêt, il semble qu'il ne soit jamais appelé.
Galaxy

Réponses:

6

Pour répondre à ma propre question, le problème est que mon code n'a pas attendu l'USB pour terminer l'initialisation et a immédiatement commencé à envoyer des données. L'insertion d'une attente active sur un booléen ou l'ajout d'un délai (comme souligné par @ramez) résout le problème.

MISE À JOUR Ce bogue a été corrigé dans les versions ultérieures du pilote CDC USB de ST. Il y a maintenant un HAL_Delay dans la configuration. Attention, si pour une raison quelconque Sys_Tick ne fonctionne pas / est désactivé / pas encore initialisé, votre code se bloque.

Galaxie
la source
1
Oui, vous devez poster ceci comme une question distincte. Ne conservez dans cette réponse que les informations pertinentes pour la question d'origine.
m.Alin
2

J'ai utilisé CubeMX pour générer du code pour la découverte STM32F4. Je l'ai utilisé comme port COM virtuel comme vous. Je n'ai pas utilisé directement la fonction USBD_CDC_SetTxBuffer () . Dans le fichier usbd_cdc_if.c , il y a une fonction nommée CDC_Transmit_FS () . Il y avait un bug dans le code généré, la fonction a pris un tampon en paramètre et n'a rien fait avec. Le code de fonction corrigé est le suivant:

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 fait, j'ai dû ajouter le memcpy au code. Après cette correction, j'ai pu envoyer des données du microcontrôleur au PC avec cette fonction de transmission. Par exemple:

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

L'initialisation dans MX_USB_DEVICE_Init () est la même chez moi que la vôtre.

tenkmilan
la source
1
Merci ramez. J'ai trouvé le problème, j'ai dû tester si le port de communication virtuel avait terminé l'initialisation, j'ai utilisé un booléen dans CDC_Init_FS que la boucle principale attendait pour être vrai avant d'appeler CDC_Transmit_FS. Je pense que le HAL_DELAY dans votre code produit le même effet. Merci pour l'aide.
Galaxy
1

Vérifiez d'abord si hUsbDevice_0 est nul (élément manquant dans votre solution):

    if (hUsbDevice_0 == NULL)
            return USBD_FAIL;

Cela empêchera de suspendre votre uC et n'a pas besoin d'attendre trop longtemps.

Vous pouvez le placer quelque part dans 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
la source
0

J'ai eu le même problème mais il s'est avéré que la seule chose que je devais faire était de rebrancher la connexion USB à l'ordinateur. La plupart du temps, vous flashez le code et réinitialisez le microcontrôleur, mais du côté PC, l'énumération n'est pas mise à jour. USBD_CDC_Init est appelé lorsque l'hôte commence à sonder votre appareil et c'est pourquoi pClassData est NULL.

Yuanyi Wu
la source
1
Vous pouvez également forcer la réénumération dans le logiciel. Le deuxième moyen le plus stupide après le re-branchement est de désactiver / activer votre port dans le gestionnaire de périphériques, si vous n'avez pas de pilote personnalisé qui gère cela de manière plus sophistiquée
Stiebrs