Hallo zusammen,
hab hier ein Problem mit dem Timer1 dessen Verhalten ich mir einfach
nicht erklären kann. Vielleicht weiß ja jemand von euch an was es liegt.
Umgebung:
- AVR Studio 6.2
- ATMEGA3250P
- Debugging/Programmieren mit Atmel ICE
Nachdem das ganze in einem größeren Programm für Schwierigkeiten gesorgt
hat, hab ich alles aufs Minimum reduziert um möglichst viel
auszuschließen:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
4
#define PWM_ON_TIME 50
5
#define PWM PINB5
6
7
ISR(TIMER1_OVF_vect){
8
PORTE&=~(1<<PE0);
9
}
10
11
intmain(void)
12
{
13
DDRE|=(1<<PE0);
14
DDRB|=(1<<PWM);
15
TCCR1A=(1<<WGM10)|(1<<WGM11)|(1<<COM1A1);
16
TCCR1B=(1<<CS11)|(1<<CS10);
17
TCCR1C=0;
18
// Set the output compare register to defined on time
19
OCR1AH=0;
20
OCR1AL=PWM_ON_TIME;
21
TIMSK1=(1<<TOIE1);
22
23
sei();
24
25
while(1)
26
{
27
PORTE|=(1<<PE0);
28
}
29
}
Ziel ist es, Timer1 im 10-bit "Phase Correct PWM Mode" zu betreiben und
beim Überlauf des Timers bei 0 etwas zu tun. Beim Debuggen im Simulator
ist alles wie erwartet, bei einem Breakpoint in der ISR ist das
Zählregister TCNT1 auf 1 oder max. 3, also kurz nachdem der Zähler auf 0
war.
Sobald ich das aber auf der HW laufen lasse, ist TCNT1 in der ISR
scheinbar auf einen Zufallswert irgendwo zwischen 0 und TOP.
Was das alles noch interessanter macht: das TOV1 Flag ist auf 1, also
nicht gelöscht wie es m.M.n. in der ISR sein sollte.
Das globale I Flag hingegen funktioniert wie erwartet, in der ISR 0, in
main 1.
Hab das ganze auch ohne Debugger laufen lassen und darauf hin getestet
mit keiner Besserung.
Nun meine Fragen:
Habe ich hier etwas Grundsätzliches im Zusammenhang mit
Timerkonfiguration oder Interrupts übersehen?
Kann man im AVR Studio irgendwelche Debugeinstellunen die Timer
betreffend vornehmen?
Vielen Dank vorab und liebe Grüße,
Sepp
Hallo,
Du hast WGM13 nicht gesetzt - brauchst Du, wenn Du mit OCR1A vergleichen
willst -> Mode 11 (Datenblatt S. 130 :-) ).
Ach ja - und bedenke, dass jede Interrupt-Routine einen Prolog und
Epilog hat, in welcher Register gesichert werden etc. Außerdem braucht
der Sprung zur Routine auch Taktzyklen. Du wirst also in der ISR nicht
so einfach bei Timerstand = 0 irgendwelchen Code ausführen können.
Ggf. müsstest Du Dich über einen Compare-Interrupt mit entsprechendem
Vorlauf vor dem Overflow-Interrupt heranhangeln - ggf. sogar über eine
eigengestrickte ISR, damit der Compiler da nicht zwischnfunkt und
optimiert. Da bin ich aber auf sehr dünnem Eis ...
Gruß
Dieter
Hallo Dieter,
Danke für die Tipps, leider weiß ich trotzdem nicht worans liegt...
WGM13 muss ich m.M.n. nicht setzen, da ich den Mode 7 (DB
2570N–AVR–05/11 s. 125 Table 17-5) für den für mich passenden halte. Mit
OCR1A wird da trotzdem verglichen und OC1A entsprechend gesetzt, das
funktioniert auch wie gewünscht, hab ich mit dem Oszi überprüft.
Weiters will ich ja nicht bei Timerstand 0 in der ISR beginnen,
irgendwas unter 5 (1MHz Takt, Prescaler 64 => < 320 Takte) reicht mir
vollkommen. In 320 Takten sollte die CPU doch in die ISR finden...
Zudem erklärt so eine Zeitverzögerung auch nicht warum das TOV1 Flag
nicht richtig gesetzt ist.
Sepp schrieb:> Ziel ist es, Timer1 im 10-bit "Phase Correct PWM Mode" zu betreiben und> beim Überlauf des Timers bei 0 etwas zu tun.Sepp schrieb:> WGM13 muss ich m.M.n. nicht setzen, da ich den Mode 7 (DB> 2570N–AVR–05/11 s. 125 Table 17-5) für den für mich passenden halte.Sepp schrieb:> Sorry, ich meinte natürlich Mode 3 "PWM, Phase Correct, 10-bit"
Hallo Sepp,
ja - was denn nun?
Du setzt OCR1A als Top-Wert - das zielt auf Phase Correct PWM mit OCR1A
als Top-Wert (Mode 11). Fast PWM mit 0x3FFF als Top-Wert (Mode 7) ist
deutlich anders. Aktuell hast Du Mode 3 eingestellt - da bringt die
OCR1A-Einstellung rein gar nichts.
Im 2. Fall müsstest Du auch WGM12 setzen, was Du nicht gemacht hast.
Hast Du Dir die Tabelle 17-5 mal genau angeschaut? Ich schätze, da musst
Du doch die Brille aufsetzen :-)
Sepp schrieb:> Zudem erklärt so eine Zeitverzögerung auch nicht warum das TOV1 Flag> nicht richtig gesetzt ist.Sepp schrieb:> Was das alles noch interessanter macht: das TOV1 Flag ist auf 1, also> nicht gelöscht wie es m.M.n. in der ISR sein sollte.
In der letzten Spalte ist definiert, wann das TOV1-Flag gesetzt wird -
nämlich im Mode 3 auf BOTTOM.
Willst Du PWM überhaupt nutzen? Oder willst lediglich in definierten
Zeitabständen irgendwelchen Code ausführen?
Gruß
Dieter
Ok, gebe zu dass meine Erklärungen wohl etwas verwirrend waren. Deshalb
nun ein neuer Versuch:
Ich möchte gern mit Timer1 ein PWM Signal auf dem OC1A pin erzeugen, an
dem eine Lichtschranke angeschlossen ist. In der Mitte des periodisch
auftretenden Highpulses soll der Zustand des Phototransistors der
Schranke eingelesen werden. Das ganze ist mir mit dem gleichen Code
bereits auf einem Steckbrett und einem ATMega32 gelungen. Mit dem
ATMega3250 plötzlich nicht mehr.
Nun zu meinen Überlegungen im Detail:
Der "Phase Correct PWM Mode" erschien mir passend:
DB Kap. 17.9.4:
"The counter counts repeatedly from BOTTOM (0x0000) to TOP and then from
TOP to BOTTOM. In non-inverting Compare Output mode, the Output Compare
(OC1x) is cleared on the compare match between TCNT1 and OCR1x while
counting up, and set on the compare match while counting down."
Tabelle 17.4: "Compare Output Mode, Phase Correct and Phase and
Frequency Correct PWM"
COM1A1 = 1, COM1A0 = 0
"Clear OC1A/OC1B on Compare Match when upcounting. Set OC1A/OC1B on
Compare Match when counting down."
Setz ich also OCR1A auf z.B. 50 entsteht also rund um den 0-Zählerstand
ein Highpuls.
Weiters steht da geschrieben:
"The Timer/Counter Overflow Flag (TOV1) is set each time the counter
reaches BOTTOM."
Wenn ich jetzt auf dieses Flag mit einem Interrupt reagiere, kann ich
kurz nach Zählerstand 0 den Input einlesen.
Tabelle 17-5.
WGM13 = 0, WGM12 = 0, WGM11 = 1, WGM10 = 1
=> Mode 3 PWM, Phase Correct, 10-bit, TOP = 0x03FF
TOV1 Flag Set on BOTTOM.
So, und genau das passiert nicht, TOV1 wird scheinbar IRGENDWANN
gesetzt.
Warum nur?
LG
Sepp
Sepp schrieb:> Ich möchte gern mit Timer1 ein PWM Signal auf dem OC1A pin erzeugen, an> dem eine Lichtschranke angeschlossen ist. In der Mitte des periodisch> auftretenden Highpulses soll der Zustand des Phototransistors der> Schranke eingelesen werden.
O.K. - in welchem zeitlichen Abstand?
Sepp schrieb:> In non-inverting Compare Output mode, the Output Compare> (OC1x) is cleared on the compare match between TCNT1 and OCR1x while> counting up, and set on the compare match while counting down."
Das Wörtchen "compare" hast Du wahrgenommen?
Wie Zeitkritisch ist das Ganze denn? Willst Du Energie sparen, weil Du
die Lichtschranke nur "ab und an" einschaltest?
Also mit aktuellem Kenntnisstand würde ich mit Mode 11 arbeiten parallel
den Compare Interrupt (mit entsprechender Einstellung) aktivieren. Also
per Hardware die Lichtschranke ein/ ausschalten lassen und per
"compare-Interrupt" die Lichtschranke auswerten.
Das "warum" erschließt sich mir leider immer noch nicht - es gibt
"normale" Lichtschranken in allen möglichen Formaten ...
Gruß
Dieter
Dieter Frohnapfel schrieb:> Das "warum" erschließt sich mir leider immer noch nicht - es gibt> "normale" Lichtschranken in allen möglichen Formaten ...
Warum wird der Overflow Interrupt von Timer1 scheinbar bei verschiedenen
TCNT1 Ständen ausgeführt und nicht immer bei Stand 0. Es ist die Frage
und wenn sie sich dir nicht erschließt ...
@Sepp
Wie stellst du das fest? Wie mißt du das? Wie läßt du dir den
Zählerstand ausgeben? Vielleicht Meßfehler?
Dieter Frohnapfel schrieb:> In der letzten Spalte ist definiert, wann das TOV1-Flag gesetzt wird -> nämlich im Mode 3 auf BOTTOM
Das muss ich zurücknehmen ... ist zwar lt. Tabelle so, aber die Realität
sieht anders aus ... .
Ich habe das Ganze mal auf einen ATMega32 portiert und (mit 16 MHz Takt)
laufen lassen.
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
4
#define PWM_ON_TIME 50
5
#define PWM PIND5
6
7
ISR(TIMER1_OVF_vect){
8
PORTA&=~(1<<PA0);
9
}
10
11
intmain(void)
12
{
13
DDRA|=(1<<PA0);
14
DDRD|=(1<<PWM);
15
TCCR1A=(1<<WGM10)|(1<<WGM11)|(1<<COM1A1);
16
TCCR1B=(1<<CS11)|(1<<CS10);
17
// TCCR1C = 0;
18
// Set the output compare register to defined on time
19
OCR1AH=0;
20
OCR1AL=PWM_ON_TIME;
21
TIMSK=(1<<TOIE1);
22
23
sei();
24
25
while(1)
26
{
27
PORTA|=(1<<PA0);
28
}
29
}
Sieht alles einwandfrei und regelmässig aus - Hardcopys der
Oszilloskop-Ansichten habe ich beigefügt. Gelb = PWM-Pin und Blau =
ISR-Pin. Daher vermute ich auch, Du misst Mist :-)
Gruß
Dieter
Dieter Frohnapfel schrieb:>> In der letzten Spalte ist definiert, wann das TOV1-Flag gesetzt wird ->> nämlich im Mode 3 auf BOTTOM>> Das muss ich zurücknehmen ... ist zwar lt. Tabelle so, aber die Realität> sieht anders aus ... .
Das zu: "Lies das Datenblatt" -Ratschlägen.
MfG Paul
Paul Baumann schrieb:> Das zu: "Lies das Datenblatt" -Ratschlägen.
Hallo Paul,
durch Deine Antwort konnte ich nicht mehr korrigieren ... :-(
Das Datenblatt ist korrekt - meine Interpretation nicht ...
"In non-inverting Compare Output mode, the Output Compare (OC1x)
is cleared on the compare match between TCNT1 and OCR1x while
upcounting, and set on the compare match while downcounting."
Das heisst, nach 50 Zählern wir der Pin auf GND gesetzt (und es wird bis
TOP = 0x03FF weitergezählt) und beim herunterzählen wird der Pin ab
Zählerstand 50 auf high gesetzt. Genau auf Bottom (Zählerstand = 0) wird
der Interrupt ausgelöst. Das ist in der Oszilloskop-Ansicht auch gut zu
sehen.
Es ist (zumindest für mich) halt auf Anhieb nicht so einfach zu
verstehen ...
Fazit: Datenblatt lesen und richtig interpretieren :-)
Vielleicht kann der Moderator ja diesen Satz
"Das muss ich zurücknehmen ... ist zwar lt. Tabelle so, aber die
Realität
sieht anders aus ... ."
aus meinem vorigen Posting entfernen - bitte!
Gruß
Dieter
lander schrieb:> Warum wird der Overflow Interrupt von Timer1 scheinbar bei verschiedenen> TCNT1 Ständen ausgeführt und nicht immer bei Stand 0.
Ausgelöst wird der Interupt garantiert bei 0 (im konkreten Fall).
Ausgeführt wird die zugehörige ISR hingegen erst, wenn Zeit dazu ist.
Und Zeit dazu ist, wenn die globalen Interrupts erlaubt sind, der
Overflow-Interupt selber erlaubt ist und nicht noch ein Interupt
höherer Priorität auf Ausführung wartet.
Da sind eine ganze Menge Ansatzpunkte, um eine Situation herzustellen,
in der erstens die Overflow-ISR zu einem (virtuell) zufälligen Zeitpunkt
ausgeführt wird und zweitens auch, um das TOVF-Bit gesetzt zu sehen.
Man muß einfach nur hinreichend wenig Ahnung vom korrekten Programmieren
haben, dann klappt das von ganz alleine irgendwann...
c-hater schrieb:> Man muß einfach nur hinreichend wenig Ahnung vom korrekten Programmieren> haben, dann klappt das von ganz alleine irgendwann...
Der Satz kommt in mein kleines schwarzes Merkbuch - das mit den
Passwörtern, wichtigen Programmen, etc. :-)
c-hater schrieb:> Da sind eine ganze Menge Ansatzpunkte, um eine Situation herzustellen,> in der erstens die Overflow-ISR zu einem (virtuell) zufälligen Zeitpunkt> ausgeführt wird und zweitens auch, um das TOVF-Bit gesetzt zu sehen
Im konkreten Fall (s.o.) gibt es aber nur eine ISR, für die ausreichend
Zeit bleibt -> Messfehler ...
c-hater schrieb:> lander schrieb:>>> Warum wird der Overflow Interrupt von Timer1 scheinbar bei verschiedenen>> TCNT1 Ständen ausgeführt und nicht immer bei Stand 0.>> Ausgelöst wird der Interupt garantiert bei 0 (im konkreten Fall).
Das weiß ich.
> Ausgeführt wird die zugehörige ISR hingegen erst, wenn Zeit dazu ist.> Und Zeit dazu ist, wenn die globalen Interrupts erlaubt sind, der> Overflow-Interupt selber erlaubt ist und nicht noch ein Interupt> höherer Priorität auf Ausführung wartet.
Das weiß ich auch.
> Da sind eine ganze Menge Ansatzpunkte, um eine Situation herzustellen,> in der erstens die Overflow-ISR zu einem (virtuell) zufälligen Zeitpunkt> ausgeführt wird und zweitens auch, um das TOVF-Bit gesetzt zu sehen.
Na klar.
> Man muß einfach nur hinreichend wenig Ahnung vom korrekten Programmieren> haben, dann klappt das von ganz alleine irgendwann...
Irgendwas Neues?
Good news everyone,
hab das/die Probleme gelöst. Zwei Dinge waren dazu nötig:
1. Bei den Tool-Einstellungen für den JTAG Atmel ICE Debugger das
Häckchen bei "Keep timers running in stop mode" weggeben. Ich war der
Meinung, dass der Code beim On-Chip Debuggen wenigstens bis zum
Breakpoint mit der normalen Geschwindigkeit läuft, dem ist aber nicht
so. Deswegen war der Counter im I/O View schon viel weiter als 0
gelaufen bis das Programm wirklich angehalten war. Das gleiche mit dem
TOV1 Flag.
Das erklärt aber immer noch nicht, warum das ganze nicht ohne Debugger
geklappt hat, was ich ja ebenso getestet habe.
2. Update von Atmel Studio auf die neueste Version (6.2.1563 - Service
Pack 2).
An was es jetzt konkret gelegen hat oder ob ich vielleicht doch noch
irgendwo einen Auswerefehler gemacht hab kann ich nicht sagen, mir fehlt
auch die Zeit/Nerven um den ganz auf den Grund zu gehen.
Jedenfalls klappt jetzt alles wie erwartet.
Danke für eure Unterstützung und das heitere Klima in diesem Forum! :-)