Optimisation énergétique STM32: un guide pratique

Bonjour, Habr!

Il existe de nombreux articles sur le réseau concernant le fonctionnement des microcontrôleurs STM32 dans les appareils éconergétiques - généralement des appareils alimentés par batterie - mais il y en a malheureusement peu qui ne comprennent pas ce sujet en dehors de la liste des modes d'économie d'énergie et des commandes SPL / HAL qui les incluent (cependant, la même affirmation s'applique) à la grande majorité des articles sur l'utilisation de STM32).

Pendant ce temps, en raison du développement rapide des maisons intelligentes et de toutes sortes d'IoT, le sujet devient de plus en plus pertinent - dans de tels systèmes, de nombreux composants sont alimentés par batterie et des années de fonctionnement continu sont attendues de leur part.

Nous comblerons cette lacune par l'exemple du STM32L1 - un contrôleur très populaire, assez économique et en même temps ayant des problèmes spécifiques à cette série. Presque tout ce qui précède s'appliquera également aux STM32L0 et STM32L4, et en termes de problèmes et d'approches communs, aux autres contrôleurs basés sur des cœurs Cortex-M.



Le résultat pratique devrait ressembler à la photo ci-dessus (et oui, nous parlerons également de l'applicabilité des multimètres et autres instruments de mesure à des tâches similaires).

Modes d'économie d'énergie dans STM32L1


Les principes de base de l'économie de batterie sont les principaux modes d'économie d'énergie du processeur. Chaque fabricant et chaque série de contrôleurs ont leurs propres (un ensemble spécifique est une extension du fournisseur des modes de base Cortex-M standard avec diverses nuances concernant la périphérie, les tensions d'alimentation, etc.).

Plus précisément, le STM32L1, qui appartient à la série économique des contrôleurs, et à cet égard, entre autres, a reçu un ensemble étendu de paramètres d'alimentation, nous avons les éléments suivants:

  • Exécuter - mode normal. Tout compris, tous les périphériques disponibles, fréquence jusqu'à 32 MHz.
  • Low Power Run (LP Run) - un mode spécial avec une fréquence de fonctionnement de 131 kHz et une consommation maximale, compte tenu de toute la périphérie , 200 μA. En mode LP Run, le régulateur de puissance du processeur passe dans un mode économique spécial, qui économise jusqu'à cinquante microampères par rapport au fonctionnement à la même fréquence en mode Run.
  • Sommeil - suspension du noyau, mais avec conservation de toutes les fréquences d'horloge. Les périphériques du processeur peuvent continuer à fonctionner si le noyau n'en a pas besoin, mais il peut être automatiquement désactivé.
  • Veille à faible puissance (LP Sleep) - une combinaison de veille avec la transition du stabilisateur en mode économie. La fréquence d'horloge n'est pas supérieure à 131 kHz, la consommation totale n'est pas supérieure à 200 μA.
  • Stop - un arrêt complet de toutes les fréquences d'horloge, à l'exception du générateur «d'horloge» 32768 Hz, externe ou interne. Dans le cas de STM32L1, seule l'horloge en temps réel continue de fonctionner dans ce mode, tout le reste s'arrête complètement; dans les processeurs plus récents, certains périphériques peuvent être cadencés à basse fréquence. Presque toutes les branches du processeur conservent leur état. Le contenu de la RAM est enregistré, les interruptions externes continuent de fonctionner.
  • Veille - un arrêt complet du cœur du processeur, de la RAM et de tous les périphériques, à l'exception des horloges en temps réel. La RAM n'est pas sauvegardée (c.-à-d. Du point de vue du logiciel, laisser en veille équivaut presque à déformer l'alimentation - recommencer depuis le début), RTC continue de cocher. Les interruptions externes ne fonctionnent pas, à l'exception de trois segments WKUPx spéciaux, dont la commutation de 0 à 1 réveille le processeur.

L'entrée dans chacun des modes est assez simple - vous devez définir les drapeaux dans trois à cinq registres, après quoi (pour les modes de veille) appeler l'instruction WFI ou WFE, il s'agit de l'instruction Cortex-M standard, signifie «Attendre une interruption» et «Attendre un événement» . Selon les drapeaux (ils sont décrits dans le Manuel de référence du processeur, pour STM32L1 c'est RM0038 ), le processeur lui-même passera dans ce mode sur cette commande.

De plus, il serait bon d'interdire les interruptions (cela n'affectera pas la capacité des événements externes et internes à sortir le processeur du sommeil) et d'attendre que les données soient enregistrées des registres dans la mémoire si cela se produit soudainement, en utilisant la commande DSB.

Par exemple, voici à quoi ressemble le passage en mode Stop:

/*  PDDS    Stop  Standby,    */ PWR->CR &= ~(PWR_CR_PDDS); /*  Wakeup   ,      */ PWR->CR |= PWR_CR_CWUF; /*    low-power ,    Stop -    */ PWR->CR |= PWR_CR_LPSDSR; /*    Vref   */ PWR->CR |= PWR_CR_ULP; /*     Cortex-M,  Stop,  Standby -   Deep Sleep */ /*      Deep Sleep */ SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk); /*  ;       */ unsigned state = irq_disable(); /*      */ __DSB(); /*  */ __WFI(); /*    */ init_clk(); /*     */ irq_restore(state); 

