vendredi 5 juillet 2013

msp430 launchpad, partie 2

Ces derniers jours j'ai continuer mon exploration du msp430 launchad en m'intéressant plus particulièrement au convertisseur analogue/numérique 10 bits (ADC10) qu'on retrouve sur le MSP430G2553. Associé à ce convertisseur il y a un canal DMA (Direct Memory Access) qui permet de transférer automatiquement sans intervention logicielle une séquence de conversions A/N dans la mémoire RAM. On peut par exemple programmer le périphérique ADC10 pour qu'il effectue une série de conversions sur le même canal ou sur une séquence de canaux. Le DMA permet même de transférer 2 blocs consécutifs. Le MCU peut donc traiter le contenu de l'un pendant que l'autre se rempli. J'ai écris 2 programmes de démonstration. Le premier montre la façon la plus simple d'utiliser l'ADC10 et le second utilise le DTC, LPM et une interruption. On va voir aussi comment configurer le DCO (Digitally Controlled Oscillator) pour modifier la fréquence du Master Clock (MCLK) ainsi que configurer l'Auxiliary Clock (ACLK) pour l'alimenter par l'oscillateur interne basse fréquence (VLO).

Le Basic Clock Module en bref

Commençons d'abord par présenter le BCS (Basic Clock System). Les msp430 ont 3 signaux d'horloges internes, MCLK (Main Clock), SMCLK (Sub-Main Clock) et ACLK (Auxiliary Clock). Le signal MCLK est utilisé pour cadencer le core du MCU et peut aussi être sélectionné pour alimenter un périphérique. Les signaux SMCLK et ACLK servent seulement pour les périphériques. Ces 3 signaux sont alimentés par divers oscillateurs internes ou externe. Il y a 2 à 4 oscillateurs internes le DCOCLK (Digitally Controlled Oscillator), présent sur tous les MSP430, génère un signal haute fréquence jusqu'à 16Mhz. Le LFXT1CLK utilise un Crystal externe à 32768Khz, il est absent sur les MCU à 8 broches. Le XT2LCK, présent sur les MCU avec plus de 20 broches, utilise un Crystal externe haute fréquence (400Khz à 16Mhz). Le VLOCLK (Very Low power Oscillateur), présent sur tous les MSP430 génère un signal à 12Khz. Normalement LFXT1CLK et utilisé avec un Crystal 32768Khz (horloge temps réel) et XT2CLK pour un oscillateur haute fréquence en remplacement du DCOCLK. Le MSP430G2553 n'a pas de XT2CLK donc soit on utilise un oscillateur externe (400Khz à 16Mhz) dont la sortie est branchée sur XIN (broche 19 sur les DIP20) ou le DCO si on veut fonctionner en haute fréquence.

La table suivante montre comment configurer le BCS (Basic Clock System) pour sélectionner un oscillateur pour chacun des 3 signaux d'horloge.

configuration des signaux horloge
signal/
source
MCLCKSMCLKACLK
VLOCLKBCSCTL2 |= SELM_3;
BCSCTL3 |= LFXT1S1;
BCSCLT3 &= ~LFXT1S0;
BCSCTL2 |= SELS;
BCSCTL3 |= LFXT1S1;
BCSCLT3 &= ~LFXT1S0;
BCSCTL3 |= LFXT1S1;
BCSCLT3 &= ~LFXT1S0;
LFXT1CLKBCSCTL2 |= SELM_3;
BCSCTL3= ~(LFXT1S0+LFXT1S1);
BCSCTL2 |= SELS;
BCSCTL3= ~(LFXT1S0+LFXT1S1);
BCSCTL3= ~(LFXT1S0+LFXT1S1);2
DCOCLCKBCSCTL2 &= ~SELM_3;2BCSCTL2 &= ~SELS;2N/A
XT2CLK1BCSCTL2 |= SELM_2;BCSCTL2 |= SELS;
N/A
osc. externeBCSCTL2 |= SELM_3;
BCSCTL3 |= LFXT1S0+LFXT1S1;
BCSCTL2 |= SELS;
BCSCTL3 |= LFXT1S0+LFXT1S1;
N/A
1 Certains MCU seulement.
2 état par défaut après une mise sous tension ou une réinitialisation (RESET).

La fréquence de la source qui alimente chacun des MCLK, SMCLK et ACLCK peut-être divisée par 1,2,4 ou 8.

