Les périphériques intégrés au microcontrôleur STM32L476RG

Nous terminerons la revue des composants utiles à notre station météo par trois périphériques intégrés au microcontrôleur STM32L476RG : La RTC, le chien de garde indépendant et la mémoire flash.

Avant cela, nous aborderons très superficiellement l’architecture du STM32L476 : Cortex M4, interruptions, périphériques, etc. Si vous souhaitez en apprendre beaucoup plus, l’excellent ouvrage de Joseph Yiu est plus que recommandé. :

The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors (Third edition), Yiu Joseph, ISBN : 9780124080829

Qu’est-ce qu’un microcontrôleur ?

Un microcontrôleur (figure 1.11) est un « système sur puce » ou « System on Chip » en anglais (SoC) qui rassemble sur une même puce de silicium un microprocesseur et d’autres composants et périphériques : des bus, des horloges, de la mémoire, des entrées-sorties, etc. voir le glossaire.


Qu’est-ce qu’un microcontrôleur ?


Dans le cas qui nous intéresse, le microprocesseur choisi par STMicroelectronics est un Cortex M4 [https://developer.arm.com/ip-products/processors/cortex-m/cortex-m4] conçu par la société ARM. L’architecture ARM Cortex-M est dominante dans les microcontrôleurs pour les applications embarquées essentiellement en raison de son excellente efficacité énergétique et de sa gestion très performante des interruptions. Le composant intégré au Cortex-M4 et chargé de la gestion des interruptions est le NVIC pour « Nested Vectored Interrupt Controller » (figure 1.12).


ARM CORTEX-M4


Crédit image : ARM

STMicroelectronics a acquis une licence de propriété intellectuelle du Cortex M4, c’est à dire paye des royalties à ARM pour disposer des plans de ce microprocesseur et des outils permettant de l’intégrer dans ses propres puces, telle que le STM32L476RG.

Les périphériques et fonctions rajoutées par STMicroelectronics autour du Cortex-M4 sont nombreux (figure 1.13). Nous passerons en revue par la suite ceux qui seront utilisés par notre projet ; en gardant à l’esprit que l’API STM32duino ne permettra pas d’en exploiter tout le potentiel mais rendra en contrepartie leur programmation plus simple par comparaison avec d’autres alternatives (programmation HAL ; MBED …).


Le STM32L476


Crédit image : STMicroelectronics

Vous pouvez consulter le glossaire qui énumère et décrit plus en détails tous les périphériques intégrés au microcontrôleur STM32L476RG.

Les interruptions et le contrôleur d’interruptions

La programmation des interruptions est essentielle pour une application lorsqu’elle nécessite :

  • Une gestion optimale de la consommation et/ou…
  • Une réactivité de type « temps réel » sans avoir recours à un système d’exploitation.

Imaginons que l’on souhaite construire un robot équipé d’un Cortex M4, fonctionnant sur batterie, qui roule droit devant lui et mesure la distance d’un éventuel obstacle sur son chemin avec un sonar. L’approche la plus simple pour le programmer consistera à utiliser une boucle sans fin comme dans le pseudo code qui suit :

void setup() { // Initialisations, réalisées une seule fois
	Initialisation du sonar
	Initialisation des moteurs
	Démarre les moteurs et avance tout droit à une vitesse donnée
}

void loop() { // Boucle sans fin, répétée aussi longtemps que le robot est alimenté
	Opération 1 : lis le sonar
	Opération 2 : si le sonar détecte un obstacle, arrête les moteurs
	Opération 3 : attend un dixième de seconde
}

Cette solution naïve présente deux inconvénients :

  • D’une part le robot interroge le sonar dix fois par seconde, alors qu’un obstacle n’est susceptible de se présenter que bien plus rarement, à un moment imprévisible. Il puise donc abondamment dans sa batterie pour cette fonction qui ne fait rien d’utile et ceci quasiment à plein temps !
  • D’autre part la temporisation (opération 3, vous pouvez imaginer qu’elle représente le temps que le microcontrôleur doit accorder aux opérations 1 et 2) fait qu’il est tout à fait possible que notre robot – s’il est rapide - parcoure une distance assez importante en un dixième de seconde pour percuter un mur avant de l’avoir détecté ; il n’est pas capable de réagir en temps-réel.

Ces deux problèmes sont essentiellement résolus par une programmation utilisant les interruptions, qui donnerait ceci :

void setup() { // Initialisations, réalisées une seule fois
	Initialisation du sonar
	Connecte le sonar au NVIC, active son interruption
	Initialisation des moteurs
	Démarre les moteurs et avance tout droit à une vitesse donnée
}

void loop() { // Boucle sans fin, répétée aussi longtemps que le robot est alimenté
	mets le microcontrôleur en mode veille
}

void service_interruption_sonar() { // Exécutée lorsque le sonar détecte un obstacle
	arrête les moteurs
}

La fonction loop ne contient que des instructions pour mettre en veille le Cortex. On a rajouté dans la fonction setup les instructions nécessaires pour connecter le sonar au gestionnaire d’interruptions (NVIC) et activer l’interruption correspondante. Enfin, on a ajouté une routine de service de l’interruption du sonar, service_interruption_sonar, qui stoppe le robot seulement lorsque le sonar détecte un obstacle.

Au démarrage, le Cortex exécute setup ; le robot avance droit devant lui. Le Cortex exécute ensuite loop qui le met en veille (pour autant, les moteurs du robot continuent de fonctionner). Le sonar mesure la distance devant lui de façon continue mais consomme beaucoup moins que le Cortex grâce à ses circuits spécialisés. Lorsque le sonar détecte un obstacle, il envoie un signal au NVIC, qui réveille le Cortex et lui ordonne d’exécuter en priorité service_interruption_sonar. Les moteurs s’arrêtent alors. Le Cortex enchaîne ensuite sur l’exécution de loop qui le place à nouveau en mode veille (les moteurs sont toujours arrêtés).

Grace à l’usage des interruptions, on assure une réactivité et une consommation d’énergie optimisées.

La gestion des interruptions par l’API Arduino est malheureusement réduite à sa plus simple expression pour des raisons de choix pédagogiques ; les développeurs d’Arduino ayant manifestement considéré que c’était un concept trop compliqué pour les débutants. Heureusement, l’API STM32duino implémente quelques fonctions de gestion des interruptions spécifiques à l’architecture STM32, qui lèvent partiellement cette limitation.

Notre station météo recourra finalement aux interruptions pour deux fonctions :

  • La gestion du bouton utilisateur, pour provoquer une mesure à la demande lorsqu’il est appuyé, via la fonction «attachInterrupt » de l’API Arduino.
  • La gestion du module HC-06 afin qu’elle réponde sans délai aux commandes de l’utilisateur.

## L’horloge temps réel

L’horloge temps réel du STM32L476RG, abrégée par RTC (pour « Real Time Clock ») est entièrement programmable. Vous pouvez la considérer comme une montre-calendrier disposant de plusieurs alarmes, certaines permettant de sonner la mise en sommeil ou le réveil du STM32L476RG. Nous l’utiliserons pour :

  • Déterminer avec précision la date et l’heure de chaque série de mesures
  • Déterminer la date et l’heure des changements d’heure d’été et d’hivers
  • Piloter (sans notre intervention explicite) le mode « Deep Sleep » du microcontrôleur

La bibliothèque STM32duino pour la RTC se nomme « STM32duino RTC », elle est disponible ici.

Le chien de garde indépendant

Le « chien de garde indépendant », abrégé par IDWG (pour « Independant Watchdog »), est un circuit intégré faisant office de compteur-à-rebours autonome. On fixe sa valeur maximum de départ, en microsecondes et on le démarre.

Une fois lancé l’IDWG décompte les microsecondes, de façon totalement indépendante du programme en cours d’exécution, jusqu’à atteindre la valeur zéro. Il force alors un « reset » du microcontrôleur. Il est possible d’interrompre et relancer le décompte de l’IDWG à partir de sa valeur maximum à tout moment, depuis le programme utilisateur, et d’empêcher ce reset.

On comprend l’intérêt de ce périphérique : si le programme utilisateur est « planté » (à cause d’un bug, d’un capteur défaillant, d’un module Wi-Fi qui ne se connecte pas, etc.) alors il ne « rechargera » pas l’IDWG avant la fin de son décompte, et l’IDWG forcera le système à redémarrer.

La bibliothèque STM32duino de l’IDWG est distribuée avec le Core STM32, vous la trouverez ici. Il n’y a donc pas besoin de l’installer en plus des définitions des cartes de ST. Elle est accessible en rajoutant « #include » dans le sketch STM32duino.

La mémoire flash embarquée

Le code binaire du programme généré après compilation de notre sketch Arduino sera enregistré dans la mémoire flash de 1 Mo du STM32L476RG. Il s’agit d’une mémoire réinscriptible de la famille des mémoires non volatiles, qui ne s’effacent pas lorsque le microcontrôleur n’est plus alimenté.

Nous allons également utiliser cette mémoire flash pour émuler un autre type de mémoire non volatile qui n’est pas intégrée dans le STM32L476RG - l’EEPROM - afin d’y enregistrer différents paramètres utilisateur (nom et mot de passe du réseau Wi-Fi ; coordonnées géographiques de la station, etc.). La bibliothèque Arduino utilisée pour cela est documentée ici. Elle est accessible en rajoutant « #include » dans le sketch STM32duino.  

Attention, les mémoires flash et les EEPROM ont leurs limites ! Les temps de lecture et d’écriture sur celles-ci sont relativement longs et elles sont aussi fragiles. Nous vous déconseillons fortement de créer des applications qui écrivent ou effacent celles-ci à un rythme soutenu, vous finiriez par endommager irrémédiablement le microcontrôleur.

Les contrôleurs de connectivité

Les protocoles de connectivité I2C, U(S)ART et SPI déjà évoqués font appel à des contrôleurs qui sont également intégrés dans le STM32L476RG. Pour faire la synthèse de ceux qui nous intéressent :

  • Le SPI1, en changeant toutefois sa broche SCK comme expliqué ici. La bibliothèque Arduino pour le gérer est rendue accessible par la déclaration « #include ».
  • L’I2C1 dont la bibliothèque Arduino se trouve ici. Il est rendu accessible par la déclaration « #include ».
  • L’UART4 et l’UART5 configurés avec la bibliothèque STM32duino « HardwareSerial » dont l’utilisation est décrite ici.

Notez que les broches pour les différents contrôleurs I2C, U(S)ART et SPI accessibles par l’API STM32duino sur la NUCLEO-L476RG sont indiquées dans cette annexe.

Les modes basse-consommation

La figure 1.14 illustre les modes basse consommation du STM32L476RG.


Les modes basse-consommation du STM32L476


Crédit image : STMicroelectronics

La bonne programmation des modes basses consommation du STM32L476RG est un sujet très technique (voir par exemple ce lien et celui-ci) et définitivement une affaire d’experts. Heureusement, la bibliothèque STM32duino « STM32 Low Power » étend l’API Arduino et donne un accès restreint mais simplifié à ceux-ci. Nous utiliserons essentiellement deux méthodes de la classe « STM32LowPower » qu’elle fournit :

  • « deepSleep » pour placer le microcontrôleur en mode STOP 2 l’essentiel du temps, entre deux séries de mesures par la station météo ;
  • « enableWakeupFrom » pour réveiller le microcontrôleur avec une interruption attachée à l’UART5 et donc, indirectement, au module Bluetooth HC-06 branché dessus.