Cette page vise à présenter une première utilisation des interruptions sur un microcontrôleur STM32. À la suite de cette page, un développeur logiciel doit être capable:

  • De trouver les informations nécessaires dans une datasheet pour l’utilisation des timers,
  • De programmer les différents registres pour différentes utilisations des timers (LED, bouton-poussoir etc.),
  • D’adapter le fonctionnement d’un timer à l’utilisation d’un capteur externe.
Version des outils Les différentes étapes utilisent la version v1.12.0 du logiciel STM32CubeIDE. Certaines variations au niveau des captures d’écrans peuvent apparaître si vous utilisez des versions différentes. De même, la carte utilisée est la Nucleo-F446RE.

Détection d’un obstacle

Dans cette partie, l’objectif va être de concevoir un système de détection d’obstacle. Le fonctionnement recherché sera le suivant: faire clignoter une LED de plus en plus rapidement selon la distance d’un obstacle. Pour cela, nous allons décomposer le problème en trois sous-arties:

  1. Le clignotement de la LED en utilisant un timer,
  2. La lecture d’un capteur pour récupérer la distance,
  3. La mise en place de l’application finale.

Clignotement d’une LED

Lors des expérimentations précédentes, nous avons utilisé différentes stratégies pour faire clignoter une LED:

  • Inversion lors de l’appui sur un bouton poussoir (scrutation),
  • Inversion lors de l’appui sur un bouton poussoir (interruption),
  • Boucle d’exécution avec l’ajout d’un délai avant l’inversion.

Si toutes ces solutions sont fonctionnelles, aucune ne permet d’avoir une prise en compte précise du temps. Il n’est donc pas possible de réaliser un clignotement régulier et d’une durée parfaitement maîtrisée. Pour cela, nous allons donc utiliser les timers mis à disposition au sein de la carte STM32. Plus particulièrement, nous utiliserons ici le timer TIM2.

Périodique

Pour commencer, nous allons voir comment utiliser un timer pour déclencher périodiquement une routine responsable de la gestion de la LED.

Question 1 Avant d’utiliser un timer, il est nécessaire d’activer son signal d’horloge. Pour cela, mettez à 1 le bit correspondant du registre RCC_APB1ENR.
Documentation

Le registre RCC_APB1ENR est détaillé page 146 du manuel de référence (Chapitre 6: Reset and clock control (RCC)).

Question 2 Le registre CR1 du TIM2 permet de configurer son fonctionnement. Notamment, les champs CEN, DIR, CMS et ARPE permettent respectivement d’activer le compteur, de sélectionner la direction du compteur (croissant ou décroissant), l’alignement (aligné sur les fronts ou centré) et de bufferiser le préchargement. Modifiez le registre pour que le compteur soit éteint, croissant, aligné sur les fronts et que le préchargement soit bufferisé. On l’activera seulement une fois la configuration terminée.
Documentation

Le registre TIM2_CR1 est détaillé page 549 du manuel de référence (Chapitre 17: General-purpose timers (TIM2 to TIM5)). L’utilisation d’un buffer pour le pré-chargement permet de s’assurer que le compteur ne change pas de valeur maximale n’importe quand. Ainsi, c’est seulement lorsqu’un débordement (overflow) aura lieu que la nouvelle valeur sera prise en compte.

Question 3 Par défaut, la génération d’un signal d’interruption lors d’un débordement est désactivé. Pour l’utiliser, il faut donc mettre à 1 le champ UIE du registre DIER.
Documentation

Le registre TIM2_DIER est détaillé page 554 du manuel de référence (Chapitre 17: General-purpose timers (TIM2 to TIM5)).