configuration des diviseur de fréquence.
signal/
diviseur
MCLCKSMCLKACLK
1 BCSCTL2 &= ~DIVM_3; BCSCTL2 &= ~DIVS_3; BCSCTL1 &=~DIVA_3;
2 BCSCTL2 &= ~DIVM_3;
BCSCTL2 |= DIVM_1;
BCSCTL2 &= ~DIVS_3;
BCSCTL2 |=DIVS_1;
BCSCTL1 &=~DIVA_3;
BCSCTL1 |= DIVA_1;
4 BCSCTL2 &= ~DIVM_3;
BCSCTL2 |= DIVM_2;
BCSCTL2 &= ~DIVS_3;
BCSCTL2 |=DIVS_2;
BCSCTL1 &=~DIVA_3;
BCSCTL1 |= DIVA_2;
8 BCSCTL2 |= DIVM_3; BCSCTL2 |= DIVS_3; BCSCTL1 |= DIVA_3;

Au démarrage c'est le DCO qui alimente MCLK et SMCLK à une fréquence de ~1Mhz. On peut diviser cette fréquence en utilisant les diviseurs mentionnés dans la table ci-haut mais si on veut au contraire augmenter la fréquence il faut modifier la configuration du DCO. Ça se fait en programmant les SFR DCOCTL et BCSCTL1. Le plus simple est d'utiliser les constantes prédéfinies dans le fichier d'entête du MCU (msp430.h). Il y a une constante pour chacun des registres DCOCTL et BCSCTL1 et pour les fréquences suivantes: 1, 8, 12, 16 Mhz. Voir la fonction configure_clock() dans le programme démo qui suis.

Ceci n'est qu'un résumé, pour plus de détails il faut consulter le document le Family user's guide correspondant au MCU choisi. Pour le MSP430G2553 les documents pdf (en anglais) sont ici.

Voltmètre à affichage binaire

Comme le convertisseur a une résolution de 10 bits j'ai simplement utiliser 10 LEDs pour afficher le résultat de la lecture faite sur le potentiomètre RV1.

Je présente 2 versions de ce démo, la première est illustre la méthode la plus simple d'utiliser le convertisseur analogue/numérique et la deuxième utilise le gestionnaire basse consommation (LPM), une interruption et le transfert d'une séquence de lectures vers la mémoire RAM en utilisant le DTC (Data Transfert Control).

première version

Presque toutes les lignes du code source sont commentées. Les étapes sont les suivantes:

  1. Désactivation du WDT
  2. Configuration de la fréquence du DCO à 16Mhz par la fonction configure_clock()
  3. configuration en sortie des bits P1.4 à P1.7 et P2.0 à P2.5
  4. configuration et activation du convertisseur analogue/numérique (ADC10)
  5. On entre dans la boucle infinie while (1)
    1. appel de la fonction read_adc()
    2. extraction des bits de poids fort 6 à 9 de la variable voltage vers la variable P1
    3. extraction des bits de poids faible 0-5 de la variable voltage vers la variable P2
    4. affichage 4 bits forts, envoie de P1 vers P1.4-P1.7
    5. affichage 6 bits faibles, envoie de P2 vers P2.0-P2.5
    6. délais 1/3 de seconde avant de boucler
Dans la fonction read_adc() on utilise l'indicateur ADC10IFG pour savoir si la conversion est terminée. En effet même si les interruptions ne sont pas activées l'indicateur est mis à 1 à la fin de chaque conversion. Donc avant de démarrer la conversion on le met à zéro, on démarre la conversion et on attend que ADCIFG revienne à 1.

voltmètre version 2

Si vous faites le montage et exécutez la version 1 du programme vous allez constater qu'il y a beaucoup de fluctuation sur les 4 bits faible d'une lecture à l'autre. Ceci est du au fait que les voltages de référence utilisé par le convertisseur sont Vdd/Vss. Hors il y a beaucoup de bruit sur l'alimentation causé par le fonctionnement du MCU lui-même. Le MCU possède 2 références de voltage interne. L'Utilisation d'une référence interne (1,5Volt, 2,5Volt) réduirait grandement ce bruit de fond. Il y a une autre façon de réduire ce bruit de fond et c'est celle que j'ai utilisé dans cette version du démo. Le programme fait 8 lectures consécutives et retourne la moyenne. De plus le MCU est arrêté pendant la lecture. Comme c'est le fonctionnement du core qui est en grande partie responsable des fluctuations sur Vdd le fait de l'arrêter pendant la lecture va forcément réduire le bruit de fond.