WFI est une instruction de blocage, le processeur entrera en veille profonde et ne le quittera pas avant qu'une sorte d'interruption ne se produise. Oui, je le répète, malgré le fait que nous ayons explicitement désactivé les interruptions, le processeur y répondra et se réveillera - mais il ne commencera le traitement qu'après que nous les ayons réactivé. Et cela a un sens profond.

Dans le code ci-dessus, après WFI, une réinitialisation des fréquences de fonctionnement ne se produit pas seulement - le fait est que L1 quitte toujours le sommeil profond à une fréquence de 4,2 MHz et avec un générateur MSI interne comme source de cette fréquence. Dans de nombreuses situations, vous ne voulez évidemment pas que le gestionnaire d'interruption qui réveille le processeur commence à fonctionner à cette fréquence - par exemple, car les fréquences de tous les temporisateurs, UART et autres bus s'envoleront; par conséquent, nous restaurons d'abord les fréquences de fonctionnement (ou, si nous voulons rester sur MSI, recalculons les bus nécessaires sous 4,2 MHz), puis nous plongons dans les interruptions.

En pratique, les deux modes les plus couramment utilisés sont Run et Stop. Le fait est que LP Run est douloureusement lent et n'a aucun sens si le processeur doit effectuer des calculs et ne pas simplement attendre des événements externes, et Sleep et LP Sleep ne sont pas trop économiques (consommation jusqu'à 2 mA) et sont nécessaires si vous en avez besoin économiser au moins un peu, mais en même temps laisser les périphériques de travail et / ou fournir la réaction la plus rapide possible du processeur aux événements. De telles exigences existent, mais dans l'ensemble pas très souvent.

Le mode veille n'est généralement pas utilisé, car après qu'il est impossible de continuer à partir de l'endroit où vous vous étiez arrêté en raison de la mise à zéro de la RAM, il existe également des problèmes avec les périphériques externes, dont nous discuterons ci-dessous, qui nécessitent des solutions matérielles. Cependant, si l'appareil a été conçu dans cet esprit, la veille peut être utilisée comme un mode «off», par exemple, pendant le stockage à long terme de cet appareil.

En fait, sur la présentation de cela, la plupart des manuels se détachent généralement triomphalement.

Le problème est que, en les suivant, vous obtiendrez une triste consommation de 100 à 200 μA de consommation réelle au lieu des 1,4 μA promis en Stop avec les heures de travail - même sur le débogage de référence Nucleo, qui n'a pas de puces, capteurs, etc. externes. à laquelle il pourrait être attribué.

Et non, votre processeur fonctionne, il n'y a rien dans les errata et vous avez tout fait correctement.

Mais pas jusqu'au bout.

Syndrome des jambes sans repos


Le premier problème STM32L1, dont certains articles mentionnent, mais ne se souviennent souvent que sur les forums, lorsque le troisième jour de discussion, d'où viennent les 100-200 μA, quelqu'un se souvient de l'existence de l' AN3430 et atteint la page 19 de celui-ci - ce état des jambes par défaut.

Je note que même STMicro lui-même fait référence au problème à travers les manches, et dans la plupart des documents où l'optimisation de la consommation d'énergie est envisagée, il est limité à une ou deux phrases avec le conseil de tirer les jambes inutilisées au sol ou de passer en mode d'entrée analogique, sans expliquer les raisons.

Ce qui est triste, c'est que par défaut, toutes les jambes sont configurées comme entrées numériques (0x00 dans le registre GPIOx_MODER). Un déclencheur Schmitt est toujours sur l'entrée numérique, ce qui améliore l'immunité au bruit de cette entrée, et il est complètement indépendant - c'est un élément logique simple, un tampon avec hystérésis qui ne nécessite pas d'horloge externe.

Dans notre cas, cela signifie que nous avons éteint l'horloge en mode Stop, et les déclencheurs Schmitt ont continué à fonctionner comme si de rien n'était - en fonction du niveau du signal d'entrée, ils commutent leurs sorties sur 0 et 1.