Fréquence des horloges Sur la vue système (double-cliquez le fichier .ioc du projet), dans Clock Configuration, vérifiez pour la suite la valeur des horloges de votre système. Notamment, regardez la valeur des horloges contrôlant le processeur (core) et le bus APB1. Pour la suite, on considèrera que la valeur d’horloge pour le microcontrôleur est de 180MHz et celle des timers de 90MHz.
Question 4 Dans un premier temps, on souhaite faire clignoter la LED toutes les secondes. La fréquence de l’horloge du timer étant de 90MHz, il est nécessaire d’attendre 90,000,000 cycles pour qu’une seconde s’écoule. À partir de ces informations, modifiez les registres ARR et PSC pour avoir le fonctionnement attendu. On considèrera que chacun de ces registres ne fait que 16 bits.
Documentation

Les registres TIM2_PSC et TIM2_ARR sont détaillés page 564 du manuel de référence (Chapitre 17: General-purpose timers (TIM2 to TIM5)).

Aide supplémentaire (si nécessaire)

90,000,000 s’écrit sur 27 bits. Chacun des regitres étant sur 16 bits, il va falloir diviser la fréquence de l’horloge avec PSC pour obtenir une valeur inférieur à $2^{16}$ à stocker dans ARR.

Mise à jour des registres Au départ, il est conseillé dans l’ordre du programme de modifier TIM2_PSC et TIM2_ARR avant d’activer le buffer avec le bit ARPE.
Question 5 Le timer TIM2 est associé à l’interruption numéro 28. De la même manière que pour les expérimentations sur les interruptions, activez la gestion de cette interruption.
Question 6

Écrivez à présent la routine qui inversera l’état de la LED à chaque fois qu’elle sera appelée. Pensez également à réinitialiser l’interruption une fois qu’elle a été traitée. Cela peut être fait en remettant à 0 le bit UIF du registre TIM2_SR.

Comme précédemment, le système est pré-configuré pour que la routine d’interruption liée au timer TIM2 soit appelée TIM2_IRQHandler.

Question 7 Dans votre fonction main à présent, ajoutez le code pour initialiser l’état de la LED à 0.
Question 8 La configuration du timer est à présent terminée. Juste avant d’activer le compteur, réinitialisez la valeur du compteur CNT à la valeur 0 Vérifiez ensuite le bon fonctionnement de votre système.
Aide supplémentaire (si nécessaire)

En cas d’erreur, utilisez le mode de debogage de l’IDE pour visualiser l’état des registres du TIM2. Assurez-vous dans l’ordre:

  1. que le bit CEN du registre CR1 est bien activé,
  2. que le registre CNT s’incrémente correctement,
  3. que les valeurs des registres ARR et PSC ont bien été calculées,
  4. que les autres registres de configuration ont les valeurs attendus.
Question 9 On souhaite à présent réduire la fréquence de clignotement. Quel(s) registre(s) faut-il modifier ? Quel est théoriquement la vitesse de clignotement minimale possible avec une fréquence d’horloge de 180MHz et ARR/PSC sur 16 bits ?

Automatique

Dans l’exercice ci-dessus, le clignotement s’effectue avec l’intervention d’une interruption. Dans un cas idéal pour notre application finale, on souhaiterait pouvoir contrôler le clignotement de la LED en modifiant seulement une valeur de configuration: l’ajustement serait alors automatique.

Or, les timers STM32 (et notamment le TIM2) intègrent tous les éléments pour effectuer ce clignotement de manière autonome, sans intervention du logiciel après configuration. À présent, plutôt que d’utiliser une interruption, on va donc voir comment reconfigurer TIM2 pour obtenir ce fonctionnement. Pour cela, nous allons utiliser le mécanisme de PWM (Pulse Width Modulation) pour contrôler directement la sortie à l’aide du canal 1 du timer.

Question 10 Reprenez la configuration du TIM2 effectuée précédemment. Désactivez l’interruption.
Question 11 Tout d’abord, activez l’horloge de GPIOA (registre RCC_AHB1ENR). Modifiez ensuite le mode de la broche 5 du GPIOA pour qu’elle utilise le mode de fonction alternative (registre GPIOA_MODER). Modifiez ensuite le registre des fonctions alternatives (GPIOA_AFR) pour connecter la broche 5 au TIM2.
Documentation