Attardons-nous pour commencer aux 4 lignes suivantes:
Cette version utilise le transfert de bloc vers la RAM donc il faut activer un mode de conversion en séquence. CONSEQ_2 indique une séquence de lectures sur le même canal, INCH_3 dans ce cas ci. Le bit MSC dans ADC10CTL0 active la multi-conversion automatique. Le bit ADC10TB indique si le DTC va transférer 1 ou 2 bloc de lectures. Dans ce cas ci on met le bit à zéro ce qui signifie 1 bloc. On va utiliser l'interruption sur fin de transfert de bloc donc on active l'indicateur d'interruption global en appelant la fonction _enable_interrupts() et en mettant le bit ADC10IE à 1 dans ADC10CTL0.

Les msp430 supportent les interruptions multi-vecteurs. Pour définir une routine d'interruption on commence par indiquer au compilateur quel est le vecteur associé à l'ISR qui suis. C'est fait avec une directive #pragma vector. La directive est suivit par une fonction de la forme __interrupt void nom_isr(void). Notre ISR est très courte, on commence par remettre à zéro l'indicateur ADC10IFG et ensuite la macro LPM3_EXIT indique qu'à la sortie de l'ISR le MCU doit-être remis en mode actif. Normalement si le MCU est dans un mode LPMx lorsqu'une interruption est déclenchée il retourne dans le même mode LPMx à la sortie de l'ISR qui répond à l'interruption. Si on veut que le MCU demeure actif après la sortie de l'ISR comme dans ce cas si on doit l'indiquer par la macro LPMx_EXIT correspondant au mode LPMx initial. Dans notre cas la fonction read_adc()mais le MCU en LPM3 juste après le déclenchement de la série de lectures, donc l'ISR doit utilisez LPM3_EXIT pour réactiver le MCU.

Comme on peut le voir la fonction read_adc() est plus complexe que celle de la version 1. le SFR ADC10DTC1 indique le nombre de lecture consécutives qui seront effectuées. Huit dans ce cas ci. Les 2 lignes suivantes ne servent qu'à s'assurer que le convertisseur n'est pas déjà occupé. La boucle while (ADC10CTL1 & BUSY); attends simplement la libération du périphérique. Au début de la fonction on a déclaré une variable tableau volatile static unsigned int voltages[8]. C'est dans ce tableau que seront transférés les 8 lectures. Le DCT doit savoir où transférer les lectures, on lui indique en mettant l'adresse du tableau dans le SFR ADC10SA. Au moment où cette adresse est écrite dans ce registre la procédure DCT est enclenchée mais pas la série de conversions qui elle est déclenchée en mettant à 1 les bits ENC (enable conversion) et ADC10SC (start conversion) dans ADC10CTL0;

Maintenant on met le MCU en mode LPM3. Dans ce mode le MCU, MCLK, SMCLK, DCO et le générateur DCO sont inactif ce qui a pour effet de réduire la consommation du MCU à presque rien, moins de 1µA1 pour un Vdd de 3volt. L'ADC10 fonctionne quand même car il utilise son propre oscillateur interne. Notez qu'on peut configurer l'ADC10 pour qu'il utilise MCLK ou SMCLK au lieu de son oscillateur interne mais dans ce cas on ne pourrait pas passé en mode LPM3. C'est l'ISR qui va sortir le MCU du coma par l'exécution de LPM3_EXIT et ce n'est qu'à ce moment que les instructions qui suivent LPM3 dans la fonction read_adc() seront exécutées.

Conclusion

Le convertisseur ADC10 avec le DTC forme un système très sophistiqué dont on a fait qu'effleuré la surface. Il en va de même pour le BCS. Le user's guide pour cette famille de MCU fait plus de 600 pages. On comprendra que je ne reproduirai pas toute cette documentation ici. Comme les fabricants de circuits intégrés traduisent rarement leur documentation en français, il est quasiment essentiel de savoir lire l'anglais. Encore heureux que ce ne soit pas seulement disponible ne chinois.


NOTES:
1) Dans ce démo la consommation de courant viens majoritairement des LED donc le fait de mettre le MCU en mode LPM3 ne réduit pas la consommation significativement mais réduit le bruit sur Vdd. Avec la version 2 du programme, lorsque je mets l'entrée P1.3 à zéro volt la lecture oscille entre 1 et 2 alors qu'avec la version 1 ça oscille entre 1 et 4.

Aucun commentaire:

Publier un commentaire