TP STM32 IoT

Ce TP STM32 va vous permettre de prendre en main un système d'exploitation temps-réel sur la carte IoT-Node déjà utilisée en SE203. Pour cela, nous allons utiliser les éléments suivants :

  • une carte IoT-Node
  • le système d'exploitation temps-réel pour microcontrôleurs FreeRTOS
  • l'interface ARM CMSIS (Cortex Microcontroller Software Interface Standard) permettant d'utiliser les fonctionalités communes à tous les microcontrôleurs de type Cortex-M et de fournir des abstractions adaptées aux systèmes temps-réel (RTOS v2)
  • le HAL pour STM32L4 (hardware abstraction layer) fourni par STMicro, qui facilite l'utilisation des périphériques du microcontrôleur équipant cette carte

Attention : ce TP fait partie intégrante du cours et le contrôle de connaissances comportera des questions sur les notions abordées, expliquées ou à comprendre. Assurez vous qu'il n'y ait pas de zone d'ombre.

Mise en place

La carte utilisée sera la même qu'en SE203, une STM32 IoT-node. Il vous faudra donc mettre en place les outils décrits sur cette page :

  • Les outils JLink
  • La chaîne de compilation et de développement pour arm-none-eabi
  • Un .gdbinit adapté (dans le répertoire de votre projet une fois créé) : attention, dans la définition de flash, assurez vous de faire le mon reset après le load. Pourquoi ? Demandez si vous ne comprenez pas.

Il vous faudra également installer l'outil STM32CubeMX qui servira à initialiser le projet.

Ce TP est prévu pour les systèmes Linux. Il est probable que vous puissiez vous en sortir avec OS X ou Windows, mais vous ne bénéficierez d'aucune assistance si c'est le cas.

Nous vous conseillons d'utiliser votre ordinateur personnel si cela est possible, afin que vous puissiez vous retrouver dans votre environnement préféré et ne soyez pas contraint par la place disque disponible sur votre compte à l'école.

Mon tout premier projet

Afin de vérifier que votre environnement fonctionne correctement, créez un premier projet à l'intérieur de votre dépôt avec les propriétés suivantes :

  • Sur STM32CubeMX, commencez un nouveau projet en sélectionnant uniquement le processeur correct (STM32L475VGT6). N'optez pas pour la carte (board) IoT-node, nous ferons ça plus tard.
  • Sur la vue "Pinout view", sélectionnez la broche correspondant à la LED 2 (led verte, cf. schematics de la carte), et configurez la en sortie, mode push-pull, état bas, sans pull-up ou pull-down, faible vitesse. Nommez la LED2. Ce nom devrait apparaître dans la "Pinout view".
  • Dans "Clock configuration", indiquez que vous voulez utiliser l'horloge HSI comme source de la PLL, et la sortie de celle-ci PLLCLK comme horloge système. Nous n'utiliserons pas d'horloge externe. S'il y a un problème, utilisez "Resolve Clock issue", sinon passez à la suite.
  • En revenant à "Pinout & Configuration", activez le middleware "FreeRTOS" en mode "CMSIS v2".
  • Dans la configuration de FreeRTOS, nous allons uniquement modifier, dans "Tasks and Queues", la tâche par défaut, qui sera la seule que nous utiliserons. Son nom sera "blinkTask", sa fonction principale "startBlinkTask", et nous favoriserons l'allocation statique.
  • Générez maintenant le code pour le projet, sous le nom "blink" dans votre dépôt avec la chaîne d'outils "Makefile"
  • Si vous avez un avertissement comme quoi il vaut mieux utiliser une autre source que "Systick" pour le HAL (SysTick étant utilisé par FreeRTOS), changez la source du HAL là où c'est indiqué ("Pinout & Configuration" / "System Core" / "Sys") pour choisir, par exemple, le timer 1.

