Bare-Metal STM32 : ajouter une touche analogique aux ADC

Un convertisseur analogique-numérique (ADC) est à la base un dispositif simple : en mesurant une tension analogique dans une plage définie et en convertissant le niveau mesuré en une valeur numérique, nous pouvons utiliser cette valeur de mesure dans notre code. Grâce à l’utilisation d’ADC intégrés dans les microcontrôleurs, nous pouvons traiter de nombreux cas d’utilisation essentiels, allant de la mesure du réglage sur un potentiomètre à la lecture d’une ligne de sortie analogique sur des capteurs, y compris les capteurs de température et de tension internes du MCU.

Les ADC trouvés dans les MCU STM32 ont une résolution comprise entre 12 et 16 bits, le premier étant le type le plus courant. Un ADC peut être configuré pour réduire cette résolution, définir une vitesse d’échantillonnage spécifique et configurer une configuration multimode en fonction du périphérique ADC exact. Les microcontrôleurs STM32 comportent au moins un seul périphérique ADC, tandis que certains en ont plusieurs. Dans cet article, nous verrons comment configurer et utiliser les fonctionnalités de base des ADC dans les MCU STM32, en particulier les ADC trouvés dans F0 et le type ADC5_V1_1 que l’on trouve dans la plupart des MCU de la famille F3.

Mettre les choses en place

Schéma fonctionnel du CAN STM32F0 (RM0091, 13.4).
Schéma fonctionnel du CAN STM32F0 (RM0091, 13.4).

Il y a trois éléments essentiels à prendre en compte lors de la configuration d’un périphérique ADC :

  1. Activation de son horloge dans son registre d’activation de réinitialisation et de contrôle d’horloge (RCC).
  2. Étalonnage du périphérique ADC.
  3. Choisir une source d’horloge commune ADC.

Le premier élément devrait être évident, car il s’agit de la procédure standard comme pour tout autre périphérique sur STM32. Même ainsi, il y a un peu de piège ici sur certains MCU STM32. Spécifiquement sur les MCU comme le F334, ses deux dispositifs ADC (ADC1 et ADC2) utilisent le même domaine d’horloge (ADC12 peu dans le RCC_AHBENR S’inscrire).

Avec le domaine d’horloge périphérique activé, nous pouvons passer à l’exécution de sa routine d’auto-étalonnage. Bien que cela soit facultatif, l’application des facteurs d’étalonnage fournis par l’usine améliore considérablement la précision des valeurs échantillonnées.

Étalonnage

L’exécution de la routine d’étalonnage applique un facteur d’étalonnage stocké pour ajuster le périphérique ADC. Ce facteur d’étalonnage est mesuré et programmé lors de la fabrication. L’exécution de la routine d’étalonnage nécessite que l’horloge du périphérique ADC soit activée (en RCC), mais qu’elle soit désactivée (ADEN bit). Sur F0 et les MCU compatibles, l’étalonnage est alors lancé en écrivant dans le ADCAL peu dans le ADC_CR enregistrez-vous et attendez que l’étalonnage soit terminé en vérifiant le ADCAL valeur binaire :

ADC1->CR |= ADC_CR_ADCAL;
while ((ADC1->CR & ADC_CR_ADCAL) != 0) { }

Sur les appareils F3, la procédure est très similaire, mais nécessite également que nous activions d’abord le régulateur de tension de l’ADC sur l’appareil. Par exemple:

ADC1->CR &= ~ADC_CR_ADVREGEN;
ADC1->CR |= ADC_CR_ADVREGEN_0; 

Le piège avec le ADVREGEN La valeur de registre est qu’elle doit toujours passer par 0x00 lors de sa modification, c’est pourquoi nous devons d’abord la désactiver. Après avoir activé le régulateur de tension, nous devons attendre 10 microsecondes pour donner à la sortie du régulateur le temps de se stabiliser. Avec cela géré, nous pouvons effectuer la procédure ADCAL comme décrit précédemment pour le F0.

Source d’horloge

