I2C, SPI, CAN, UART ? Qu’est-ce qu’un bus

Pendant ma première année de master à l’UCLouvain, j’ai eu l’occasion de participer à la compétition Eurobot et de développer un robot complet de A à Z. Je me suis particulièrement occupé de la partie électronique, ce qui m’a permis d’apprendre énormément de choses. La méthode d’apprentissage était un peu spéciale, et je me souviens du jour où l’un des assistants nous a dit :

« Vous devez utiliser des bus parce que vous n’aurez pas assez d’IOs. »

Un certain assistant

Il y a quelques années, j’aurais aimé tomber sur un article comme celui-ci pour aborder cette phrase ou tout simplement pour la comprendre.

Loin des explications que vous pourrez trouver facilement sur Wikipedia, je vous donne ici les miennes, faciles à retenir, suffisantes à mes yeux, mais sans la prétention d’être exactes et rigoureuses. Ensemble, essayons de décrypter cette réflexion.

Considérons un cas simple : j’ai d’une part un capteur type “switch”, sur une carte électronique, et d’autre part un micro-contrôleur qui nécessite l’information mesurée par le capteur. Comment sont physiquement reliées ces deux entités ? Selon le montage de mon capteur, sa tension de sortie sera l’image de son état (par exemple, l’interrupteur est fermé : 3,3 V, l’interrupteur est ouvert : 0 V). J’ai donc besoin d’un câble qui ramène cette tension à un pin d’entrée digitale de mon micro-contrôleur. Si je veux maintenant mettre 1 000 capteurs sur ma carte, il me faut 1 000 câbles et 1 000 entrées digitales ; c’est ce qu’on appelle de la connexion parallèle. On se rend vite compte de la complexité de la situation.

L’idée d’un bus est de diminuer le nombre de lignes nécessaires et donc le nombre d’entrées/ sorties nécessaires pour communiquer avec plusieurs entités, la connexion devient série. En pratique, on va utiliser la même ligne (i.e le même câble) pour discuter avec toutes les entités. On comprend rapidement les limites d’un bus :

  • Les entités doivent devenir “intelligentes” pour être capables d’établir la discussion. Je devrai donc rajouter un composant type “contrôleur” pour gérer mes 1 000 capteurs. Comment une entité saura-t-elle qu’on lui parle ou que l’on parle à sa voisine ?
  • Comme toutes les informations sont sur le/les mêmes câbles, c’est forcément moins rapide, moins immédiat. Quelle est la vitesse de communication ?
  • On comprend qu’une entité qui nécessite une information (par exemple celle d’un capteur) ou qui donne des informations (par exemple pour un contrôleur de moteur) sera le « maître » tandis que l’entité réceptrice sera “l’esclave”. Comment cette relation est-elle définie ?
  • Si un seul câble est partagé, comment les données de l’émission ne rentrent-elles pas en conflit avec les données de la réception ? Comment synchroniser les entités pour que tout le monde puisse se comprendre ?

Bien d’autres points sont intéressants, mais ceux-ci nous permettent déjà de mettre en évidence les principales contraintes d’un bus et leurs raisons d’utilisation. Les réponses sont bien différentes pour chaque bus, et c’est là que ça devient intéressant.

En quelques mots,

Le bus I2C présente deux lignes : SDA, les données, SCL, l’horloge. Chaque esclave possède une adresse, parfois configurable en hardware, qui permet de le différencier de son voisin. La communication est synchronisée par le signal d’horloge. Le maître envoie une trame qui commence par l’adresse ; le bon esclave écoute alors les informations suivantes et, sur la même ligne, renvoie ses données. C’est ce qu’on appelle le half duplex et de ce fait, la communication est assez lente. Ce bus est assez vieux, mais il est utilisé pour beaucoup de capteurs et activateurs en tout genre. Il faut prêter attention aux adresses pour que deux entités n’aient pas les mêmes, et à placer des résistances de pullup sur les lignes. Voici un exemple avec l’étendeur d’IO que j’ai utilisé dans PiKot, le MCP23017.

Exemple pour le bus I2C.