Si tout va bien, en lançant make dans le répertoire "blink" de votre dépôt, un exécutable build/blink.elf (ainsi qu'un .bin et un .hex) apparaîtra.

En regardant dans le répertoire "Core", vous verrez que "main.h" contient la définition de LED2_GPIO_Port et LED2_Pin correspondant à votre définition. De plus, dans "main.c", vous trouverez une fonction main, qui initialise le HAL, les horloges puis les GPIO, dont votre port LED2 à l'état indiqué. La tâche "blinkTask" est ensuite créée, et l'environnement d'exécution de FreeRTOS est lancé.

Vous pouvez maintenant faire clignoter cette fameuse LED 2 à la fréquence d'1Hz (interprétez cette phrase comme vous le souhaitez). Pour cela, en prenant bien soin de placer la totalité de votre code utilisateur entre des balises existantes "USER CODE BEGIN" et "USER CODE END", faîtes clignoter la led en utilisant les fonctions du HAL STM32.

En ce qui concerne le délai entre deux changements d'états, plusieurs solutions s'offrent à vous :

  • Vous pouvez utiliser les fonctions de FreeRTOS (vTaskDelay par exemple) et les macros associées.
  • Vous pouvez utiliser les fonctions de CMSIS (osDelay par exemple), qui, derrière, se charge d'appeler celles de FreeRTOS, si vous voulez utiliser une interface qui vous permet de changer facilement de système d'exploitation temps-réel au prix d'une légère surcouche logicielle.

De la même manière, vous êtes libres dans toute la suite de ce TP, de choisir si vous souhaitez déclarer vos objets de synchronisation, vos ports, etc. en utilisant STM32CubeMX, ou si vous préférez le faire à la main, ou un mélange des deux.

Quoi qu'il en soit, faîtes clignoter cette led et committez votre code dans votre dépôt Git. Il doit être possible de le reconstruire juste en tapant la commande make.

On ne rappelera pas ici les étapes nécessaires pour lancer JLinkGDBServer avec les bons paramètres ou pour utiliser arm-none-eabi-gdb pour charger le code et l'exécuter.

Allez, pendant qu'on y est, une toute petite modification

Dans STM32CubeMX, indiquez dans "Pinout & Configuration" / "RCC" que vous avez un oscillateur connecté sur HSE. Dans "Clock Configuration", indiquez que cet oscillateur est à 8MHz et indiquez aussi que vous voulez que l'horloge système HCLK soit à 80MHz (c'est le maximum sur STM32L4). Regénérez le code, compilez, chargez, vérifiez que ça marche, committez dans Git. Regardez la différence d'initialisation dans "main.c".

Vous remarquerez que HAL_RCC_ClockConfig prend en paramètre le paramètre de latence à utiliser pour les accès à la flash. Plus le système est rapide, plus la flash est lente en comparaison et plus il faut l'attendre avant de signaler une erreur.

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.

 

I²C

On souhaite utiliser le capteur HTS221 (température et humidité) qui est sur la carte.

Étape 1

Dans STM32Cube, activez le port I²C sur lequel est connecté ce capteur avec une vitesse de 400kHz. C'est le seul bus I²C qui nous intéressera ici.

Étape 2

Écrivez une interface i2cll (pour low-level), sous la forme d'un fichier d'entête et d'un fichier C correspondant, permettant de :

  • écrire vers un périphérique de ce bus ;
  • lire depuis un périphérique de ce bus ;
  • écrire et lire des registres à l'adresse demandée si le périphérique concerné ce comporte comme une mémoire (comme la plupart des périphériques I²C).

Vous pouvez n'implémenter que le dernier item. Dans tous les cas, ces fonctions devront utiliser un sémaphore binaire qu'elles attendront de pouvoir prendre une fois la commande terminée, ce qui permettra au système de passer en veille. Ce sémaphore sera signalé depuis la routine d'interruption idoine, en utilisant les fonctionnalités de FreeRTOS.

