Atmega32
From Eric
m |
|||
Line 53: | Line 53: | ||
Le transfert du programme se fait ''in-situ'' à l'aide du programmateur USBASP et du programme [http://www.nongnu.org/avrdude Avrdude]. | Le transfert du programme se fait ''in-situ'' à l'aide du programmateur USBASP et du programme [http://www.nongnu.org/avrdude Avrdude]. | ||
+ | |||
+ | == Génération de signaux PWM == | ||
+ | |||
+ | Les moteurs à courant continu de [[Trobot1]]] sont pilotés en PWM par un ATMEGA32. J'utilise pour cela les deux sorties OC1A (moteur droit) et OC1B (moteur gauche). | ||
+ | |||
+ | Ces sorties sont commandées en PWM mode 8 : ''PWM Phase and Frequency Correct'' avec la valeur de TOP (j'y viens, j'y viens) déterminée par la valeur du registre ICR1. | ||
+ | |||
+ | La figure ci-dessous illustre le mode de fonctionnement retenu. | ||
+ | |||
+ | [[File:atmega32_pwm_mode8.png|400px|thumb|none]] | ||
+ | |||
+ | Le principe est le suivant : | ||
+ | * Le compteur 16 bits TCNT1 est incrémenté périodiquement (on verra plus loin comme est obtenue cette horloge) jusqu'à atteindre la valeur TOP déterminée par le registre ICR1 ; il est alors décrémenté jusqu'à la valeur BOTTOM (0) et le cycle recommence. | ||
+ | * Lors de la phase de croissance, lorsque le compteur atteint la valeur définie par le registre OCR1A (resp. OCRAB), la sortie OC1A (resp. OC1B) passe à un ; réciproquement, lors de la phase de décroissance, lorsque le compteur atteint la valeur définie par le registre OCR1A (resp. OCR1B), la sortie OC1A (resp. OC1B) passe à zéro. | ||
+ | |||
+ | Le résultat est un signal dont la période est déterminée par la fréquence d'horloge et la valeur du compteur ICR1 et dont le rapport cyclique est déterminé par la valeur de OCR1X. | ||
+ | |||
+ | Le code correspondant est le suivant : | ||
+ | <code> | ||
+ | // In the PWM phase and frequency correct mode, the counter goes from BOTTOM | ||
+ | // to TOP and then from TOP to BOTTOM for a period. | ||
+ | // As we are trying to calculate the counter value for TOP, it represents | ||
+ | // half the PWM period. | ||
+ | period = period /2; | ||
+ | |||
+ | // Compute the prescaler value. | ||
+ | while ( ((65535UL*PRESCALER[cs]*1000UL) / (F_CPU/1000UL)) < (period)) | ||
+ | { | ||
+ | cs++; | ||
+ | } | ||
+ | |||
+ | TOP = (period* (F_CPU/100UL))/ ( PRESCALER[cs]*10000UL); | ||
+ | |||
+ | // Compare output mode, phase and frequency correct PWM | ||
+ | // FOC1A and B are don't care, set to 0 for compatibility. | ||
+ | // MODE 8: WGM13=1, WGM12=0 WGM11=0 WGM10=0 )(PWM phase and frequency correct) | ||
+ | // TOP = OCR1A | ||
+ | TCCR1A= (1 << COM1A1) | (1 << COM1A0) | | ||
+ | (1 << COM1B1) | (1 << COM1B0) | | ||
+ | (0 << FOC1A) | (0 << FOC1B) | | ||
+ | (0 << WGM11) | (0 << WGM10); | ||
+ | |||
+ | // MODE 8: WGM13=1, WGM12=0 (PWM phase and frequency correct) | ||
+ | // ICNC1, ICES1 : don't care | ||
+ | // No prescaling : at F_CPU=1MHz, | ||
+ | TCCR1B = (0 << ICNC1) | (0 << ICES1) | | ||
+ | (1 << WGM13 ) | ( 0 << WGM12 ) | (cs+1); | ||
+ | |||
+ | // ICR1 defines the TOP value | ||
+ | ICR1 = TOP; | ||
+ | |||
+ | // OCR1A determine the pulse width for OC1A | ||
+ | // OCR1A determine the pulse width for OC1B | ||
+ | OCR1A = 0; | ||
+ | OCR1B = 0; | ||
+ | </code> | ||
+ | |||
+ | == Problèmes courants == | ||
+ | |||
+ | === Pas de démarrage! === | ||
+ | Symptome : le composant se programme bien mais refuse de démarrer. | ||
+ | Diagnostic : il s'agit peut-être d'une mauvaise programmation des fusibles. Ces fusibles peuvent être programmés à l'aide d'[[Avrdude]] en mode "terminal". | ||
+ | ''A compléter'' |
Revision as of 12:07, 15 February 2011
Contents |
Programmation de l'Atmega 32
Edition, compilation et édition de liens
Utilisation des flottants
L'utilisation du format "%f" nécessite l'utilisation d'une bibliothèque particulière, printf_flt.a
qui contient le code de la fonction vfprintf
supportant les conversions flottantes. Ceci est expliqué en détail dans la description de la bibliothèque "std_lib" de la libc d'AVR (ici, dont voici un extrait :
Since the full implementation of all the mentioned features becomes fairly large, three different flavours of vfprintf() can be selected using linker options. The default vfprintf() implements all the mentioned functionality except floating point conversions. A minimized version of vfprintf() is available that only implements the very basic integer and string conversion facilities, but only the # additional option can be specified using conversion flags (these flags are parsed correctly from the format specification, but then simply ignored). [...]
En effet, la fonction vfprintf
standard (qui constitue le coeur des fonctions printf
) est simplifiée de façon à occuper le moins de place possible. Aussi, si on ne substitue pas la version complète de vfprintf
à la version minimaliste, l'affichage d'une valeur flottante se résume à un "?" !
Pour effectuer cette substitution, il faut modifier les options de compilation de façon à ce que :
- la bibliothèque
printf_flt.a
résolve le symbolevfprintf
en lieu et place de la bibliothèque standard ; - la bibliothèque mathématique soit chargée.
Les options à utiliser au niveau du Makefile sont les suivantes (le fichier complet est [ici]):
## Compile options common for all C compilation units. CFLAGS = $(COMMON) CFLAGS += -Wall -gdwarf-2 -std=gnu99 -DF_CPU=1000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d
## Assembly specific flags ASMFLAGS = $(COMMON) ASMFLAGS += $(CFLAGS) ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2
## Linker flags LDFLAGS = $(COMMON) LDFLAGS += -uvfprintf -Wl -Map=CtrlRobot.map LIBS = -lprintf_flt -lm
Ici, l'option importante est -uvfprintf
qui supprime la résolution de vfprintf
de façon à ce qu'il soit résolu par la version contenue dans la bibliothèque printf_flt
.
Il faut aussi noter l'utilisation de la bibliothèque mathématique (-lm
) optimisée pour l'AVR. En l'absence de cette option, l'édition de liens s'effectue avec la bibliothèque standard, se qui conduit à des messages d'erreurs du linker ("relocation truncated to fit") qui traduisent des déplacements trop grands pour l'AVR.
Ces options peuvent normalement être modifiées directement sous l'environnement AVR.
Nota : on vérifiera dans le fichier "map" que le symbole vfprintf
est bien résolu. Ainsi, dans le cas de l'application pour laquelle j'ai eu le besoin de réaliser des entrées / sorties flottante, on trouve les lignes suivantes :
c:/bin/winavr-20100110/bin/../lib/gcc/avr/4.3.3/../../../../avr/lib/avr5\libprintf_flt.a(vfprintf_flt.o) (vfprintf)
Transfert du programme
Le transfert du programme se fait in-situ à l'aide du programmateur USBASP et du programme Avrdude.
Génération de signaux PWM
Les moteurs à courant continu de Trobot1] sont pilotés en PWM par un ATMEGA32. J'utilise pour cela les deux sorties OC1A (moteur droit) et OC1B (moteur gauche).
Ces sorties sont commandées en PWM mode 8 : PWM Phase and Frequency Correct avec la valeur de TOP (j'y viens, j'y viens) déterminée par la valeur du registre ICR1.
La figure ci-dessous illustre le mode de fonctionnement retenu.
Le principe est le suivant :
- Le compteur 16 bits TCNT1 est incrémenté périodiquement (on verra plus loin comme est obtenue cette horloge) jusqu'à atteindre la valeur TOP déterminée par le registre ICR1 ; il est alors décrémenté jusqu'à la valeur BOTTOM (0) et le cycle recommence.
- Lors de la phase de croissance, lorsque le compteur atteint la valeur définie par le registre OCR1A (resp. OCRAB), la sortie OC1A (resp. OC1B) passe à un ; réciproquement, lors de la phase de décroissance, lorsque le compteur atteint la valeur définie par le registre OCR1A (resp. OCR1B), la sortie OC1A (resp. OC1B) passe à zéro.
Le résultat est un signal dont la période est déterminée par la fréquence d'horloge et la valeur du compteur ICR1 et dont le rapport cyclique est déterminé par la valeur de OCR1X.
Le code correspondant est le suivant :
// In the PWM phase and frequency correct mode, the counter goes from BOTTOM // to TOP and then from TOP to BOTTOM for a period. // As we are trying to calculate the counter value for TOP, it represents // half the PWM period. period = period /2; // Compute the prescaler value. while ( ((65535UL*PRESCALER[cs]*1000UL) / (F_CPU/1000UL)) < (period)) { cs++; } TOP = (period* (F_CPU/100UL))/ ( PRESCALER[cs]*10000UL); // Compare output mode, phase and frequency correct PWM // FOC1A and B are don't care, set to 0 for compatibility. // MODE 8: WGM13=1, WGM12=0 WGM11=0 WGM10=0 )(PWM phase and frequency correct) // TOP = OCR1A TCCR1A= (1 << COM1A1) | (1 << COM1A0) | (1 << COM1B1) | (1 << COM1B0) | (0 << FOC1A) | (0 << FOC1B) | (0 << WGM11) | (0 << WGM10); // MODE 8: WGM13=1, WGM12=0 (PWM phase and frequency correct) // ICNC1, ICES1 : don't care // No prescaling : at F_CPU=1MHz, TCCR1B = (0 << ICNC1) | (0 << ICES1) | (1 << WGM13 ) | ( 0 << WGM12 ) | (cs+1); // ICR1 defines the TOP value ICR1 = TOP; // OCR1A determine the pulse width for OC1A // OCR1A determine the pulse width for OC1B OCR1A = 0; OCR1B = 0;
Problèmes courants
Pas de démarrage!
Symptome : le composant se programme bien mais refuse de démarrer. Diagnostic : il s'agit peut-être d'une mauvaise programmation des fusibles. Ces fusibles peuvent être programmés à l'aide d'Avrdude en mode "terminal". A compléter