Dans le même temps, une partie des jambes du processeur dans un circuit typique est suspendue dans l'air - c'est-à-dire qu'il n'y a aucun signal intelligible sur elles. Il serait faux de penser que l'absence d'un signal clair signifie que sur ces jambes 0 ne l'est pas, sur ces jambes en raison de leur impédance d'entrée élevée, il y a un bruit aléatoire d'une valeur indéterminée, provenant des micros et du courant circulant des pistes voisines vers la première chaîne de télévision, si le pied est assez long pour servir d'antenne (cependant, les téléviseurs analogiques en Russie seront bientôt éteints, ce qui devrait entraîner une certaine réduction de la consommation d'énergie des microcontrôleurs mal configurés).

Conformément à ces fluctuations, la jambe bascule de façon aléatoire entre 0 et 1. La logique CMOS consomme du courant lors de la commutation. C'est-à-dire qu'une jambe de processeur suspendue en l'air, configurée en mode d'entrée numérique, consomme un courant perceptible en soi .

La solution est simple: lorsque vous démarrez le programme, vous devez configurer toutes les branches à l'état de l'entrée analogique; STM32 l'a formellement pour toutes les jambes sans exception, qu'elles soient connectées ou non à l'ADC, et ne diffère de l'entrée numérique qu'en l'absence d'un déclencheur Schmitt à l'entrée.



Pour ce faire, il suffit d'écrire la valeur 0xFF ... FF dans tous les registres GPIOx_MODER, il est plus facile de le faire, comme mentionné ci-dessus, dès le début, puis au cours du jeu, vous reconfigurerez les jambes individuelles selon les besoins de cet appareil.

Ici, cependant, un problème de second ordre se pose - c'est bien si votre micrologiciel fonctionne sur un contrôleur spécifique, et donc vous savez toujours ce que x est dans GPIOx. Pire encore si le firmware est universel - le STM32 peut avoir jusqu'à 8 ports, mais il peut être plus petit; lorsque vous essayez d'écrire sur un port qui n'existe pas dans ce modèle de contrôleur, vous obtiendrez Hard Fault, c'est-à-dire crash du noyau.

Cependant, même ce cas peut être contourné - Cortex-M vous permet de vérifier la validité des adresses, d'ailleurs, dans le cas de M3 et M4, le contrôle est généralement trivial, et sur M0 il nécessite un peu de magie, mais il est réalisable (les détails peuvent être lus ici , nous ne fan pas cet article )

Autrement dit, le processeur a démarré, réglé les fréquences - et a immédiatement parcouru tous les ports GPIO disponibles, en les écrivant sur ceux MODER (le code ci-dessous est écrit pour RIOT OS, mais en général, il est clair sans commentaire et peut être transféré en trois minutes toute autre plateforme).

 #if defined(CPU_FAM_STM32L1) /* switch all GPIOs to AIN mode to minimize power consumption */ GPIO_TypeDef *port; /* enable GPIO clock */ uint32_t ahb_gpio_clocks = RCC->AHBENR & 0xFF; periph_clk_en(AHB, 0xFF); for (uint8_t i = 0; i < 8; i++) { port = (GPIO_TypeDef *)(GPIOA_BASE + i*(GPIOB_BASE - GPIOA_BASE)); if (cpu_check_address((char *)port)) { port->MODER = 0xffffffff; } else { break; } } /* restore GPIO clock */ uint32_t tmpreg = RCC->AHBENR; tmpreg &= ~((uint32_t)0xFF); tmpreg |= ahb_gpio_clocks; periph_clk_en(AHB, tmpreg); #endif 

Je note que cela ne s'applique qu'à la série L1, dans L0 et L4, l'expérience a été prise en compte et, par défaut, ils configurent tous les ports comme entrées analogiques au démarrage.

Après avoir soigneusement effectué toutes ces procédures, vous remplissez le firmware dans l'appareil fini ... et obtenez 150 uA en mode Stop sur le processeur et toutes les puces externes désactivées, malgré le fait que vos estimations soient les plus pessimistes, provenant des fiches techniques pour tout ce que vous avez soudé sur la carte ne donne pas plus de 10 μA.

De plus, vous essayez de mettre le processeur en veille plutôt qu'en arrêt, c'est-à-dire il suffit de l'éteindre presque complètement - et au lieu de baisser, la consommation d'énergie triple, s'approchant de près d'un demi-milliampère!

Pas besoin de paniquer. Comme vous l'avez peut-être deviné, vous avez tout fait correctement. Mais pas jusqu'au bout.

Syndrome des jambes sans repos - 2


Le problème suivant comporte deux parties.

La première est assez évidente: si votre appareil ne se compose pas d'un seul microcontrôleur, il est important de ne pas oublier que les puces externes ont également des signaux d'entrée sur lesquels les déclencheurs Schmitt se bloquent et qui, de plus, peuvent réveiller la logique interne de la puce. Par exemple, une puce qui est retirée et retirée de son sommeil par l'équipe UART essaiera de lui lire des données avec n'importe quel mouvement sur ce bus.

Par conséquent, si toutes ces jambes sont suspendues en l'air, nous n'obtiendrons rien de bon.

Dans quelles conditions finissent-ils dans l'air?

Premièrement, lorsque le contrôleur passe en mode veille, tous les GPIO sont transférés à l'état High-Z, avec une résistance élevée - c'est-à-dire que les puces externes qui leur sont connectées sont en l'air. Il est impossible de résoudre ce problème par programme dans STM32L1 (dans d'autres séries et d'autres contrôleurs, cela se produit de différentes manières), par conséquent, la seule issue est dans un système qui utilise le mode veille, les entrées des puces externes doivent être tirées à la terre ou alimentées par des résistances externes.

Un niveau spécifique est choisi pour que la ligne soit inactive du point de vue de la puce:

  • 1 pour UART TX
  • 0 pour SPI MOSI
  • 0 pour SPI CLK en mode SPI 0 ou 1
  • 1 pour SPI CLK avec SPI Mode 2 ou 3
  • 1 pour SPI CS

Deuxièmement, sur STM32 lors de l'utilisation du mode Stop (sic!) , L' état des GPIO connectés aux blocs matériels internes des interfaces peut être ... différent. C'est-à-dire que la même interface SPI, lorsqu'elle est configurée, dans Stop se révèle soudainement être soit une entrée numérique, soit, en général, High-Z - avec les conséquences correspondantes pour les puces externes qui s'y accrochent. Bien que la documentation indique que les jambes sont en bon état, vous ne pouvez a priori vous y fier que si vous utilisez vos jambes en tant que GPIO ordinaires.

Vous ne pouvez pas le comprendre et le pardonner, mais vous pouvez vous en souvenir et le réparer: pour les interfaces qui se comportent de cette façon, vous devez ajouter la commutation forcée au GPIO normal avec des niveaux correspondant aux niveaux inactifs de cette interface dans la fonction de soin du sommeil. Après s'être endormi, les interfaces peuvent être restaurées.

Par exemple, le même SPI avant de s'endormir (pour plus de simplicité, je reprends le code du RIOT OS, il est clair que le même est facile à implémenter sur les registres):

 /* specifically set GPIOs used for external SPI devices */ /* MOSI = 0, SCK = 0, MISO = AIN for SPI Mode 0 & 1 (CPOL = 0) */ /* MOSI = 0, SCK = 1, MISO = AIN for SPI Mode 2 & 3 (CPOL = 1) */ for (i = 0; i < SPI_NUMOF; i++) { /* check if SPI is in use */ if (is_periph_clk(spi_config[i].apbbus, spi_config[i].rccmask) == 1) { /* SPI CLK polarity */ if (spi_config[i].dev->CR1 & (1<<1)) { gpio_init(spi_config[i].sclk_pin, GPIO_IN_PU); } else { gpio_init(spi_config[i].sclk_pin, GPIO_IN_PD); } gpio_init(spi_config[i].mosi_pin, GPIO_IN_PD); gpio_init(spi_config[i].miso_pin, GPIO_AIN); } } 

Veuillez noter que les sorties ici ne sont pas configurées en tant que GPIO_OUT avec un niveau de 0 ou 1, mais en tant qu'entrées avec un pull-up à 0 ou 1 - ce n'est pas un point fondamental, mais offre une sécurité supplémentaire si vous faites une erreur et essayez de jouer au pull-push avec une sorte de une puce externe tirant cette jambe dans l'autre sens. Avec GPIO_OUT, vous pouvez organiser un court-circuit, avec GPIO_IN avec un pull-up - jamais.

De plus, le signal SPI CS n'est pas affecté - dans ce cas, il est généré par programme, c'est-à-dire par un GPIO normal, et il conserve son état dans un rêve en toute confiance.

Pour restaurer l'état de la jambe en sortant du sommeil, il suffit d'écrire les valeurs des registres qui seront modifiés (MODER, PUPDR, OTYPER, OSPEEDR - voir la situation dans un cas particulier) à l'entrée, en variables, et de les reculer dans les registres en sortant du sommeil des variables .

Et maintenant ... ta daaam! Image de titre. Un et demi microampères.

Mais il est trop tôt pour célébrer. Sur ce point, nous avons terminé l'optimisation statique de la consommation d'énergie, et devant nous est dynamique .

Achilles vs Turtle


Quel est le meilleur - manger plus et courir plus vite ou manger moins, mais courir plus lentement? Dans le cas des microcontrôleurs, la réponse à cette question est deux fois non triviale.

Premièrement, les fréquences de fonctionnement peuvent être modifiées dans une très large plage - de 65 kHz (LP Run) à 32 MHz en mode normal. Comme toute puce CMOS, STM32 a deux composants en termes de consommation d'énergie: statique et dynamique; le second dépend de la fréquence, le premier est constant. En conséquence, la consommation d'énergie ne diminuera pas aussi rapidement que la fréquence de fonctionnement et la productivité, et selon la tâche, la fréquence optimale du point de vue de l'efficacité énergétique peut se révéler différente - où vous devez attendre un événement, mais pour une raison quelconque vous ne pouvez pas vous endormir, il y aura les basses fréquences sont efficaces, où vous avez juste besoin de battre des nombres - élevés. Dans les tâches "moyennes à l'hôpital" typiques, il n'est généralement pas logique de descendre en dessous de 2-4 MHz.

Deuxièmement, et c'est un moment moins trivial, le taux de sortie du sommeil dépend de la fréquence de travail et de la façon dont il est reçu.

Le pire des cas est de sortir du sommeil à une fréquence de 32 MHz à partir d'un quartz externe (laissez-moi vous rappeler que le STM32L1 se réveille sur un oscillateur interne à 4 MHz), car il se compose de trois étapes:

  • en fait, le processeur se réveille du sommeil
  • stabilisation de la génération de quartz (1-24 MHz)
  • Stabilisation de génération PLL (32 MHz)

En fait, sortir le processeur du sommeil est le plus petit problème, à une fréquence de 4,2 MHz, cela prend environ 10 μs. Mais la stabilisation du quartz peut prendre jusqu'à 1 ms (bien que généralement pour les résonateurs à grande vitesse, elle soit encore plus rapide, de l'ordre de plusieurs centaines de microsecondes), l'accès au mode PLL est encore de 160 μs.

