Et si on parlait de l’USB

7 juillet 2025

Après plusieurs participations, nous avons observé des problèmes de communication I2C entre nos cartes équipées de Raspberry Pi Pico. Nous avions deux choix :

  • Continuer à analyser le problème côté logiciel pour rétablir la communication en cas de coupure ;
  • S’assurer qu’il n’y ait plus de coupure de communication.

Nous avions tenté, avec plus ou moins d’acharnement et pas trop de succès, le premier choix. La difficulté résidant dans la reproduction du défaut. On peut toujours débrancher un fil, mais le débranche-t-on le bon fil ? au bon moment ? Bref, nous n’avons rien produit de concluant.

Pour la seconde solution, nous faisons l’hypothèse que les problèmes de communication viennent des perturbations électromagnétiques. Alors qu’est-ce qui permettrait de se protéger des perturbations électromagnétiques ?

  • Un protocole qui utilise une paire différentielle ;
  • Un câble blindé ;
  • Un connecteur qui relie le blindage à la masse proprement.

Et quel protocole (relativement) bien supporté par tout microcontrôleur moderne coche ces cases ? Devinez... L’USB !

Des notions d’USB

De son nom, Universal Serial Bus, nous pourrions croire que le protocole se rapproche d’une liaison UART un peu évoluée, mais il n’en est rien. Le protocole est organisé autour d’un "hôte" (host) et des périphériques (devices). La norme USB décrit un empilement de protocoles, de la définition du 0 et du 1 sur le bus à la définition des classes de périphériques (Devices class) qui vont jusqu’à spécifier, de manière flexible, les cas d’utilisation de l’USB.

Ces classes de périphérique permettent de prendre en charge un grand nombre de périphérique différents sans développer de pilote spécifique à chaque fois. Quelques exemples de classes :

  • Video device class : pour les webcam, autorisant des flux élevés de données mais avec de potentielles pertes de débit
  • Mass Storage class (MSC) : pour les systèmes de stockage tels que les clés USB, les disques USB. C’était aussi utilisé sur les vieux téléphones portables
  • Media storage class : pour les systemes de stockage qui vont gérer les permissions sur les fichiers indépendamment de l’hôte USB. C’est ce qui est actuellement utilisé sur les téléphones portables pour transférer des photos ou des vidéos. Vous n’avez accès qu’à ce que le téléphone vous propose.
  • Communication device class (CDC) : pour tout ce qui émule une liaison série. Si vous mettez un composant pour convertir votre UART en liaison USB, ce composant se déclarera certainement en CDC. C’est ainsi que le Raspberry Pi Pico (et probablement les autres microcontrôleurs) communique avec l’ordinateur par défaut
  • Human interface device (HID) : pour les claviers, les souris, mais aussi les manettes de jeux, et entrées de simulateurs (cockpits d’avion, volants et pédales de voiture).

Pour une liste plus complète, wikipédia en anglais propose quelque chose de compréhensible.

Vouloir utiliser l’USB sans utiliser l’une des classes existante demande un effort considérable ! Bref, nous ne le conseillons pas !

La flexibilité du protocole USB en fait sa force mais crée une complexité qui fait que, même si nous maîtrisions parfaitement le protocole, nous ne pourrions le résumer en un billet de blog. Le meilleur résumé que nous pouvons vous proposer en ligne est USB in a Nutsheel. En français, j’ai le souvenir d’une revue qui présentait l’USB à travers une série d’articles, mais je n’en trouve pas la trace.

Et nos microcontrôleurs, dans tout ça ? La plupart des cartes pour développer sur microcontrôleur proposent un port USB, mais nous les classerons en 3 familles :

  • Celle où le microcontrôleur sort les données en UART et les envoie à un composant qui les adapte pour l’USB
  • Celle où le microcontrôleur supporte nativement l’USB, mais pour la partie "périphérique" seulement
  • Celle où le microcontrôleur supporte nativement l’USB, la partie "hôte" et la partie "périphérique"

Les 2 premières familles peuvent envoyer des données sur le bus USB sans soucis. La première sera restreinte à la classe CDC, tandis que la seconde sera plus flexible et pourra, par exemple, émuler un clavier ou une souris.

Mais seuls les microcontrôleurs appartenant à la 3e famille peuvent coordonner le bus USB. La solution "simple" est de laisser un ordinateur embarqué assurer ce rôle. Mais ce n’est pas notre souhait. Le Raspberry Pi Pico, basé sur le RP2040 est de la 3e famille, qui support hôte et périphériques. Notons qu’ayant qu’un seul port, un seul des rôles USB (hôte ou périphérique) peut être actif à un moment donné.

Hôte USB

Pour tester la fonctionnalité hôte USB, nous utilisons le code de démonstration fourni dans pico-example : host_cdc_msc_hid.

L’exemple de la fondation RaspberryPi marche bien. Ce qui nous a pris du temps :

  • Compiler l’exemple dans un projet indépendant ;
  • Avoir le bon câble, de type MicroUSB OTG (lien boutique) ;
  • S’installer pour récupérer les retours du microcontrôleur hôte.

Câble micro USB OTG

Si le port USB est pris, il faut récupérer les informations par un autre moyen. Nous utiliserons la liaison UART avec un convertisseur UART / RS232 puis un second convertisseur RS232/USB (parce que nous avions ceci sous la main).


Montage pour tester l’USB hôte

Note : sur le montage ci-dessus, il manque encore un câble USB pour l’alimentation...

L’exemple permet de gérer 4 types de périphériques USB :

  • HUBs ;
  • HID (Claviers, souris, manettes) ;
  • CDC (Communication type série) ;
  • MSC (Mass storage : clé USB, disque USB).

Côté architecture logicielle, nous en somme là :


Architecture logicielle - démo USB

Pour tester, nous commençons par relier un Raspberry Pi Pico avec un bête code printf("exemple\n") toutes les secondes à notre hôte USB. La connexion est détectée et les informations sont bien reçues !

Sortie du programme TinyUSB Host CDC MSC HID Example # Branchement d'un Rapsberry Pi Pico CDC Interface is mounted: address = 1, itf_num = 0 Baudrate: 115200, Stop Bits : 0 Parity : 0, Data Width: 8 A device with address 1 is mounted # Echo des données reçues Exemple Exemple Exemple # Déconnection du Raspberry Pi Pico A device with address 1 is unmounted CDC Interface is unmounted: address = 1, itf_num = 0 # Branchement d'un hub USB A device with address 1 is mounted # Branchement d'un Rapsberry Pi Pico sur le hub CDC Interface is mounted: address = 2, itf_num = 0 Baudrate: 115200, Stop Bits : 0 Parity : 0, Data Width: 8 A device with address 2 is mounted # Echo des données reçues Exemple Exemple Exemple # Déconnection du Raspberry Pi Pico A device with address 2 is unmounted CDC Interface is unmounted: address = 2, itf_num = 0 # Déconnection du hub USB A device with address 1 is unmounted

Commentaires

Il n'y a pas de commentaires

Ajouter un commentaire

Pseudo :
Mail :

Texte :

Copyright "POIVRON" 2011-2023, tous droits réservés
Administration du site