L’ensemble des connections pour les fonctions alternatives sont disponibles page 57 de la datasheet (Chapitre 3: Pinout and pin description).

Question 12 La configuration du canal 1 s’effectue au sein du registre TIM2_CCMR1. Dans notre cas, on souhaite configurer le canal en tant que sortie, utilisez le mode 1 de PWM et activer le préchargement (preload).
Question 13 Le canal 1 n’est pas supposé générer d’interruption. Ainsi, toujours dans le registre TIM2_DIER, désactivez l’interruption pour le canal 1.
Question 14 L’activation du signal en sortie et la polarité sont configurées au sein du registre TIM2_CCER. Modifiez le registre pour activer la sortie sur l’état haut.
Question 15 À l’aide d’un schéma, représentez l’allure attendue du signal de sortie contrôlant la LED en fonction des valeurs de CNT, PSC, ARR et CCR1.
Question 16 Modifiez les registres CNT, PSC, ARR et CCR1 pour obtenir le clignotement souhaité.
Question 17

Pour notre application finale, nous aurons besoin de trois fonctions:

  1. TIM2_Init qui configure et initialise l’état du timer TIM2 au départ,
  2. TIM2_Start qui lance le fonctionnement du compteur,
  3. TIM2_Frequency qui prend en paramètre une distance en cm et fait clignoter la LED plus ou moins rapidement selon la valeur reçue. Pour information, la distance calculée mesurée peut aller de 2.5cm à 425cm. En-dessous de cet intervalle, on laissera la LED constamment allumé (ou clignotement très rapide). Au-dessus de cet intervalle, on laisse la LED constamment éteinte (ou clignotement très lent). Une stratégie envisageable est simplement de modifier la valeur du registre CCR1 selon la distance et ainsi faire varier le rapport cyclique.

Préparez ces trois fonctions pour la suite du projet. Testez ensuite leur bon fonctionnement.

Valeur entière Pour les variables, on n’utilisera uniquement des valeurs entières (pas de float). On effectuera donc des arrondis: par exemple 3 au lieu de 2.5cm.

Lecture d’un capteur HC-SR04

Capteur HC-SR04

Dans notre application de détection d’obstacle, nous avons besoin d’un mécanisme pour mesurer la distance entre notre système et un éventuel objet. Pour cela, nous allons utiliser le capteur de mesure de distance par ultrasons HC-SR04. Ce composant possède deux signaux:

  • Une entrée Trig utilisée pour commander la mesure. Chaque demande de mesure est effectuée en mettant le signal Trig à l’état haut pour au moins 10µs.
  • Une sortie Echo qui est la réponse sous forme d’impulsion. Cette impulsion est à l’état haut entre 0.15ms et 25ms. Lorsque cette valeur dépasse 38ms, alors cela signifie qu’aucun obstacle n’a été détecté. On s’assurera qu’une nouvelle mesure n’est commandée que toutes les 60ms. La distance est ensuite déduite selon le calcul suivant: $distance = (T / 58.8235)$ avec la distance en cm et T la durée de l’impulsion en µs.

Capteur HC-SR04

L’objectif des prochaines étapes va être de piloter ce capteur en utilisant le timer TIM3. Notamment, nous allons utiliser les canaux 1, 3 et 4 du TIM3. Dans l’ordre, l’objectif sera alors de lancer les opérations suivantes:

  1. Lancer d’un nouveau cycle de mesure. Placer à 1 le signal Trig en utilisant le canal 1.
  2. Au bout de 10µs, remettre le signal Trig à 0.
  3. Sauvegarder le moment du front montant du signal Echo avec le canal 3.
  4. Sauvegarder le moment du front descendant du signal Echo avec le canal 4.
  5. Adapter la fréquence en fonction de la mesure à la fin du cycle de mesure.
  6. Relancer un nouveau cycle de mesure.

Configuration générale du TIM3

Question 18 Comme pour le timer TIM2, activez l’horloge pour le timer TIM3 dans le registre RCC_APB1ENR. De même, modifiez le registre pour que le compteur soit éteint, croissant, aligné sur les fronts et que le préchargement soit bufferisé.
Question 19 Pour cette application, nous n’avons pas besoin de générer d’interruption lors d’un débordement. Il est donc nécessaire de désactiver l’interruption correspondante dans le registre TIM3_DIER.
Question 20 Pour les intéractions avec le capteur HC-SR04, la granularité de temps minimale est de l’orde de la µs. Il est également précisé que le temps minimal entre deux requêtes de mesure doit être d’environ 60 ms. Configurez les registres PSC et ARR en conséquence.

Canal 1: génération du signal Trig

Pour qu’une mesure soit effectuée, une demande doit avoir été faite sur le signal Trig. Ainsi, détecter dès que possible un obstacle implique d’effectuer de manière régulière des mesures. Pour cela, nous allons à nouveau utiliser le principe de PWM (Pulse Width Modulation) des timers. La configuration attendue sera finalement en grande partie similaire à celle du clignotement automatique de la LED: seuls la période et le rapport cyclique seront différents.

Question 21 Pour utiliser l’entrée Trig du capteur comme sortie de notre timer, il est nécessaire de la rediriger par le biais des fonctions alternatives des GPIO. À partir des spécifications de la carte Nucleo et du microcontrôleur, déduisez quelles broches peuvent être utilisées pour relier Trig à la sortie du canal 1 du timer TIM3.
Question 22 Selon votre choix, activez le port et la clock du port correspondant et utilisez la fonction alternative nécessaire pour rediriger le signal vers le canal 1 du timer TIM3.
Question 23 La configuration du canal 1 s’effectue au sein du registre TIM3_CCMR1. Dans notre cas, on souhaite configurer le canal en tant que sortie, utilisez le mode 1 de PWM et activer le préchargement (preload).
Question 24 Le canal 1 n’est pas supposé générer d’interruption. Ainsi, toujours dans le registre TIM3_DIER, désactivez l’interruption pour le canal 1.
Question 25 L’activation du signal en sortie et la polarité sont configurées au sein du registre TIM3_CCER. Modifiez le registre pour activer la sortie sur l’état haut.
Question 26 A l’aide d’un schéma, représentez l’allure attendue du signal de sortie Trig. En considérant les valeurs précédemment choisies d’ARR et PSC, à quelle valeur le signal Trig doit être mis à 0 / à 1. Modifiez le registre TIM3_CCR1 en fonction de la valeur voulue.

Canaux 3/4: réception du signal Echo

Question 27 Pour utiliser la sortie Echo du capteur comme entrée de notre timer, il est nécessaire de la rediriger par le biais des fonctions alternatives des GPIO. À partir des spécifications de la carte Nucleo et du microcontrôleur, déduisez quelles broches peuvent être utilisées pour relier Echo à l’entrée des canaux 3 ou 4 du timer TIM3.
Question 28 Selon votre choix, activez le port et la clock du port correspondant et utilisez la fonction alternative nécessaire pour rediriger le signal vers les canaux 3 ou 4 du timer TIM3.
Question 29 Le timer TIM3 dispose de 4 canaux. Le canal 1 est utilisé pour l’émission du signal Trig. D’après l’architecture du timer, pourquoi est-il alors nécessaire d’utiliser les canaux 3 et 4 pour faire les détections distinctes des fronts montants et descendants plutôt que les canaux 2 et 3 ? Expliquez avec un schéma simplifié.
Documentation

L’architecture du timer TIM3 est détaillée page 512 du manuel de référence (Chapitre 17: General-purpose timers (TIM2 to TIM5)).

Question 30 La configuration du canal 3 s’effectue au sein du registre TIM3_CCMR2. Dans notre cas, on souhaite configurer le canal en tant qu’entrée, sans filtre, sans prescaler et avec le signal IC3 connecté à TI3 (voir l’architecture). De même, désactivez l’interruption correspondante dans TIM3_DIER.
Question 31 La capture et la polarité sont configurées au sein du registre TIM3_CCER. Modifiez le registre pour activer la capture sur front montant du canal 3.
Question 32 La configuration du canal 4 s’effectue également au sein du registre TIM3_CCMR2. Dans notre cas, on souhaite configurer le canal en tant qu’entrée, sans filtre, sans prescaler et avec le signal IC4 connecté à TI3 (voir l’architecture). En revanche, la détection d’un front descendant implique que la mesure est terminée. Il est donc nécessaire d’activer l’interruption correspondante dans TIM3_DIER.
Question 33 La capture et la polarité sont configurées au sein du registre TIM3_CCER. Modifiez le registre pour activer la capture sur front descendant du canal 4.
Question 34 La routine appelée pour le timer TIM3 s’appelle TIM3_IRQHandler. Modifiez cette routine pour qu’elle calcule le nombre de cycles écoulés entre les deux fronts et stocke le résultat dans une variable globale. Pensez également à réinitialiser l’état du bit d’interruption dans le registre TIM3_SR.

Montage et test

Nous avons à présent configué le timer TIM3 afin qu’il s’interface avec le capteur HC-SR04. L’objectif va être de tester le bon fonctionnement du système et de préparer les fonctions pour l’application finale.

Question 35 Selon les broches choisies précédemment, connecté le capteur à votre carte Nucleo.
Question 36

Pour notre application finale, nous aurons besoin de trois fonctions:

  1. TIM3_Init qui configure et initialise l’état du timer TIM3 au départ,
  2. TIM3_Start qui lance le fonctionnement du timer,
  3. TIM3_IRQHandler qui est appelée par une interruption pour calculer le temps entre les deux fronts.

Préparez ces trois fonctions pour la suite du projet. Testez ensuite leur bon fonctionnement. TIM3_Init et TIM3_Start doivent être exécutées avant la boucle while. À l’aide du mode de debogage, vérifiez la valeur renvoyée par TIM3_IRQHandler après plusieurs appels.

Application finale

Nous disposons à présent de tous les éléments pour notre application de détecteur d’obstacle. Il nous reste à appeler les différentes fonctions dans notre main afin de les faire fonctionner ensemble.

Question 37 Modifiez votre fonction main pour qu’elle appelle d’abord les fonctions d’initialisations puis lance les compteurs. Dans la boucle TIM3_IRQHandler, ajoutez le code nécessaire au calcul de la distance en cm à partir de la valeur calculée et appelez la fonction TIM2_Frequency.
Question 38 Proposez une fonction qu’on appellera HCSR04_Init() responsable d’effectuer le paramétrage entier d’un timer passé en paramètre. Cette fonction devra réutiliser vos fonctions définies précédemment.
Question 39

Plusieurs optimisations sont imaginables au niveau du code conçu jusqu’à maintenant:

  • Utiliser un seul canal pour la détection des deux fronts,
  • N’appeler TIM2_Frequency depuis la boucle while que lorsque c’est nécessaire,
  • Avoir une boucle while complètement vide,

Proposez et/ou testez une ou plusieurs de ces possibles optimisations.

Communication avec une télécommande infrarouge

Télécommande infrarouge

Tout comme le capteur HC-SR04, de nombreux composants utilisent des durées variables d’état haut / bas pour transmettre des informations. Par exemple, c’est le cas du modèle standard de télécommande infrarouge illustré ci-dessous. Plus précisément, celui-ci s’appuye sur le protocole NEC, qui transmet les bits d’informations sous la forme d’impulsions.

Question 40 À partir des spécifications du protocole NEC et de la télécommande infrarouge, mettez en place un ensemble de fonctions permettant de configurer un timer afin de récupérer les informations transmises.