Ces retards peuvent ne pas être importants du point de vue de la consommation d'énergie pour un système qui se réveille rarement (pas plus d'une fois par seconde), mais où la période entre les réveils est de quelques dizaines de millisecondes et moins, et les réveils eux-mêmes sont courts, les frais généraux commencent à faire un ajout déjà mesurable même sachant que lors du réveil le processeur consomme un courant relativement faible.

Que peut-on faire avec ça? En général, la réponse est évidente: essayez d'éviter d'utiliser du quartz externe. Par exemple, un programme dans lequel il existe de rares sous-tâches lourdes qui nécessitent une synchronisation précise (par exemple, des plus triviales - échange de données UART), et des sous-tâches simples fréquentes, peut décider par lui-même à chaque réveil s'il est nécessaire d'aller à quartz externe, ou il sera plus facile (et plus rapide!) d'effectuer la tâche en cours sur le générateur MSI, sur lequel le processeur s'est déjà réveillé sans passer beaucoup de temps à initialiser les fréquences.

Dans ce cas, cependant, il peut être nécessaire d'ajuster les fréquences d'horloge de la périphérie, ainsi que d'ajuster les modes d'accès à la mémoire flash (le nombre de cycles de retard), la tension du cœur du processeur (dans STM32L1, il est sélectionné parmi trois valeurs possibles), etc. Cependant, en ce qui concerne les modes de fonctionnement du noyau et de la mémoire, il est souvent possible de les affiner en choisissant ceux recommandés pour la fréquence maximale utilisée, car un fonctionnement non optimal du cœur à des fréquences plus basses n'entraînera pas de changement significatif dans les performances pratiques et la consommation d'énergie en raison du faible volume de tâches à ces fréquences effectué.

