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 :
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 ?
Et quel protocole (relativement) bien supporté par tout microcontrôleur moderne coche ces cases ? Devinez... L’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 :
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 :
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é.
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 :
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).
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 :
Côté architecture logicielle, nous en somme là :
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 !
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