Programmation de microcontrôleurs STM32: GPIO
Cette page vise à présenter une première utilisation des GPIO 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 GPIO,
- De programmer les différents registres pour différentes utilisations des GPIO (LED, bouton-poussoir etc.)
Clignotement d’une LED
Pour la première partie, on se propose de concevoir un programme faisant clignoter la LED d’une carte. Notamment, la carte Nucleo-F446RE dispose d’une LED directement intégrée sur la carte. Elle est connectée sur la broche (pin) 5 du port GPIO A.
Les différentes informations dont nous aurons besoin par la suite sont disponibles dans deux documents. Le manuel utilisateur des cartes Nucleo-64 (dont fait partie la Nucleo-F446RE) regroupe les différentes informations propres à la carte (caractéristiques de la carte, branchements existants etc.). Le manuel de référence des microcontrôleurs STM32 F446XX donne lui toutes les informations propres au microcontrôleur lui-même (bus mémoires, mémoires, registres et périphériques etc.).
Du point de vue d’un microcontrôleur, allumer/éteindre une LED est similaire: cela revient à configurer différents registres en mémoire pour forcer une valeur en sortie à 1 / 0.
Les prochaines questions s’intéressent donc à la manière de configurer un GPIO en tant que sortie.
Pour modifier les registres d’un GPIO, il est nécessaire de savoir dans quel(s) registre(s) et partie(s) de registre(s) il est nécessaire d’écrire. En utilisant le manuel de référence (Chapitre 7: General Purpose I/Os), repérez les valeurs de registres nécessaires pour configurer le GPIO du port A ainsi:
- MODE: General purpose output mode,
- TYPE: push-pull,
- DATA: 1.
On laissera pour l’instant les autres paramètres inchangés.
MODER, OTYPER, IDR …
Un pointeur de structure GPIOA existe pour le PORTA.
On peut accéder à la valeur de chaque registre du port en utilisant l’opérateur ->: GPIOA->MODER.
En utilisant ce mécanisme, initialisez les registres nécessaires pour obtenir la configuration de la précédente et ainsi allumer la LED verte.gpio_set_pin et gpio_reset_pin vous permettant respectivement d’allumer ou éteindre la LED.main pour faire clignoter notre LED à une vitesse visible.
Pour cela, l’idée va être d’appeler à tour de rôle les fonctions respectives au sein de la boucle while(1).
Pour créer l’effet de clignotement, ajouter entre les appels de chaque fonction des boucles pour insérer du délai dans le temps d’exécution.
Le microcontrôleur tournant à plusieurs dizaines de MHz, pensez à ajouter suffisamment de tours de boucles entre les appels pour que le délai soit suffisant.Détection d’un bouton poussoir
Faire clignoter une LED implique d’utiliser un GPIO en tant que sortie. Cependant, un GPIO peut aussi également être utilisé en tant qu’entrée pour lire une valeur externe. C’est nécessaire par exemple si l’on souhaite connaître l’état d’un bouton poussoir (pressé ou non). Ce dernier est le sujet de cette seconde partie.
La carte Nucleo-F446RE dispose d’un bouton poussoir directement intégré sur la carte.
Celui-ci est connecté à la broche 13 du port GPIO C.
Lorsque le bouton est pressé, l’entrée est connectée à la masse (valeur logique de 0).
Sinon, l’entrée est considérée comme flottante (haute impédance).
Une résistance de rappel vers VDD est alors nécessaire pour détecter ce cas.
En utilisant le manuel de référence (Chapitre 7: General Purpose I/Os), repérez les valeurs de registres nécessaires pour configurer le GPIO du port C ainsi:
- MODE: Input,
- RESISTANCE DE RAPPEL: pull-up.
On laissera pour l’instant les autres paramètres inchangés.
0 ou 1.
Utilisez le mode debug pour vérifier que la variable prend bien la bonne valeur selon que vous poussez le bouton ou non.Aide supplémentaire (si nécessaire)
Pour traiter la valeur lue dans le registre et isoler le bit utile, réutilisez le principe du masquage binaire.
Pour cela, appliquez un masque qui remettra à 0 tous les bits non-utilisés.
Ensuite, pensez à décaler vers la droite la valeur pour passer le bit utile en position 0.
main pour qu’elle allume la LED lorsque le bouton est pressé.main pour que l’état de la LED soit inversé à chaque nouvelle pression du bouton-poussoir.Aide supplémentaire (si nécessaire)
Pour détecter que le bouton poussoir a été pressé une nouvelle fois, il est nécessaire de détecter qu’il a été relâché entre temps. Pour cela, le plus simple est de stocker à chaque fois l’état du bouton dans une variable. Si le bouton n’était pas pressé la fois précédente alors qu’à présent c’est le cas, alors cela signifie que c’est une nouvelle pression.
Aide supplémentaire (si nécessaire)
Par rapport aux questions précédentes, une nouvelle information est maintenant nécessaire: le nombre de pressions du bouton.
Ainsi, à chaque fois, qu’une pression est détectée, il faudra incrémentée une variable puis l’utiliser pour décider de garder la LED à 1 ou pas.
Développement d’une surcouche logicielle
L’utilisation de registres par le logiciel est directement dépendant du matériel. Ainsi, si l’adresse d’un des ports est modifiée, il est alors nécessaire de réadapter l’ensemble du code qui en dépend. Généralement, une surcouche logicielle est donc mise à disposition avec des fonctions qui s’occupent de paramétrer les registres en fonction des besoins. De ce fait, si la plateforme matérielle change, alors seules ces fonctions seront à adapter pour que l’application finale continue de fonctionner.
Sur la plateforme Arduino, des fonctions sont par exemple mises à disposition pour configurer les entrées/sorties. L’objectif de cette partie est simplement de reproduire cette fonctionnalité directement avec du langage C.
À partir de ces informations, concevez une fonction gpio_mode responsable de changer le mode d’une broche.
Elle devra prendre en paramètre:
- Le port GPIO à modifier,
- Le numéro de la broche,
- Le mode utilisé.
Dans notre cas, on définira les modes suivants:
- OUTPUT (sortie + push/pull),
- INPUT (entrée + pas de pull-up/pull-down),
- INPUT_PULLUP (entrée + pull-up),
- INPUT_PULLDOWN (entrée + pull-down).
Aide supplémentaire (si nécessaire)
Voici l’en-tête de la fonction attendue:
void gpio_mode(GPIO_TypeDef *GPIO, uint8_t pin, uint8_t mode);
Les différentes valeurs des modes peuvent ensuite être fixées par des macros:
#define OUTPUT 0
#define INPUT 1
#define INPUT_PULLUP 2
#define INPUT_PULLDOWN 3
gpio_output_set qui met la valeur de sortie d’une broche de GPIO à 1.gpio_output_reset qui met la valeur de sortie d’une broche de GPIO à 0.gpio_output_inv qui inverse la valeur de sortie d’une broche de GPIO.gpio_input renvoyant 0 ou 1 selon la valeur d’entrée d’une broche de GPIO.gpio_mode, gpio_output_set, gpio_output_reset et gpio_input