Bien que toutes ces mesures s'appliquent déjà au réglage fin des modes (et, par exemple, la plupart des systèmes d'exploitation et des bibliothèques ne savent même rien de proche de la boîte), dans certains cas, elles peuvent entraîner une diminution de la consommation moyenne à l'échelle des unités de pourcentage, et parfois même plus. Imaginez, par exemple, un compteur d'eau qui interroge les contacts d'un interrupteur à lames toutes les 50 ms, tandis que le levé réel prend plusieurs dizaines de microsecondes - voulez-vous ajouter ~ 500 μs à ce moment pour réveiller le contrôleur? ..

Insoutenablement longue seconde


Un autre problème qui n'est pas directement lié à la conservation de l'énergie, mais qui se pose inévitablement en rapport avec celui-ci - comment compter les intervalles de temps inférieurs à 1 seconde?

Le fait est que sur STM32L1 il n'y a qu'une seule minuterie qui fonctionne en mode Stop - c'est RTC, l'unité de temps standard pour laquelle est 1 seconde. Dans le même temps, dans les programmes, il y a constamment des intervalles de temps d'unités, de dizaines et de centaines de millisecondes, pour prendre au moins le même compteur d'eau.

Comment être Fonctionne sur des processeurs avec des temporisateurs LPTIM, cadencés à 32768 Hz? Une bonne option, en fait, mais pas toujours nécessaire. C'est possible sans cela.