Le bus SPI présente au moins quatre lignes : MOSI (master output, slave input), MISO (master input, slave output), CLK (l’horloge) et CS (chip select). Pour chaque entité esclave, un signal de sélection (CS) est nécessaire ; lorsque celui-ci passe à l’état haut (généralement actif bas), l’entité sait que le maître lui parle. Il n’y a donc plus ici de problématique d’adressage. Le SPI est très rapide parce que deux lignes sont consacrées aux données : une pour l’émission, une pour la réception ; on parle ici de full duplex. La synchronisation est aussi gérée par un signal d’horloge. Le SPI est très répandu et se retrouve dans des applications qui nécessitent un grand débit de données (par exemple, la lecture d’une mémoire). Voici un exemple avec le même étendeur d’IO, mais dans sa version SPI.

Exemple pour le bus SPI.

Le bus CAN présente deux lignes : CAN H (high) et CAN L (low) qui forment une paire différentielle. De cette façon, le bus est très robuste au bruit ambiant. Ce bus a été inventé par Bosch pour le secteur automobile et permet de diminuer considérablement la longueur des câbles dans les voitures et de faciliter le processus de fabrication. On ne parle plus de relation entre esclave et maître ; chaque entité est considérée comme un nœud et tout le monde peut parler à tout le monde tout le temps. Il n’y a pas de concept d’adressage, le bus utilise un protocole de communication très astucieux pour gérer les priorités des trames. De cette façon, tout le monde finit toujours par communiquer l’information qu’il souhaite sur le bus. Ce bus est particulièrement utilisé dans le monde industriel, de l’énorme moteur au petit capteur de pression. On oubliera pas de placer les résistances aux extrémités des lignes pour éviter la résonance. La grosse différence avec ce bus, c’est que l’on sort de la communication au sein d’une carte, on relie entre elles différentes entités physiquement séparées.

Schéma de principe du bus CAN.

Le bus UART présente deux lignes : RX (réception) et TX (transmission). Une variante existe avec l’USART, qui rajoute un aspect de synchronisation avec une horloge. Ce bus permet de relier seulement deux entités entre elles. On l’utilise principalement pour programmer des chips, communiquer avec une antenne ou encore établir une communication série sur USB (avec le FT232RL). On n’oubliera pas de croiser les lignes entre les deux entités. Ci-dessous, le schéma électrique d’un bien connu petit programmeur USB. Il n’a maintenant plus de secret pour vous.

USB to UART avec le FT232RL.

Le 1-Wire, comme son nom l’indique, ne présente qu’une seule ligne, c’est un bus inventé par Dallas Microconductor et encore bien utilisé dans le monde de la domotique pour des petits capteurs. Il est du même genre que le l’I2C, mais sans horloge de synchronisation et donc encore plus lent.

Il existe encore bien d’autres bus, ceux-ci étant les principaux. Ces quelques informations devraient être suffisantes pour comprendre comment ils fonctionnent et quelles sont leurs principales différences.

La plupart du temps, le choix d’un bus de communication sera limité par le choix des composants à utiliser et non pas par l’ingénieur lui-même.

Notez que ces bus de communication, à l’exception du CAN, sont directement intégrés aux micro-contrôleurs que j’utilise souvent : Arduino, ESP8266 ou Raspberry Pi. On peut faire du “CAN over SPI” avec un MCP2515. Le STM32 selon ses différents modèles, intègre ces bus et est adapté pour faire du CAN à l’aide d’un unique composant, comme le MCP2551.

CAN over SPI avec le MCP2515.

Certains contrôleurs présentent des niveaux de tension logiques différents, généralement 5 V et 3,3 V. Il faut alors utiliser des translateurs de niveaux (level shifters en anglais). Cela peut se faire avec des composants dédiés comme le TXS0108E, des portes à hystérésis, avec des transistors MOSFET comme le bien connu montage du BSS138, etc. Si les lignes sont monodirectionnelles, on peut utiliser un diviseur résistif (l’impédance d’entrée est généralement très grande) ou encore un montage avec deux inverseurs avec des BJT pour monter la tension.

Level shifter bidirectionnel avec le BSS128.

Notez également que les longueurs de ligne ne peuvent être infinies et qu’on doit y prêter attention lors du routage. Sur notre robot, nous avions fait l’erreur d’utiliser des câbles pour distribuer l’I2C dans tout le robot. Toutes ces longueurs et le bruit électromagnétique ambiant nous ont joué des tours.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *