• 30 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 18/07/2024

Comprenez les spécificités d’une architecture microcontrôleur

Au début du chapitre 2.1 nous avons abordé les différences entre un microcontrôleur, un microprocesseur, un DSP (Digital Signal Processor), etc. Nous avons vu que le domaine pour lequel une architecture microcontrôleur est pensée est celui très vaste des systèmes embarqués. Dans ce chapitre nous continuons de détailler l’architecture d’un microcontrôleur.

Qu’est-ce qu’une architecture de microcontrôleur ?

Un système embarqué se traduit par un système autonome. Cela implique au niveau de l’architecture des mécanismes qui permettent de minimiser la consommation électrique. Citons, par exemple, la capacité de n’activer qu’en fonction des besoins certaines parties du microcontrôleur ou encore d’avoir la possibilité d’endormir le circuit complètement si celui-ci n’est pas utilisé.

Considérons maintenant les grands blocs constitutifs d’un microcontrôleur tels que nous pouvons les schématiser ci-dessous :

Blocs
Blocs constitutifs d’un microcontrôleur

Les broches d’E/S

Les broches d’E/S constituent sans aucun doute la partie la plus passive et la moins « intelligente » du circuit. N’oublions pas cependant qu’un microcontrôleur doit piloter un système embarqué. Il a donc nécessité de se « brancher » sur celui-ci et cela ne peut se faire au final que via ces broches.

Dans le catalogue d’un fondeur, un choix important à faire est le type de boitier (packaging) du processeur : LQFP, VFQFPN, LFBGA,…. Ces types ne vous disent sans doute rien (je vous rassure, à moi pas beaucoup plus !) mais ils définissent des choses essentielles comme les dimensions et la façon dont sont disposées les broches. Pour le développeur logiciel cela n’est que peu important puisque cela a surtout un impact sur la technologie électronique de la carte. Ce qui est bien plus important, soit parce que vous avez à le définir soit parce que cela vous est imposé, ce sont le nombre de broches que le circuit possède. Cela se traduit par une connaissance, avant de tomber la première ligne de code, de la référence exacte du circuit qui sera utilisé. En effet selon le boiter vous disposerez de plus ou moins de broches et les capacités d’interfaçage du processeur seront plus ou moins grandes.

Les périphériques

Ces éléments constituent la partie la plus typique des microcontrôleurs. Comme le processeur doit « dialoguer » avec le monde physique qui l’entoure il doit posséder des éléments qui sont capables de réaliser cet interfaçage. Cela passe par des capacités hors norme de gérer le temps via des timers (synchronisation d’échange numérique) à la gestion de grandeurs analogiques (convertisseur analogiques numériques).

Toutes ces parties périphériques peuvent être considérées comme des micromachines extrêmement spécialisées, mais autonomes. Elles sont évidemment accessibles pour le cœur, mais leur dialogue débute généralement par une demande du périphérique via un mécanisme d’interruption.

Combinée étroitement avec le nombre de broches d’un circuit, dans la gamme d’une famille de microcontrôleurs, il existe toute une déclinaison qui, sur une même base, proposent des circuits qui intègrent plus ou moins (en variété et en nombre) de périphériques. Comme pour le besoin en termes de capacité mémoire, connaître a priori toutes les ressources périphériques qui seront nécessaires à la future application relève du défi.

Les principaux périphériques

Une application embarquée et un microcontrôleur pourront « dialoguer » ensemble si les signaux qu’ils se transmettent sont compréhensibles et compatibles entre eux. Cette information est transmise par les broches du circuit et donc sera toujours supportée par un signal électrique que l’on peut séparer en trois grandes classes :

  • les grandeurs binaires

  • les grandeurs analogiques

  • les grandeurs numériques (succession de valeurs binaires dont la suite forme des valeurs codées)

Le sens de transmission est aussi essentiel : pour une broche donnée, on va soit du processus physique au microcontrôleur (on dit que la broche est en entrée) soit l’inverse (la broche est en sortie).

Comment et par qui sont gérés ces signaux ?

C'est ce que nous allons voir tout de suite !

Les GPIO