Pas sur tous les STM32L1, mais à partir de Cat. 2 (il s'agit des processeurs STM32L151CB-A, STM32L151CC et plus récents), le bloc RTC a été complété par un nouveau registre - SSR, Registre des sous-secondes. Plus précisément, il n'était pas tant complété qu'il le rendait visible à l'utilisateur, plus les alarmes de sous-seconde ALRMASSR et ALRMBSSR ont été ajoutées.

Ce registre ne contient aucune unité de temps compréhensible, il a été fouetté à partir d'un compteur technique interne. Dans STM32L1, une horloge à 32768 Hz passe à travers deux compteurs diviseurs, asynchrones et synchrones, qui au total la divisent normalement par 32768 pour obtenir une tique de 1 seconde pour l'horloge. Ainsi, SSR est juste la valeur actuelle du deuxième compteur.

Bien que le SSR ne compte pas en millisecondes, mais dans ses unités, la dimension de ces unités peut être modifiée en modifiant le rapport des diviseurs du compteur synchrone et asynchrone, tout en conservant leur coefficient total égal à 32768 pour obtenir la norme 1 seconde à l'entrée RTC. Connaissant ces coefficients, nous pouvons calculer le prix d'une division de SSR en millisecondes, et à partir de là, nous pouvons procéder à la programmation d'alarmes de sous-seconde.

Il convient de noter qu'un pré-compteur asynchrone est plus économique qu'un SSR synchrone, et donc le mettre à 1, et déjà diviser la fréquence d'entrée en SSR par 32768, après avoir reçu un compte de seulement 30 μs, est énergétiquement désavantageux. Pour nous-mêmes, nous avons déterminé la valeur optimale pour le diviseur préliminaire 7, pour synchrone - 4095 ((7 + 1) * (4095 + 1) = 32768). Avec une nouvelle diminution du diviseur préliminaire, la consommation d'énergie du RTC commence à augmenter de façon mesurable - d'une fraction de microampère, mais puisque nous la comparons à la «référence» 1,4 μA en mode Stop, même les fractions comptent. Par défaut, pour STM32L1, ces valeurs sont 127 et 255, c'est-à-dire le prix de référence est d'environ 4 ms, ce qui est un peu approximatif.

Si vous souhaitez approfondir le code, nous avons finalisé en temps voulu le pilote RTC standard de RIOT OS pour prendre en charge RTC_SSR et les intervalles en millisecondes. Depuis lors, nous l'utilisons littéralement à chaque étape (et puisque nous travaillons dans le système d'exploitation, un service se bloque également au-dessus de lui, ce qui vous permet de suspendre presque n'importe quel nombre de tâches avec des périodes arbitraires sur une minuterie matérielle avec un coup de poignet).

La même approche est transférée aux contrôleurs STM32L0 et STM32L4, dont tous les modèles ont le registre RTC_SSR; cela élimine le besoin de temporisateurs LPTIM et unifie le code pour différentes plates-formes.

Comment comprendre qu'un multimètre est couché


Bien sûr, après toutes les optimisations, la question légitime se pose: qu'avons-nous réalisé en fait?Sans en connaître la réponse, on pourrait se limiter complètement à un WFE avec des drapeaux correctement configurés, s'endormir et obtenir vos 200-500 μA.

La façon la plus traditionnelle de mesurer le courant est, bien sûr, un multimètre. Comprendre qu'il est allongé sur une charge comme un microcontrôleur avec sa consommation dynamique est très simple - s'il est allumé, il est allongé.

Cela ne signifie cependant pas que le multimètre est inutile à cet égard. Il vous suffit de pouvoir l'appliquer.

Premièrement, un multimètre est une chose très lente, un temps typique pour un compte est une deuxième échelle, un temps typique pour changer l'état d'un microcontrôleur est une échelle de microsecondes. Dans un système qui modifie sa consommation à ce rythme, le multimètre affichera simplement des valeurs aléatoires.

Cependant, l'une des variables non aléatoires qui nous intéresse est la consommation du microcontrôleur en mode veille; s'il dépasse de manière significative la valeur que nous avons estimée sur les fiches techniques, alors quelque chose ne va clairement pas. Il s'agit de la consommation d'un système statique , c'est-à-dire qu'il peut être mesuré avec un multimètre.

La méthode la plus banale montrée dans la photo de titre est un multimètre en mode micro-ampèremètre, qui est maintenant dans la plupart des modèles de milieu de gamme, et a une bonne précision et une excellente résolution. L'UT120C a une résolution de 0,1 μA avec une précision certifiée de ± 1% ± 3 décharges, ce qui nous suffit.

Il n'y a qu'un seul problème avec ce mode - les multimètres qu'il contient ont une grande résistance en série, une échelle de centaines d'ohms, donc en mode normal, un microcontrôleur avec un tel multimètre dans le circuit de puissance ne démarre tout simplement pas. Heureusement, les positions de "mA" et "uA" dans presque tous les instruments de la balance sont proches, les prises de mesure sur les deux gammes sont les mêmes, vous pouvez donc démarrer en toute sécurité le contrôleur à la limite de "mA", et quand il se met en veille, cliquez sur "uA" "- cela se produit assez rapidement pour que le contrôleur n'ait pas le temps de perdre le courant et de redémarrer.

Veuillez noter que si le contrôleur connaît des pics d'activité, cette méthode n'est pas applicable. Par exemple, la minuterie du chien de garde est réinitialisée toutes les 15 secondes dans le micrologiciel de l'appareil - à ces moments, le multimètre parvient à afficher quelque chose dans la région de 27 μA, ce qui, bien sûr, n'a rien à voir avec la météo sur Mars. Si quelque chose de court arbitrairement se produit sur votre système plus d'une fois toutes les 5 à 10 secondes, le multimètre se trouvera simplement.

Une autre façon de mesurer l' électricité statique(Je souligne directement ce mot) la consommation par un multimètre est une mesure de la chute sur un shunt externe. Si vous souhaitez mesurer des courants ultra-petits à l'échelle de quelques dizaines de microampères, vous devez mettre un shunt de grande taille (par exemple, 1 kOhm) et parallèle à celui-ci - une diode Schottky en connexion directe. Si le shunt chute de plus de 0,3 V, la diode s'ouvrira et limitera la chute de tension, et jusqu'à 0,3 V, vous pouvez mesurer la chute en toute sécurité avec un multimètre de l'ordre du millivolt, 1 mV = 1 μA.

Hélas, il ne fonctionnera pas pour mesurer la chute sur un shunt à basse impédance avec un multimètre typique - des appareils de classe moyenne, même s'ils montrent quelque chose en dessous de 100 μV, la précision dans cette gamme est regrettable. Si vous avez un bon appareil de bureau pouvant afficher 1 uV, vous n'avez plus besoin de mes conseils.

Cependant, la statique est bonne, mais qu'en est-il de la dynamique? Comment évaluer le même effet de fréquences différentes sur la consommation électrique moyenne?

Ici, tout est compliqué.

Écrivons les exigences de base:

  • plage de courant d'au moins 1 μA - 100 mA (10 ^ 5)
  • période de mesure ne dépassant pas 10 μs
  • chute de tension non supérieure à 100 mV
  • durée de mesure - illimitée

Si nous traduisons simplement cela directement en chiffres, nous obtiendrons un ADC relativement rapide et pas moins de 18 bits avec une polarisation d'entrée inférieure à 30 μV, un frontal analogique capable de mesurer des tensions à partir de 1 μV et une interface rapide avec l'ordinateur qui nous permettra de transférer tout cela et économisez.

Et tout cela pour une seule utilisation.

Vous voyez, oui, pourquoi de telles choses ne se trouvent pas à chaque coin de dix dollars? Keysight N6705C dans la première approximation répond à nos exigences, seulement il en coûte 7960 $.

À partir de solutions budgétaires, par exemple, SiLabs intègre la mesure du courant dans ses débogages - les caractéristiques de leur système de surveillance énergétique avancée (AEM) dépendent du modèle de débogage spécifique, et ils ont le plus gros problème avec la vitesse de mesure. Dans les anciens «kits de démarrage», le STK3300 / 3400 n'est que de 100 Hz, sur les plus récents débogue le STK3700 / 3800 (facilement reconnaissable par le textolite noir) - 6,25 kHz, et dans les modèles plus anciens de la série DK débogue, il peut atteindre jusqu'à 10 kHz, mais cela coûte aussi ils sont déjà 300 $ +. Pour les tâches sérieuses, SiLabs recommande officiellement le Keysight susmentionné.

En principe, un tel appareil peut être conçu par vous-même - tout d'abord, vous avez besoin de très bons amplis opérationnels avec une polarisation d'entrée minimale, comme l'OPA2335. Ces amplificateurs opérationnels sont placés sur le même shunt de 2-3 pièces avec différents facteurs d'amplification, tous sont enroulés sur différentes entrées ADC (avec cette approche, il est tout à fait possible d'utiliser le microcontrôleur intégré), puis chaque acquisition de données détermine par programme lequel des amplificateurs opérationnels dans ce le moment n'est pas surchargé, les lectures de celui-ci sont comptées.

Le problème de la vitesse de transfert des données vers un ordinateur est résolu assez simplement - car pour des raisons pratiques, nous nous intéressons principalement à la consommation moyenne du système dans la vie réelle, des lectures en microsecondes peuvent être collectées dans le microcontrôleur embarqué du compteur et la moyenne arithmétique pour une échelle raisonnable en millisecondes peut être envoyée.

De plus, comme le montre la pratique, il est très utile d'avoir un compteur-enregistreur, bien que simple et pas trop précis, mais toujours à portée de main - afin de ne pas avoir de surprises avec une sorte de changement de firmware cassé par des économies d'énergie.

Par exemple, nous en avons intégré un dans notre adaptateur USB standard UMDK-RF, qui est constamment utilisé lors du débogage du micrologiciel - il dispose déjà d'un programmeur SWD avec prise en charge du protocole DAPLink, d'un pont USB-UART et d'une logique de gestion de l'alimentation, respectivement, il a obtenu un compteur de consommation presque gratuit. Le compteur lui-même est un shunt de 1 Ohm et un amplificateur INA213 (gain 50 fois, décalage zéro typique 5 μV): l'



amplificateur est connecté directement à l'entrée de l'ADC du microcontrôleur (STM32F042F6P6), l'ADC traite avec une période de 10 μs par une minuterie matérielle, et via USB les données moyennes sont sorties pour un intervalle de 100 ms. En conséquence, en changeant quelque chose dans la logique du firmware, vous pouvez simplement aller fumer ou boire un café, en laissant l'appareil sur la table et en revenant, regardez un calendrier comme celui-ci:



La précision d'un tel appareil "gratuit" n'est bien sûr pas élevée - avec un ADC 12 bits et un amplificateur, le quantum minimum est de 16 μA, mais il est extrêmement utile pour une évaluation rapide et régulière du comportement des appareils débogués du point de vue de la consommation d'énergie. En fin de compte, si vous faites quelque chose de mal dans le firmware ou l'appareil, avec une garantie très élevée, vous pourrez sortir des unités de microampères au moins des centaines, et cela sera clairement visible.



Un autre avantage intéressant est que, puisque les données sont envoyées au port COM virtuel sous forme de texte (valeurs en microampères), vous pouvez positionner la fenêtre du terminal à côté de la fenêtre affichant la console de l'appareil et regarder la consommation d'énergie simultanément avec les messages de débogage.

Je m'en vante pour une raison, mais pour offrir à tous ceux qui veulent utiliser ce programmeur de débogueur minimal (et très bon marché!) Dans leurs propres projets.

Vous pouvez dessiner le diagramme ici ( source dans DipTrace ), faire glisser le firmware ici (brunch umdk-rf, lorsque la construction de la cible est UMDK-RF, basée sur le projet dap42 ). Le diagramme est dessiné en désordre, mais j'espère que les points principaux sont clairs, le firmware est écrit en C en utilisant libopencm3 et est assemblé avec le bras-aucun-eabi-gcc habituel. En tant que fonctions supplémentaires, le micrologiciel dispose d'une gestion de l'alimentation, captant les signaux de surcharge des touches de commande et entrant le contrôleur qui lui est connecté dans son chargeur de démarrage natif en appuyant longuement sur un bouton.

NB: si vous voulez que le bouton de démarrage amène le propre contrôleur du programmeur dans son chargeur de démarrage de manière régulière, il doit avoir la polarité de la connexion modifiée, les octets d'option d'édition du contrôleur au premier démarrage et l'entrée du programme dans le chargeur de démarrage supprimé, et la polarité d'interruption pour le régulier fonctions de ce bouton.

Vous pouvez voir comment la mesure actuelle est effectuée sur une paire d'amplificateurs opérationnels avec différents facteurs de gain (par exemple, pour améliorer le débogueur décrit ci-dessus pour vos tâches), ici (p. 9), une alternative plus traditionnelle - avec un amplificateur opérationnel et un ADC 24 bits coûteux - TI l'a (EnergyTrace à la page 5).

PS Veuillez noter que lors du débogage avec un UART ou JTAG / SWD connecté, un petit courant peut également fuir à travers leurs jambes, ce qui ne se produira pas pendant le fonctionnement réel de l'appareil. Ainsi, sur UMDK-RF, environ 15 μA fuient dans le SWD (et donc, dans la photo d'en-tête, les mesures avec un multimètre sont effectuées sur l'ancienne version de la carte, sans SWD), et sur le STM32 Nucleo, il y avait des cas de flux parasite à travers le SWD d' environ 200 μA . Les cartes de débogage utilisées pour la mesure doivent être vérifiées pour ces fonctionnalités - soit en déconnectant leurs lignes d'interface, s'il y a une telle possibilité, soit en comparant les résultats avec la consommation de l'appareil mesurée sans l'installer pour le débogage, par exemple, avec un multimètre en mode statique.

Au lieu d'une conclusion


J'espère que vous avez déjà compris l'erreur que vous avez commise en choisissant la programmation des microcontrôleurs comme spécialité principale.

Source: https://habr.com/ru/post/fr430218/


All Articles