Nous avons appris dans les trois premiers articles à utiliser les timers de nos microcontrôleurs ATmega328P équipant les modules Arduino Uno, Nano et Mini. Nous avons décrit deux modes de fonctionnement des timers, le mode normal, voir l’article Les Timers (I), et le mode CTC, voir l’article Les Timers (III). Nous allons découvrir dans cet article deux autres modes de fonctionnement qui servent, entre autre, à fabriquer la PWM. Une introduction à ce qu’est la PWM se trouve dans l’article La PWM : Qu’est-ce que c’est ? (1). Bien entendu, la lecture du présent article suppose d’avoir lu et compris les trois premiers articles sur les Timers, Les Timers (I), Les Timers (II) et Les Timers (III).
Les Timers
Les Timers (IV)
La génération des PWM
.
Par :
DIFFICULTÉ :★★★
PWM et broches de sortie
Le module Arduino Uno est capable de générer de la PWM sur 6 broches de sorties grâce à la fonction analogWrite
. D’une manière transparente pour l’utilisateur, cette fonction utilise les timers du microcontrôleur pour générer sur les sorties, un signal carré de fréquence fixe mais de largeur variable pour l’impulsion à l’état haut. Le tableau suivant indique quel timer est utilisé pour générer la PWM et sur quelles sorties du module Uno elle est générée.
Timer | Sorties du module Uno |
---|---|
timer0 | 5 et 6 |
timer1 | 9 et 10 |
timer2 | 3 et 11 |
Un timer gère donc deux broches de sortie ; la figure 1 (extraite de la datasheet de l’ATmega328P) permet de comprendre l’architecture d’un bloc timer. Sur cette figure, la lettre « n » est utilisée pour désigner le numéro du timer (n = 0, 1, 2).
Le signal d’horloge clkTn (en jaune) arrive à la logique de contrôle, en provenance de l’extérieur (Tn) ou bien de l’horloge interne et du prescaler. La logique de contrôle incrémente ou décrémente le timer TCNTn (en vert) et celui-ci est comparé aux valeurs des registres OCRnA et OCRnB (en bleu). Lorsqu’il y a égalité, un signal est envoyé à un bloc appelé « Waveform Generation » (Génération de la forme d’onde) (en rouge) et c’est ce bloc qui met en forme la PWM en positionnant à 0 ou à 1 le registre des broches OCnA ou OCnB (en violet). Bien entendu, ces broches doivent avoir été déclarées comme des sorties auparavant.
Le timer0 génère donc de la PWM sur les broches OC0A et OC0B. La figure 2 (extraite de la datasheet de l’ATmega328P) montre que ces broches (en rouge) sont les broches 12 et 11 du microcontrôleur (PD6 et PD5).
Le schéma de câblage du module Arduino Uno Rev 3, donné sur le site d’Arduino, permet de voir que la broche PD5 est reliée à la sortie 5 du module alors que la broche PD6 est reliée à la sortie 6 :
http://arduino.cc/en/uploads/Main/A...
De la même façon, on peut voir sur la figure 2 que le timer1 génère la PWM sur les broches en bleu (broches 15 et 16 du microcontrôleur) et que le timer2 le fait sur les broches en vert (broches 5 et 17 du microcontrôleur). Les broches 15 et 16 sont reliées aux sorties 9 et 10 du module Uno et les broches 5 et 17 le sont aux sorties 3 et 11.
Génération de la PWM
Maintenant que nous savons où récupérer nos signaux PWM, voyons comment ils sont générés. Deux modes de fonctionnement de nos timers peuvent être utilisés pour générer de la PWM :
- Le mode « Fast PWM Mode »
- Le mode « Phase Correct PWM Mode »
Comme son nom l’indique (fast signifiant rapide), le Fast PWM Mode permet d’obtenir une PWM ayant une fréquence plus élevée que le Phase Correct PWM Mode (pratiquement un facteur deux comme nous le verrons), mais en contrepartie, une résolution du signal moins bonne. En effet, le mode Fast est basé sur une opération à simple pente, ce qui signifie que le timer/counter ne fait que s’incrémenter pour aller chercher la valeur de comparaison OCRnx (« x » signifiant A ou B). Rappelez-vous que nous avons dit que lorsqu’il y a égalité, un signal est envoyé au bloc Waveform Generation qui va alors générer le signal PWM désiré. Le mode Phase Correct est basé sur une opération à double pente, ce qui signifie que le timer/counter s’incrémente de la valeur BOTTOM à la valeur TOP puis se décrémente de TOP à BOTTOM. Ces deux opérations prennent plus de temps, ce qui donne une période plus longue donc une fréquence moins élevée.
Pour bien comprendre la différence entre ces deux modes, il est nécessaire de rentrer dans le détail des deux modes de fonctionnement de nos timers. À partir de maintenant, nous raisonnerons avec le timer2, mais il est tout aussi possible d’utiliser d’autres timers.
Fast PWM Mode
On est dans ce mode si les 3 bits WGM2 de 0 à 2 sont égaux à la valeur 3 ou 7 (on écrit alors WGM22:0 = 3 ou 7, et on rappelle ce qui a été dit dans l’article Les Timers (I), WGM signifie Waveform Generation Mode). Ce mode est un mode à simple pente, ce qui signifie que le timer/counter ne fait que s’incrémenter entre la valeur BOTTOM jusqu’à la valeur TOP, puis redémarre depuis BOTTOM, etc.
BOTTOM est égal à 00 et TOP est égal à FF (ou 255) si WGM22:0 = 3 ou OCR2A si WGM22:0 = 7.
L’unité de comparaison génère alors la forme d’onde du signal PWM sur la broche OC2x. Ce signal PWM peut être inversé, comme nous le verrons plus loin. Pour que le signal PWM soit non inversé, il faut que les 2 bits COM2x1:0 soient égaux à la valeur 2 (COMnx signifie Compare Match Output « x » Mode du timer « n »). Dans ce cas, la forme d’onde du signal PWM est générée automatiquement en mettant à 0 le registre OC2x lorsque le timer/counter TCNT2 atteint la valeur OCR2x, et en le positionnant à 1 le registre OC2x lorsque le timer/counter TCNT2 passe de la valeur TOP à BOTTOM. C’est ce que montre la figure 3 ; la petite marque horizontale sur la pente du timer représente le moment où le timer/counter TCNT2 est égal à la valeur du registre OCR2x. Dans la figure, le rapport cyclique de la PWM est changé plusieurs fois par la mise à jour du registre OCR2x.
Si TOP vaut 255, le timer/counter TCNT2 compte de 0 à 255 puis au coup suivant qui devrait être 256, il se remet à 0 (overflow) ; une période représente 256 opérations de comptage. Ces opérations de comptage se font à la fréquence de l’horloge divisée par la valeur N du prescaler. La fréquence du signal PWM obtenu est donc :
$$ f = \frac{F_{clk}}{N\times 256} $$
Phase Correct PWM Mode
On est dans ce mode si les 3 bits WGM22:0 = 1 ou 5 ; ce mode produit une forme d’onde de PWM à haute résolution, basée sur un mode opératoire à double pente. Le timer/counter TCNT2 compte de façon répétitive depuis BOTTOM jusqu’à TOP puis redescend à BOTTOM. Encore une fois, BOTTOM est égal à 00 et TOP est égal à FF (ou 255) si WGM22:0 = 1 ou OCR2A si WGM22:0 = 5.
Le timer/counter est donc incrémenté depuis BOTTOM jusqu’à ce qu’il atteigne la valeur TOP, puis la direction de comptage est inversée et le timer/counter est décrémenté de TOP jusqu’à BOTTOM. La valeur de TCNT2 est donc égale à TOP pendant un cycle d’horloge.
L’unité de comparaison génère alors la forme d’onde du signal PWM sur la broche OC2x. Ce signal PWM peut également être inversé, comme nous le verrons plus loin. Pour que le signal PWM soit non inversé, il faut que les 2 bits COM2x1:0 soient égaux à la valeur 2. Dans ce cas, la forme d’onde du signal PWM est donc générée en mettant à 0 le registre OC2x lorsque le timer/counter TCNT2 atteint la valeur OCR2x quand il s’incrémente, et en le positionnant à 1 le registre OC2x lorsque le timer/counter TCNT2 atteint la valeur de OCR2x quand il se décrémente. C’est ce que montre la figure 4 ; la petite marque horizontale sur les pentes du timer représente le moment où le timer/counter TCNT2 est égal à la valeur du registre OCR2x. Dans la figure, le rapport cyclique de la PWM est changé plusieurs fois par la mise à jour du registre OCR2x.
Si TOP vaut 255, le timer/counter TCNT2 compte de 0 à 255 puis décompte jusqu’à 0 ; la période pour faire cela vaut donc 510 cycles d’horloge (2 fois 255). Si Fclk est la fréquence d’horloge et N le facteur de division du prescaler, la fréquence du signal PWM obtenu est donc :
$$ f = \frac{F_{clk}}{N\times 510} $$
Cette fréquence est donc à peu près deux fois moins élevée que dans le mode Fast.
Inversion du signal PWM
Que l’on travaille en mode « Fast » ou en mode « Phase Correct », on peut inverser le signal PWM sur la broche OC2x en faisant en sorte que les 2 bits COM2x1:0 soient égaux à la valeur 3, ou, ce qui revient au même, que les deux bits soient positionnés à 1. Dans le cas du mode « Fast », la forme d’onde du signal PWM est générée automatiquement en positionnant à 1 le registre OC2x lorsque le timer/counter TCNT2 atteint la valeur OCR2x, et en mettant à 0 le registre OC2x lorsque le timer/counter TCNT2 passe de la valeur TOP à BOTTOM, comme le montre la figure 3. Dans le cas du mode « Phase Correct », la forme d’onde du signal PWM est générée automatiquement en positionnant à 1 le registre OC2x lorsque le timer/counter TCNT2 atteint la valeur OCR2x quand il s’incrémente, et en mettant à 0 le registre OC2x lorsque le timer/counter TCNT2 atteint la valeur de OCR2x quand il se décrémente, comme le montre également la figure 4.
Valeurs extrêmes du registre OCR2A
Dans les deux modes, les valeurs extrêmes du registre OCR2A représentent des cas particuliers pour générer le signal PWM. Dans le mode Fast, si OCR2A est égal à BOTTOM, le signal de sortie sera un pic étroit pour chaque cycle d’horloge MAX + 1 du timer et si OCR2A est égal à MAX, la sortie sera constamment à l’état haut ou bas selon le mode de sortie PWM (inversé ou non inversé) réglé par les 2 bits COM2A1:0 . Dans le mode Phase Correct, si OCR2A est égal à BOTTOM, la sortie sera constamment à l’état bas et si OCR2A est égal à MAX, la sortie sera constamment à l’état haut, ceci pour un mode PWM non inversé ; pour un mode PWM inversé, la sortie aura les valeurs logiques opposées. On rappelle que MAX vaut FF (ou 255).
Deux exemples
Nous allons voir comment fabriquer un signal PWM de rapport 50% dans chacun des deux modes, avec le timer2. Peu importe la fréquence, il suffit de régler le prescaler en fonction de ce qu’on veut comme cela a été décrit dans les articles précédents (bits CS22:0 à régler).
Dans le cas du Fast PWM Mode, on veut que notre timer/counter compte de 0 à 255 ; les 3 bits (des registres de contrôle TCCR2A et TCCR2B) WGM22:0 doivent former la valeur 3 (soit 011 en binaire, ce qui règle TOP = 255). On veut récupérer un signal PWM non inversé sur la broche OC2B (la broche 5 du microcontrôleur ATmega328P ou encore la sortie 3 du module Arduino Uno). Les 2 bits (du registre de contrôle TCCR2A) COM2B1:0 doivent former la valeur 2 (soit 10 en binaire) pour que le signal soit non inversé. Pour un rapport de 50%, on charge le registre OCR2B avec la valeur 128.
La figure 5 montre comment le timer2 évolue ; le registre OC2B est mis à 0 quand le timer2 est égal à OCR2B et mis à 1 quand le timer2 est remis à 0.
Le programme suivant est celui de ce premier exemple avec N = 1 : d’après la formule donnée plus haut, la fréquence est de 62,500 kHz.
/* ----------------------------------------------
Exemple 1 de l'article Timers IV
N = 1 pour le prescaler
La PWM de frequence 62500 Hz
est sur la sortie 3 du module UNO
-------------------------------------------------
*/
void setup(){
pinMode (3, OUTPUT);
TCCR2A = 0b00100011;
TCCR2B = 0b00000001;
OCR2B = 128;
}
void loop(){
}
La photo 1 montre le signal PWM obtenu sur l’écran d’un oscilloscope.
Dans le cas du Phase Correct PWM Mode, on veut que le timer2 compte de 0 à 255 et décompte de 255 à 0 ; les 3 bits (des registres de contrôle TCCR2A et TCCR2B) WGM22:0 doivent former la valeur 1 (soit 001 en binaire, ce qui règle TOP = 255). On veut récupérer un signal PWM non inversé sur la broche OC2A (la broche 17 du microcontrôleur ATmega328P ou encore la sortie 11 du module Arduino Uno). Les 2 bits (du registre de contrôle TCCR2A) COM2A1:0 doivent former la valeur 2 (soit 10 en binaire) pour que le signal soit non inversé. Pour un rapport de 50%, on charge le registre OCR2A avec la valeur 128.
La figure 6 montre comment le timer2 évolue ; le registre OC2A est mis à 0 quand le timer2 devient égal à OCR2A en s’incrémentant et le registre OC2A est mis à 1 quand le timer2 devient égal à OCR2A en se décrémentant.
Le programme suivant est celui de ce deuxième exemple avec N = 8 : d’après la formule donnée plus haut, la fréquence est de 3,9216 kHz.
/* ---------------------------------------------
Exemple 2 de l'article Timers IV
N = 8 pour le prescaler
La PWM de frequence 3921,6 Hz
est sur la sortie 11 du module UNO
------------------------------------------------
*/
void setup(){
pinMode (11, OUTPUT);
TCCR2A = 0b10000001;
TCCR2B = 0b00000010;
OCR2A = 128;
}
void loop(){
}
La photo 2 montre le signal PWM obtenu sur l’écran d’un oscilloscope.
Il est évident que ces deux exemples ne peuvent pas être obtenus en même temps puisqu’un timer ne peut travailler que dans un seul mode à la fois.
Conclusion
Nous n’avons fait que survoler la génération d’un signal PWM par les timers du microcontrôleur ATmega328P. Encore une fois, le recours à la documentation du constructeur est nécessaire pour bien programmer les timers dans les modes PWM, mais cette programmation au cœur même du microcontrôleur permet de compléter la fonction analogWrite
du langage Arduino.
En effet, l’IDE d’Arduino configure les timers avant même d’exécuter la fonction setup. Le timer2 par exemple est initialisé en mode Phase Correct PWM avec un prescaler où N vaut 64, ce qui donne une fréquence de 490 Hz nettement insuffisante pour la bonne santé de nos moteurs de trains miniatures. Quand la fonction analogWrite
est appelée, elle agit sur les bits COM2A ou COM2B pour connecter les sorties et obtenir la PWM dessus. Vous savez maintenant comment agir sur les registres de contrôle pour changer la fréquence de vos signaux PWM.