Schéma d'horloge ADC STM32F334.  (RM0364, 13.3.3)
Schéma d’horloge ADC STM32F334. (RM0364, 13.3.3)

La source d’horloge ADC est essentiellement le choix entre une source synchrone (dérivée de l’AHB ou de l’APB) ou asynchrone (indépendante des resynchronisations du domaine d’horloge). Généralement, choisir la source asynchrone est une option sûre, par exemple pour STM32F0 en définissant la valeur pour CKMODE dans ADC_CFGR2 et activation de l’horloge ADC haute vitesse (ici l’horloge HSI 14 MHz):

ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE;
RCC->CR2 |= RCC_CR2_HSI14ON;
while ((RCC->CR2 & RCC_CR2_HSI14RDY) == 0) { }

Il est important ici d’attendre que la source d’horloge se stabilise avant de continuer. Avec l’horloge HSI14 sur F0, cela se fait en attendant le HSI14RDY peu à régler RCC_CR2.

L’utilisation d’un mode d’horloge synchrone dérivé du bus est également une option, par exemple l’horloge AHB sans diviseur sur les microcontrôleurs F334 :

ADC1_2_COMMON_BASE->CCR |= ADC_CCR_CKMODE_1;

Le mode d’horloge étant sélectionné et les tâches précédentes également rayées de la liste, nous pouvons procéder à la configuration des canaux que nous souhaitons échantillonner au cours d’une séquence.

Configuration du canal

Connectivité des canaux ADC1 et ADC2 du STM32F334.  (RM0364, 13.3.4)
Connectivité des canaux ADC1 et ADC2 du STM32F334. (RM0364, 13.3.4)

Chaque ADC est connecté à un certain nombre de canaux d’entrée analogiques, avec une gamme de canaux externes fixes (connectés GPIO) et un nombre supplémentaire de canaux dits internes. Ces derniers canaux sont reliés au capteur de température interne (Vsense), référence de tension interne (Vrefint), Voltage de batterie (vbat), et sur les MCU F334, il y a Vopamp2 sur la voie 17 de son deuxième périphérique ADC pour un amplificateur opérationnel embarqué.

La façon dont un canal est configuré est celle où les ADC des familles F0 et F3 commencent à diverger de manière significative. Si nous regardons F0, la configuration des canaux de l’ADC1 est effectuée en définissant le canal comme actif dans ADC_CHSELR, suivi du réglage du temps d’échantillonnage. Si nous configurons les canaux 1 (GPIO) et 16 (Vsense), par exemple, nous obtenons :

ADC_BASE->CCR |= ADC_CCR_TSEN;
ADC1->CHSELR |= (1 << 1); 
ADC1->CHSELR |= (1 << 16); 
ADC1->SMPR = 7;

Cela définit les canaux 1 et 16 comme actifs dans le registre de sélection de canal et définit le temps d’échantillonnage sur la longueur maximale (0b111). Pour le canal 16 (Vsense), il s’agit de la longueur d’échantillonnage recommandée pour l’échantillonnage de Vsense (239,5 cycles ADC). Comme le temps d’échantillonnage sur les ADC F0 est le même pour tous les canaux, nous devons choisir ici le temps d’échantillonnage requis le plus long.

Notez que nous devons également activer le TSEN peu dans le commun ADC_CCR enregistrer afin d’activer ce canal. Il en est de même pour les autres canaux internes, en utilisant le VREFINT et VBAT bits dans le même registre. Enfin, notez que nous devons activer le mode analogique sur la broche GPIO que nous souhaitons utiliser pour l’entrée analogique.

Ensuite, regardons à quoi ressemble la configuration des mêmes canaux sur un appareil F334 :

ADC1_2_COMMON_BASE->CCR |= ADC_CCR_TSEN;
ADC1->SQR1 = 1;
ADC1->SQR1 |= (1 << 6);
ADC1->SQR2 |= (16 << (6 * 2));
ADC1->SMPR2 |= (7 << (3 * 6));