Attention, on ne devra pas utiliser CMSIS-OS (les fonctions et types commençant par "os") dans cette interface et dans la suivante, nous n'utiliserons que des fonctions et types natifs de FreeRTOS.

Il faudra que ces fonctions soient appelables depuis plusieurs threads en même temps. Il vous faudra probablement utiliser un mutex pour implémenter une section critique afin de ne pas tenter d'accéder au bus I²C de manière concurrente.

Étape 3

Écrivez une interface hts221 permettant :

  • d'initialiser le périphérique et de procéder à une capture de température par seconde ; cette fonction devra être idempotente, y compris en cas d'appel depuis plusieurs threads simultanément ;
  • de procéder à une lecture de la température, appelable depuis plusieurs threads simultanément.

Il vous faudra probablement utiliser un mutex pour implémenter une section critique afin de ne pas mélanger les transactions faite envers le hts221.

Étape 4

Écrivez un programme de test qui envoie la température toutes les secondes sur le port série. Vérifiez que la carte réagit bien aux changements de température en la couvrant de votre main (sans la toucher) ou en soufflant doucement dessus.

Un peu moins de STM32CubeMX

STM32CubeMX est pratique pour :

  • déterminer l'affectation des broches ;
  • déterminer les coefficients des multiplicateurs et diviseurs d'horloge ;
  • générer le code d'initialisation en utiliser CMSIS et le HAL du processeur ;
  • générer le Makefile initial.

Il est par contre lourd dans certains cas :

  • Il utilise généralement une version de FreeRTOS qui n'est pas la dernière en date.
  • Il utilise FreeRTOS à travers la surcouche CMSIS-OS qui rajoute des surcoûts à chaque appel de fonction.
  • Il a un côté « magique » qui plaît à certains programmeurs mais déplaît à d'autres.

Nous allons donc déSTM32CubeMXiser notre application avant de l'étendre.

Copie de la structure

Une fois votre projet "button" fonctionnel, copiez les fichiers gérés par git dans un nouveau projet "tpstm32" et ajoutez les fichiers. Ce nouveau projet doit compiler. Committez dans git, pushez.

DéCMSIS-OSisation

Dans le fichier main.c généré, remplacez toutes les références à des types et fonctions de CMSIS-OS (commençant par "os") par des types et fonctions natifs de FreeRTOS. Cela nécessitera l'ajout de certains headers de FreeRTOS (lesquels ?). Enlevez l'include de "cmsis-os" et effacez tous les fichiers de la couche d'adaptation. Vérifiez que l'application fonctionne toujours après avoir modifié le Makefile, puis committez dans git et pushez.

Mise à jour de FreeRTOS

Remplacez les sources de FreeRTOS par la dernière version. Vérifiez que tout fonctionne toujours, committez, pushez.

Nettoyage du code

Enlevez tous les restes de "USER CODE BEGIN" / "USER CODE END" qui persistent. Assurez vous de comprendre le code qui reste et pourquoi vous le gardez. Testez, committez, pushez. Notez que vous pouvez aussi enlever les commentaires qui vous semblent inutiles pour alléger la structure.

Normalement, il ne reste plus qu'un programme qui utilise FreeRTOS, CMSIS pour ce qui concerne le cœur de Cortex-M et le HAL de ST pour gérer les spécificités du STM32L4.

Version alternative : Meson

Alternativement aux deux dernières étapes, vous pouvez partir du squelette donné ci-dessous qui utilise Meson et ninja pour construire l'application et y réintégrer votre code (toujours à l'endroit prévu). Vous pouvez utiliser un Makefile si vous préférez, charge à vous de le réécrire.

Fichier attachéTaille
Fichier Squelette d'application utilisant Meson et ninja74.72 Mo

Un peu de stabilité

Nous allons maintenant chercher à utiliser le capteur LSM6DSL qui intègre un accéléromètre et un gyroscope afin de mesurer, de manière stable, l'inclinaison de notre carte IoT-node dans l'axe de sa longueur. Cet exercice fonctionne de manière indépendante sur les différents axes et peut donc se généraliser sans complication.