Allumer une lampe, savoir qu’un bouton poussoir est appuyé, ouvrir une électrovanne tout ou rien, détecter la présence d’une pièce avec un capteur inductif… Tous ces exemples montrent que beaucoup d’informations que l’on envoie ou que l’on reçoit du process sont binaires. En étant capable de piloter l’état binaire d’une broche (en entrée ou en sortie), il devient facile d’un point de vue fonctionnel de réaliser ces services. Même si ce n’est pas le sujet ici, il faudra tout de même s’interroger sur l’aspect électronique des branchements. Inutile d’espérer allumer un halogène de 500W sans un étage de puissance intermédiaire.

Le timer

La gestion du temps est une problématique générique et essentielle pour les systèmes embarqués et on se doute bien que les périphériques de type timer vont répondre à ce besoin. Mais la notion « d’unité timer » est plus subtile. Ce sont des unités qui, à la base, ne vont que compter (ou décompter) les changements d’état (front montant, front descendant ou les deux) d’un signal binaire. On parle alors de compteur (counter). Si l’entrée de l’unité est choisie comme étant une broche du circuit, il est possible de dénombrer un événement. Si le signal que cette unité voit est une horloge synchrone (donc un signal carré périodique) dont la fréquence est fixe et connue, la conversion entre le nombre de changements d’états et le temps écoulé est directe. On parle alors de timer bien que le mécanisme soit strictement similaire. En interne, un processeur possède au minimum une horloge pour cadencer le fonctionnement du cœur. Les unités de timer sont donc naturellement connectées à de telles horloges via un diviseur de fréquence pour pouvoir choisir la base de temps.

Les signaux sont aussi de type binaire puisqu’intrinsèquement la succession de valeurs binaires ne codent pas de valeurs. 

Ramené à sa plus simple expression, un compteur/timer n’est rien d'autre qu’un registre qui s’incrémente ou qui se décrémente en fonction de ce qu’il voit à son entrée. 

Timer/Counter
Timer/Counter

Rien ne peut donc lui arriver de bien méchant sauf le débordement (overflow ou underflow). En effet, le registre est à capacité finie, par exemple un registre de 16 bits. Aussi en comptage lorsqu’il vaut 0xFFFF et qu’un nouveau front apparait il ne peut basculer que vers 0 ; toute l’information précédemment accumulée est alors perdue, ce qui peut être fort regrettable. Un tel événement est heureusement détectable car l’unité va alors émettre une requête d’interruption pour que le programme puisse réagir en conséquence.

Lors de ce débordement, un autre mécanisme se met en place : plutôt que de repartir à 0, l’unité va repartir d’une valeur prédéfinie à l’avance (c’est-à-dire stockée dans un registre ad-hoc, nommé généralement reload). Le temps entre deux débordements est alors modifié.

Comme la base de temps est ajustable (diviseur de fréquence) et que l’on peut aussi programmer le nombre de fronts qui pourra intervenir entre deux requêtes d’interruptions successives (reload), il est possible de mettre en place des événements logiciels synchrones de façon très précise à l’aide de ces timers. 

Dans le périmètre des timers on trouve aussi la notion de Watchdog. Ces timers spécifiques sont des mécanismes qui existent pour s’assurer que le système (le programme en l’occurrence) ne reste pas bloqué dans le traitement qu’il exécute (typiquement une boucle infinie). C’est donc une sorte de sablier qu’il faut venir retourner avant qu’il ne se soit vidé. S’il est vide alors une alerte (interruption) est levée. Bien évidemment le temps propre au watchdog (la quantité de sable dans le sablier) est paramétrable.

Les Capture/Compare 

Ces unités sont en quelque sorte des sous-fonctions des timers. Elles sont parfois directement associées aux unités timer, parfois elles sont indépendantes, mais auquel cas, elles intègrent une capacité propre de type timer.

La fonction Capture consiste à dater un évènement lorsqu’apparaît sur une broche du circuit un front montant ou un front descendant ou un des deux. L’unité capture est donc associée à un signal de type binaire sur une broche, à un timer qui mesure le temps qui passe et à un registre pour stocker la valeur capturée du timer lorsque l’événement apparait. Exemple d’application : je mesure le temps pendant lequel un bouton poussoir a été appuyé.

La fonction Compare est un peu le symétrique.  Il y a toujours un signal de type binaire, mais le timer est remplacé par un compteur qui compte les événements (toujours les fronts) qu’il détecte sur la broche.  Il a également, stocké dans un registre interne, une valeur dite de comparaison. Lorsque le compteur égale cette valeur l’unité va déclencher une demande d’interruption. Exemple d’application : je compte le nombre de pièces qui sont passées sur mon tapis roulant et je déclenche une action quand 100 pièces ont été détectées.

L’ADC

Le monde que l’on cherche à piloter peut nous indiquer son état à travers de grandeurs physiques (température, pression, distance, accélération, …). L’électronicien de service aura équipé le process d’un capteur qui transforme cette grandeur en une grandeur proportionnelle en volts. Nous sommes en présence alors d’un signal de type analogique dont on espère que l’échelle de grandeur soit compatible avec notre microcontrôleur (typiquement [0V - 5V]).

Le processeur lui ne connait que le monde numérique, il faut donc une unité spécialisée qui réalise cette transformation : l’Analog Digital Converter.

Très généralement cette unité est branchée sur un multiplexeur, c’est à dire que plusieurs broches sont capables de porter un signal analogique et qu’il revient au programmeur de sélectionner logiciellement sur quelle(s) voie(s) d’entrée du multiplexeur il doit connecter l’ADC. 

ADC
Connexion de l'ADC sur un multiplexeur

Une grandeur importante qui qualifie un ADC est sa résolution, c’est-à-dire la quantité de valeurs entières que peut prendre l'ADC après conversion. Elle peut être donnée par :

  • le nombre de bits du registre de conversion (par exemple 12 bits),

  • le nombre de valeurs différentes de conversion (par exemple $\(1024 = 2^{10}\)$),

  • le quantum en volts entre deux valeurs numériques de conversion (par exemple si la pleine échelle est de [0V - 5V] on obtient $\(4,88mV = \frac{5}{1024}\)$). 

La PWM

Le symétrique d’un ADC est un DAC (Digital Aanlog Converter) qui permet de transformer une valeur numérique en une valeur analogique proportionnelle permettant de commander le process. Cependant ces unités sont peu courantes dans une gamme complète de microcontrôleur. La raison principale est que ce genre de circuit consomme beaucoup (on transfère directement de l’énergie électrique). On peut d’autant mieux s’en passer qu’une unité Pulse Width Modulation peut très correctement remplacer un DAC.

Ces unités PWM fournissent un signal binaire carré périodique dont on peut agir sur le rapport entre le temps à l’état haut et le temps à l’état bas. Dans l’exemple ci-dessous le signal est d’une période fixe $\(T_p\)$ . Au début de la séquence le ratio $\(\frac{T_{h1}}{T_p}\)$ est fixé à 75%. Au temps $\(\tau\)$ , ce ratio est changé à 37%, le période $\(T_p\)$  ne change pas, c’est le temps $\(T_{h2}\)$  qui est diminué par rapport à $\(T_{h1}\)$ .

Période fixe
Signal d'une période fixe

En quoi cela équivaut-il à un signal analogique ?

Considérons que ce signal commande un petit moteur électrique. Lorsque l’on applique une tension constante à un tel moteur à courant continu il va se mettre à tourner à une vitesse constante mais il lui faut un petit temps d’établissement pour passer de sa vitesse initiale à sa vitesse finale. Imaginons que l’on s’amuse à maltraiter le moteur en lui envoyant un signal carré lent, voici ce que donnerait l’évolution de sa vitesse en fonction du temps en réponse à ce signal de commande :

Moteur
Envoi d'un signal carré lent au moteur

Supposons que nous répétions cette même expérience en augmentant maintenant la fréquence du signal d’entrée mais tout en maintenant le même ratio. Le moteur est toujours le même et son temps de réaction (temps d’établissement) est identique. Il va donc être amené à faire varier sa vitesse plus rapidement. Ci-dessous est représentée cet évolution en superposant le signal de commande de la PWM et celui du signal de la vitesse de sortie :

d
d
d

Le moteur n’a plus le temps de s’adapter au changement intempestif de l’entrée qui n’arrête pas de changer entre 5V et 0V. Il ne va voir au final qu’une moyenne du signal. Cette moyenne correspond au 5V multiplié par le ratio.

En jouant ainsi sur le ratio entre 0% et 100% il nous est possible de créer un pseudo-signal analogique aux yeux du système commandé. Cela suppose que la période de base $\(T_p\)$ de la PWM soit correctement choisie : trop grande le système commandé va « suivre » les oscillations du signal d’entrée, trop petit on risque d’exciter les circuits électroniques du système commandé de façon plus ou moins néfaste.

Les bus

Pour de multiples raisons un système informatique a besoin d’envoyer des données à un autre système informatique. L’information prise à son plus bas niveau est une information binaire. Elle peut donc être transportée du point à un autre à l’aide d’un simple fil en faisant transiter sur ce fil une suite de 1 et de 0 qui forme la donnée numérique à transmettre. Le principe est simple, mais la mise en œuvre peut être bien plus complexe car il faut que l’émetteur et le récepteur se retrouvent et se comprennent.

Le protocole le plus simple est celui de la liaison série asynchrone (Universal Asynchronous Receiver Transmitter). Un fil pour émettre, un pour recevoir et une masse électrique commune. Les données transitent octet par octet à une vitesse fixée à l’avance.

Ce premier protocole peut se complexifier en ajoutant un signal d’horloge commun qui permet de synchroniser les données. On obtient alors un Universal Synchronous/Asynchronous Receiver Transmitter (USART).

Une transmission RS-232 (petit nom familier d’un UART) n’est pas toujours suffisant : Il faut souvent augmenter les débits et sécuriser les données pour s’assurer que ce qui est envoyé est correctement reçu. Il est également souvent nécessaire de connecter plus de 2 systèmes ensemble, induisant par exemple l’idée de réseau, de système maître/esclave pour la communication et aussi d’adresse numérique d’un système à contacter.

Pour répondre à ces besoins est donc apparu sur le marché plusieurs standards de protocole. Les plus célèbres, car liés au monde de l’informatique, sont sans aucun doute l’Ethernet et l’USB. D’autres répondent à des besoins plus industriels et portent généralement le terme générique de bus industriel ou bus de terrain : I²C, SPI, CAN.

Dans un microcontrôleur, on trouvera pratiquement toujours une liaison USART et très souvent au moins un protocole de bus (industriel ou pas). Il est à remarquer qu’il peut être utile parfois d’opter pour un microcontrôleur simple et de lui ajouter une fonction périphérique manquante à travers un bus industriel si ce protocole équipe le circuit. À titre d’exemple pensons à un DAC qui est communément absent. Il existe sur le marché des DAC qui se pilotent directement avec une interface I²C ou SPI, il suffit donc de prévoir l’extension électronique pour avoir accès à cette conversion numérique analogique.

Le STM32-F…

STMicroelectronics a développé depuis 2006 une gamme de microcontrôleur appelée STM32. Ces processeurs sont basés sur un cœur Cortex M conçu par ARM. Comme son nom l’indique, ces STM32 sont des microcontrôleur 32 bits.

A la fin de 2016 cette gamme comprenait 7 familles allant de processeur très basique (STM32L0 basé sur un Cortex M0) à des produits nettement plus performants en terme de capacité de calcul et d’équipements périphériques (SMT32 H7). Le rapport de puissance de calcul entre ces deux extrêmes est de l’ordre de 30. Toujours fin 2016, cette gamme comprenait plus de 700 références ! Le milieu de gamme est constitué des microcontrôleurs STM32F0 à STM32F7.

Pour favoriser la distribution de ces produits, ce fondeur propose un panel de cartes de développement à bas coût qui porte le nom générique de Nucléo et dont la grosse majorité est basée sur des STM32F.

Dans ce cours, nous vous proposons de vous exercer sur carte Nucleo F103RB basée sur un processeur STM32F103RB. Cette carte inclut une sonde de debug. Elle est également équipée d’un double connecteur (dont un compatible Arduino) qui permettre se brancher aux différentes broches du circuit. Il devient alors assez facile et très ludique d’agrémenter la carte avec toute sorte de capteurs et d’actionneurs pour construire son propre système.

Les principales caractéristiques du STM32F103 sont : jusqu’à 80 GPIO, 4 timers (incluant des fonctionnalités de PWM, de Capture et de Compare), 2 timers de type watchdog, le timer propre au coeur Cortex, 2 ADC, 2 bus I²C, 2 bus SPI, 3 USART,1 bus CAN, 1 port USB.  Bref déjà un bel objet qui permet de piloter des process déjà évolués et complexes notamment en nombres d’entrées et de sorties. 

La datasheet : la bible du développeur

Vous vous sentez prêt à affronter la bête ? Heureusement que ce MOOC existe (et d’autres ressources aussi, soyons modestes !) puisque sans cela il vous faudrait explorer les quelques centaines de pages des documentations spécifiques, à savoir :

La datasheet du microcontrôleur 103xB

Ce n’est peut-être pas le plus utile et ses pages 117 pages vont globalement plus intéresser un électronicien qui devra concevoir la carte qui hébergera ce processeur mais c’est le seul endroit où il vous sera possible de savoir à quel GPIO et à quels périphériques sont associés chacune des broches du circuit. Information intéressante au passage : on y apprend qu’il appartient à la medium-density performance line,

Le Reference manual

Le morceau de choix avec ses 1137 pages est sans conteste le Reference manual. Ce document est déjà plus générique que le précédent puisqu’il concerne tous les STM32 F10x (101, 102, 103 105 et 107). Ce document est découpé en chapitres qui contiennent chacun une partie ou un périphérique bien spécifique. Par exemple le chapitre 11 est dédié aux ADC.

Les chapitres sont structurés de la même façon : ils débutent par une description globale, donnent ensuite des précisions sur toutes les possibilités de fonctionnement et se terminent par une partie qui détaille le contenu de chacun des registres. Dans la phase de programmation, c’est bien souvent cette dernière partie qui est consultée. 

Le fait que ce document soit commun à toute une série de processeurs est bien compréhensible (une pensée émue à ce sujet envers les petites mains chargées de rédiger de telles œuvres…) mais cela en complique la lecture. À titre d’exemple, regardons ce qui se passe pour les GPIO (chapitre 9). Il débute ainsi :

d

Il est donc déjà important de savoir que nous sommes dans la case medium density. Par la suite, on trouve des informations comme :

d

On pourrait en déduire qu’il existe des ports GPIO qui vont de GPIOA jusqu’à GPIOG. Et bien non ! Sur le 103RB il n’y a que 4 ports (A à D) et encore D n’existe qu’avec 3 broches de sortie. Pour le savoir cela nécessite d’avoir déjà parcouru le document précédent.

Le programming manual du Cortex M3

Ce document est aussi nécessaire : et 156 pages de plus ! Rappelez-vous que les STM32 sont basés sur un cœur Cortex. Ce dernier étant générique, il possède sa propre documentation. Celui nous sera nécessaire pour comprendre et programmer le timer commun (appelé Systick), mais aussi les mécanismes d’interruption.

Il y a bien sur d’autres documents qui seraient nécessaires de consulter pour avoir une maîtrise complète de cet ensemble matériel. Mais pour débuter ces trois PDF sont largement suffisants. Rassurez-vous immédiatement, nul besoin de potasser l’ensemble de ces documents pour y arriver.  De notre côté, cela fait des années que nous travaillons et enseignons la programmation de ces puces et il y a bien des pages sur lesquelles nos yeux ne se sont jamais posés. L’important est d’avoir une connaissance de leur contenu général et de leur structuration, ce qui s’acquiert avec un peu d’expérience et de pratique. Par la suite, si on souhaite par exemple programmer un nouveau service de PWM, il suffit d’aller directement aux pages ciblées pour y comprendre ce qu’il convient de faire.

  

À la fin de ce chapitre, vous êtes capable : 

  • d'identifier les principaux périphériques d'un microcontrôleur et d'en expliquer leur principale fonctionnalité,

  • de savoir où chercher une information pour comprendre et configurer un périphérique.

Exemple de certificat de réussite
Exemple de certificat de réussite