Un peu plus de STM32CubeMX

Nous allons continuer à profiter des services de STM32CubeMX. Créez un nouveau projet "button", mais cette fois choisissez comme point de départ la carte (board) plutôt que le microcontrôleur (MCU). Le petit nom de votre carte IoT-node se trouve sur un autocollant à fond blanc placé sur la carte.

Lorsque le logiciel vous en donne l'opportunité, demandez à ne pas initialiser tous les périphériques dans leur état par défaut. Vous verrez toutefois que les broches ont été libellées de manière appropriée correspondant à la documentation de votre carte.

Configuration de base

On ne peut pas utiliser l'horloge externe HSE sur la carte IoT-node : sur les schémas, le quartz à 8MHz et les composants associés sont notés comme "Not fitted" (non soudés). Si on regarde le PCB, on peut voir que l'emplacement est disponible si on souhaite les rajouter, mais par défaut ils n'y sont pas, nous utiliserons donc HSI.

Dans votre projet :

  • Configurez l'horloge principale HCLK à 80MHz, en utilisant HSI et en passant à travers la PLL.
  • Vérifiez que la led verte (LED2), les leds jaune et bleue (LED3_WIFI_LED4_BLE) et le bouton bleu (BUTTON_EXTI13) sont bien configurés respectivement en sortie push-pull et en mode interruption externe sur front descendant. Regardez dans la datasheet de la carte comment sont connectées les leds au microcontrôleur. Comprenez-vous comment fonctionne LED2 ? Et LED3_WIFI_LED4_BLE ? Pourquoi n'y a-t-il pas besoin d'activer de pullup internes sur le bouton ?
  • Activez FreeRTOS en mode CMSISv2, et choisissez un autre timer (TIM7 par exemple) pour la source de temps du HAL (dans SYS).

Dans la configuration de FreeRTOS créez trois entités :

  • Une tâche blinkTask, initialisée statiquement, dont le rôle sera de faire clignoter la led verte pour vérifier que le système continue bien d'avancer.
  • Une tâche buttonTask, initialisée statiquement elle aussi, dont le rôle sera d'attendre un appui sur le bouton pour piloter les leds bleu et jaune.
  • Un sémaphore binaire buttonPressed, initialisé statiquement, dont le rôle sera d'indiquer si le bouton a été appuyé.

Traitement de l'interruption

  • Dans le code généré, cherchez ce qui se passe lorsqu'on appuie sur le bouton bleu. Commencez par la table des vecteurs dans startup_stm32l475xx.s, continuez dans Src/stm32l4xx_it.c, fouillez dans Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_gpio.c. Implémentez la fonction demandée dans Src/main.c en signalant le sémaphore binaire buttonPressed. Vous pourrez noter qu'il aurait été possible d'utiliser une autre partie du HAL, Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_exti.c, pour gérer le bouton, mais ce n'est pas le choix fait par STM32CubeMX.

Programme principal

  • Dans la tâche blinkTask, faîtes clignoter la led verte à une fréquence de 1Hz.
  • Dans la tâche buttonTask, en boucle, attendez de pouvoir prendre le sémaphore buttonPressed, puis inversez les leds jaune et bleue.
  • Testez votre code.

Votre code ne fonctionne probablement pas correctement. Pourquoi ? En utilisant gdb, vous pourrez voir qu'il y a un problème avec les priorités.

En fait, afin de protéger ses structures de données, FreeRTOS interdit de faire des appels à des fonctions du RTOS depuis des ISR trop prioritaires. En effet, lorsqu'il est en train de modifier des structures relatives aux threads, aux sémaphores, etc., il bloque les interruptions de priorité numériquement supérieure à LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY (sur STM32, cela signifie des interuptions moins prioritaires, 0 étant la plus grande priorité). Puisque vous voulez signaler un sémaphore depuis votre routine d'interruption, il faut que vous puissiez être bloqué par FreeRTOS lorsqu'il entre dans ses sections critique ; la priorité de votre IRQ doit donc être numériquement supérieure ou égale à 5. Changez la dans la catégorie NVIC de STM32CubeMX, regénérez le code, et profitez d'un programme qui marche.

Port série

Le premier port série (USART1) du STM32 est connecté au module STlink, qui le connecte lui-même à travers USB à l'hôte pendant les séances de développement ou de déverminage. Ainsi, en utilisant ce port série à une vitesse de 115200 bits par seconde, en mode 8 bits, sans bit de parité et un bit de stop, nous pourrons échanger des informations avec un port série virtuel sur notre ordinateur. Sous Linux, il sera nommé par exemple /dev/ttyACM0, et on pourra utiliser le programme tio pour s'y connecter (tio /dev/ttyACM0). Attention, si vous avez un processus "modem manager" qui tourne sur votre ordinateur, désactivez le (idéalement de manière permanente) afin qu'il n'interfère pas avec le port série en essayant de découvrir quel modem vous avez bien pu brancher.

Passons à l'implémentation :

  • Dans STM32CubeMX, activez le port série USART1 en mode UART (asynchrone) sans contrôle de flux. Les paramètres par défaut (115200 8N1) nous conviennent.
  • Regénérez le code du projet. Normalement, vos parties ont été préservées, pour peu que vous les ayez placées entre les balises "USER CODE BEGIN" et "USER CODE END". Sinon, recommencez tout.
  • Dans la tâche buttonTask, envoyez la chaîne de caractère "Waiting for button presses\r\n" (sans les guillemets) sur le port série.
  • Dans cette même tâche, envoyez à chaque appui de bouton, en addition du changement de leds, l'information "Button press count: XXX\r\n"XXX est en décimal le nombre d'appuis sur le bouton. Oui, il va falloir écrire un peu de code de formatage.

Watchdog indépendant

Activez le watchdog indépendant (IWDG) dans STM32CubeMX avec les paramètres par défaut et regénérez le code sans rien faire d'autre. Compilez, exécutez : la carte reboote elle bien toute seule spontanément ?

Le délai, comme indiqué dans la documentation du STM32, est égal à la période de l'horloge alimentant le watchdog multipliée par le prescaler et comptant à partir de la window value (qu'on laissera maximale car on veut utiliser le watchdog en mode simple, non fenêtré). Déduisez en le temps de grâce avant que le système ne redémarre. Configurez ce temps en modifiant le prescaler pour qu'il soit strictement supérieur à 1 seconde, mais pas trop. Regénérez, compilez, exécutez. La valeur semble-t-elle correcte ?

Modifiez maintenant votre code pour rafraîchir le watchdog (il existe une fonction du HAL pour cela) une fois par seconde. Compilez, exécutez, la carte ne devrait plus rebooter spontanément.

Assurez vous maintenant que vous comprenez le rôle de tous les fichiers générés à la racine du projet, dans Inc et Src, ainsi que dans les sous-répertoires. Vous devez retrouver tout ce que vous connaissez (startup, vecteurs, main, configuration des horloges, etc.). Portez également une attention particulière à FreeRTOSConfig.h et au Makefile, car c'est ce que vous devrez configurer en premier si vous décidez d'utiliser FreeRTOS sans STM32CubeMX.