Ici aussi, nous devons activer le TSEN bit, mais la façon dont une séquence d’échantillonnage est configurée est plus compliquée. Fondamentalement le SQR1 à travers SQR4 Les registres contiennent les numéros de canaux successifs à échantillonner dans la séquence, avec la première entrée dans ADC_SQR1 contenant le nombre de canaux dans toute la séquence (0 signifiant un canal).

Avec les canaux configurés comme tels en utilisant sinon les paramètres par défaut, nous sommes prêts à démarrer la séquence.

Exécution d’une séquence

Avant de commencer une séquence, nous souhaitons nous assurer que ADRDY dans le ADC_ISR register est 0. Cela nous permet de savoir que nous pouvons démarrer une nouvelle séquence en toute sécurité. Ensuite, nous activons l’appareil en définissant ADEN dans le ADC_CR enregistrer pour le périphérique ADC cible. L’appareil est maintenant prêt pour le démarrage du séquençage.

Lorsque nous écrivons au ADSTART peu de ADC_CR , il fait commencer l’échantillonnage par l’ADC, qui par défaut est une séquence unique, ce qui signifie qu’il échantillonnera chaque canal actif une fois, avant de s’arrêter. Lorsqu’un canal a été échantillonné, nous pouvons le détecter en attendant le bit EOC (End Of Conversion) dans le ADC_CR registre à régler. Une fois que ce bit devient un ‘1’, nous pouvons lire la valeur échantillonnée à partir du ADC_DR registre, ce qui réinitialisera le bit EOC. Une fois la séquence complète terminée, EOSEQ dans ADC_ISR sera défini.

Gestion des valeurs échantillonnées

La valeur échantillonnée sera un nombre compris entre 0 et quelle que soit la tension d’entrée analogique du MCU. Il s’agit généralement de 3,3 VDC, ce qui signifie que nous obtenons une valeur comprise entre environ 0 et 3 300, lorsque nous mesurons des millivolts. Cela facilite la détection de l’état d’un potentiomètre externe, par exemple, car il affectera cette valeur de manière linéaire. Pour quelque chose comme le capteur de température interne, nous devons effectuer quelques calculs pour obtenir un nombre significatif.

Lorsque vous recherchez dans la fiche technique du MCU spécifique, l’adresse mémoire pour deux valeurs d’étalonnage est fournie pour le capteur de température. Pour le MCU F042, ce sont 0x1FFFF7B8 pour 30°C et 0x1FFFF7C2 pour 110°C. Nous prenons la valeur 12 bits que nous avons obtenue pour Vsense comme température brute (dans un int16_t variable) et branchez-la dans la formule donnée dans le manuel de référence :

int32_t temperature = 0;
temperature = (((int16_t) raw) - *TEMP30_CAL_ADDR);
temperature = temperature * (int32_t)(110 - 30);
temperature = temperature / (int32_t)(*TEMP110_CAL_ADDR - *TEMP30_CAL_ADDR);
temperature = temperature + 30;

Pour le MCU référencé STM32F042, cela donne une température d’environ 36°C peu après l’écriture de l’image du firmware sur l’appareil, avec une température ambiante d’environ 28°C. Bien que la précision du capteur de température interne des appareils STM32 ne soit pas garantie, en utilisant les valeurs d’étalonnage fournies, il doit être précis à quelques degrés près, ce qui est suffisant pour mesurer la santé de l’appareil.

Que le début

Ce qui précède ne donne qu’une brève introduction aux périphériques ADC tels qu’ils existent dans les microcontrôleurs STM32, bien sûr. Nous n’avons utilisé qu’un seul ADC et avons laissé la résolution d’échantillonnage, l’alignement des données, etc. à leurs valeurs par défaut. Nous examinerons ces options plus en détail dans un prochain article, ainsi que l’utilisation des interruptions, le mode continu et le fonctionnement multimode des microcontrôleurs F3 multi-ADC.

Quoi qu’il en soit, il devrait être possible d’effectuer de nombreuses tâches essentielles liées à l’ADC avec les informations fournies jusqu’à présent et de comprendre certains des principes fondamentaux de leur fonctionnement.