Attention : faites simple. Une cinquantaine de lignes devrait suffire pour implémenter la totalité de ce qui est demandé ci-dessous. Si vous dépassez cette limite, demandez vous si vous ne pouvez pas factoriser ou simplifier votre code.

Principes

L'axe X du LSM6DSL se trouve à l'horizontale,dans la longueur de la carte, l'axe Y à l'horizontale dans la largeur de la carte et l'axe Z à la verticale. Nous allons faire des acquisitions des accéléromètres et des gyroscopes sur chacun de ces axes une centaine de fois par seconde et en déduire l'inclinaison de la carte dans le plan XZ (ou, dit autrement, sa rotation autour de l'axe Y).

À partir des données du vecteur d'accélération projeté sur le plan XZ et de la vitesse angulaire autour de l'axe Y, nous allons pouvoir obtenir une position stable.

Configuration

Nous allons configurer les registres du LSM6DSL de la manière suivante :

  • CTRL1_XL : accéléromètre à 104Hz, échelle de ±2g (nous n'avons pas besoin de plus, la position qui nous intéresse est statique)
  • CTRL2_G : gyroscope à 104Hz, échelle de ±125°/s
  • CTRL3_C : mode BDU (block data update) et auto-incrément

Nous utiliserons 0 pour tous les autres registres de configuration (cf. la documentation). En particulier, nous ne choisirons aucun filtre pour récupérer un signal de capteur bruité.

Programmez l'ensemble des registres de configuration (ceux commençant par CTRL_), y compris ceux qu'on laisse à 0.

Attention : si vous choisissez de configurer les registres en bloc (ce qui est conseillé, étant donné qu'ils sont situés à des adresses consécutives), assurez vous que le capteur est bien en mode auto-incrément en faisant une écriture isolée de CTRL3_C pour soit positionner ce mode au cas où il ait été déconfiguré soit faire un reset.

Récupération des données

Faîtes une boucle à 100Hz pour récupérer les données du capteur. Utilisez vTaskDelayUntil() pour que cette boucle ne dérive pas indépendamment du temps qu'elle met pour s'exécuter. Ce genre de fonctions est très utile lors de la conception de systèmes temps-réel. Il vous faudra peut-être activer cette fonctionnalité dans FreeRTOSConfig.h si ce n'est pas déjà le cas.

En déclarant votre structure de manière appropriée, vous pourrez lire en une seule fois le résultat des trois axes des deux capteurs. Voici une possible déclaration :

static struct {
  int16_t g[3];   // Gyroscope
  int16_t xl[3];  // Accelerometer
} sensors;

Vous avez alors la garantie que les déclarations se font dans l'ordre indiqué, sans trou entre les tableaux.

Vérification du temps disponible

A-t-on le temps de faire ces lectures I²C 100 fois par seconde ? Combien de temps prend chaque lecture ?

Pour lire ces 12 octets, il faut :

  • Envoyer une demande d'écriture pour indiquer l'index : 1 bit de start, 8 octets pour l'adresse du périphérique, 1 bit de ack, 8 octets pour l'adresse à lire, 1 bit de ack, 1 bit de stop ; soit 20 bits.
  • Lire le résultat : 1 bit de start, 8 octets pour l'adresse du périphérique, 1 bit de ack, 12 octets avec chacun un ack (ou un nack pour indiquer qu'on a fini la lecture), 1 bit de stop ; soit 119 bits.

Il faut donc échanger au total 139 bits. Si le bus I²C est configuré à 400kHz, cela prend donc 139 / 400000 = 0,0003475 seconde. Tout va bien, on pourrait même faire ces calculs en configurant les capteurs à 1,66kHz sans aucun problème. Par contre, pour augmenter la fréquence au delà (le LSM6DSL va jusqu'à 6,66kHz), il faudrait passer par le bus SPI qui permet des vitesses plus grandes.

Interprétation des données

Affichez les valeurs reçues pour l'accéléromètre et le gyroscope. Les valeurs s'interprètent ainsi : chaque valeur est comprise entre -32768 et 32767 (16 bits) et couvre la sensibilité programmée pour chaque capteur. Ainsi, une force égale à 1g appliquée sur un axe donnera, avec la sensibilité de ±2g que nous avons choisie, une valeur d'environ ±16384 selon le sens d'application.

Pour ne pas perturber trop les mesures par le temps de transmission sur le port série, nous n'enverrons ces informations qu'une fois sur 100 (une fois par seconde).

Détermination de l'inclinaison grâce à l'accéléromètre

En utilisant la fonction atan2(), déterminez la valeur de l'orientation autour de l'axe Y et affichez cette valeur multipliée par 100. On souhaite que 0 corresponde à la position de repos normale (horizontale) de la carte, ±9000 à la carte posée sur la tranche.

Détermination de l'inclinaison grâce au gyroscope

Vous vous souvenez du cours qu'un gyroscope a une dérive fixe et dérive lentement. Après avoir attendu qu'une mesure soit disponible (par exemple après un délai d'un centième de secondes), faîtes une première mesure du gyroscope et stockez la valeur comme étant son drift (dérive). Cette valeur sera soustraite aux mesures suivantes, en espérant que la dérive sera lente par rapport à notre expérience. Idéalement il faudrait un filtre passe-haut.

En partant d'une inclinaison initiale de 0°, stockée dans une variable en virgule flottante, ajoutez à chaque itération la variation relevée par le gyroscope. N'oubliez pas que les rotations pour les valeurs limites correspondent à un nombre de degrés par seconde. Il ne s'écoule qu'1/100ème de seconde entre chaque tour de boucle, il faut donc en tenir compte lors du calcul.

Affichez, une fois par seconde, la valeur de l'angle calculée à l'aide du gyroscope multiplié par 100. Assurez vous que vos deux valeurs sont orientées dans le même sens.

Filtre complémentaire

Maintenez séparément des autres valeurs une variable en virgule flottante représentant l'angle indépendante des capteurs individuels. À chaque itération :

  • Prenez 95% de la valeur de l'angle corrigé par la variation indiquée par le gyroscope (en soustrayant le drift).
  • Incorporez-y 5% de la valeur calculée à partir de l'accéléromètre.
  • Ceci donne le nouvel angle.

Toutes les secondes, affichez les trois valeurs multipliées par 100 : l'angle calculé à partir de l'accéléromètre, à partir du gyroscope, et après le filtre complémentaire. Les plus courageux afficheront de manière interactive les différentes orientations (en lisant /dev/ttyACM0 ou équivalent depuis un programme) afin de pouvoir en visualiser la stabilité.

Vous pouvez également configurer le filtre pour des coefficients respectifs de 98%/2% et observer l'influence sur la stabilité ainsi que sur le temps de réaction du système lorsque vous bougez la carte.

Amélioration de la précision

Nous avons vu qu'avec un bus I²C à 400kHz nous pouvions opter pour des mesures à une fréquence de 1,66kHz. Configurez les accéléromètres et gyroscopes pour cette fréquence, et faites un relevé toutes les millisecondes tout en affichant toujours les résultats toutes les secondes. Vous pourrez constater la stabilité conservée et l'amélioration du temps de réaction du dispositif face à des changements d'orientation.

Séparation du calcul et de l'affichage

Afin de rendre les mesures plus régulières :

  • Écrivez chaque seconde et de manière non bloquante les 3 mesures dans une file d'attente (queue) de FreeRTOS sans rien afficher et rendez cette tâche de calcul plus prioritaire.
  • Dans une autre tâche de priorité moindre, affichez les valeurs en provenance de la file d'attente au fur et à mesure de leur arrivée.