Hallo,
ich möchte den Timer0 im AVR missbrauchen, um eine fallende Flanke eines
externen Signals zu detektieren. Ich simuliere das externe Signal, indem
ich den T0-Pin als Ausgang festlege und per Software einen Pulse
generiere.
Falls es wichtig sein sollte: uC ist der ATMega328P.
Mit folgendem Asm-Codeschnipsel will ich die Erkennung durchführen:
1
// PD4 (=T0) als Ausgang und auf low
2
sbi _SFR_IO_ADDR (DDRD), DDD4
3
cbi _SFR_IO_ADDR (PORTD), PD4
4
5
// Kein Int handling, Erkennung ueber Abfrage TIFR0
6
cli
7
8
// Timer aus, falls er laeuft
9
ldi r18, (0b000 << CS00)
10
out _SFR_IO_ADDR (TCCR0B), r18
11
12
// Timer0 vorbereiten: CTC, OCR0A=0
13
ldi r18, 0
14
out _SFR_IO_ADDR (TCNT0), r18
15
ldi r18, 0
16
out _SFR_IO_ADDR (OCR0A), r18
17
ldi r18, (0b10 << WGM00)
18
out _SFR_IO_ADDR (TCCR0A), r18
19
ldi r18, (0 << WGM20) | (0b110 << CS00)
20
out _SFR_IO_ADDR (TCCR0B), r18
21
22
// Evtl. OCF0A loeschen
23
sbi _SFR_IO_ADDR (TIFR0), OCF0A
24
25
nop
26
nop
27
nop
28
nop
29
nop
30
nop
31
32
// Pulse auf T0 generieren
33
sbi _SFR_IO_ADDR (PORTD), PD4
34
nop
35
cbi _SFR_IO_ADDR (PORTD), PD4
36
nop
37
38
// Warten wg. Edge Detector
39
nop
40
nop
41
nop
42
nop
43
nop
44
nop
45
nop
46
nop
47
48
// Erkennung
49
clr r24
50
sbic _SFR_IO_ADDR (TIFR0), OCF0A
51
inc r24
Ergebnis ist jedoch immer 0, also Flanke nicht erkannt.
Leider ist das Datenblatt etwas missverständlich. Unter Output Compare
Unit heisst es:
The 8-bit comparator continuously compares TCNT0 with the Output
Compare Registers (OCR0A and OCR0B). Whenever TCNT0 equals OCR0A [...],
the comparator signals a match. Somit würde ich erwarten, dass OCR0A
eigentlich 1 sein müsste, damit er nach einem ClkTn den TCNT0 auf 1
hätte und dann, gemäß obiger Aussage, einen Compare Match signalisieren
würde.
Demgegenüber zeigt aber das Diagramm "Timer/Counter Timing Diagram,
Clear Timer on Compare Match mode", dass der Compare Match nur
durchgeführt wird, nachdem ein Puls auf clkTn vorliegt.
Beide Fälle habe ich im abgeprüft, hier codiert ist der zweite Fall (den
ich auch für wahrscheinlich halte, sonst hätte Atmel nicht extra ein
Diagramm dazu gemalt). Aber beide Prüfungen gaben auch dasselbe
Ergebnis.
Habt ihr noch ne Idee?
Ach so: es muss der Weg über den Timer sein, da ich von insgesamt 4
externen Signalen die Flanken beobachten muss und ich für die ersten 3
schon die Wege INT0, INT1 und ICP1 beschreite.
Volker
Volker schrieb:> Habt ihr noch ne Idee?
Zu knapp beschrieben, wie das ganze funktionieren soll.
Nimm einen PCINT und frage in der ISR ab, ob der auslösende PIN high
oder low ist. Ein high zeigt eine vorausgehende steigende Flanke an.
>ich möchte den Timer0 im AVR missbrauchen,>um eine fallende Flanke eines externen>Signals zu detektieren.
Was ist denn daran zu knapp beschrieben?
Wie würdest Du denn eine fallende Flanke detektieren? Dein Weg über den
PCINT führt leider nicht zum Ziel, denn damit kann ich nur eine
beliebige Flanke detektieren (siehe DB). Und Dein Vorschlag, in der ISR
den Pegel zu prüfen, ist ja nicht wirklich das Wahre; während der Zeit,
bis die ISR zur Ausführung kommt, kann sich der Pegel ja wieder ändern.
...sonst bräuchte man ja nie eine Flankenerkennung.
Volker schrieb:> Habt ihr noch ne Idee?
Ja.
Wie kommst du auf die Idee, OCR0A auf 0 zu setzen und zu erwarten,
dass es funktioniert ?
Es wird funktionieren, aber erst nach 256 Mal.
Setze OCR0A auf 1 und es wird funktionieren.
Tut es nicht, ich schrieb ja, dass ich auch diesen Fall geprüft habe und
es nicht funktionierte. Und dann wäre das referenzierte Diagramm im DB
auch falsch, wonach der OCF0A dann gesetzt wird, wenn TCNT0=MAX (=OCR0A)
zum Ende eines clkTn ist.
> Somit würde ich erwarten, dass OCR0A eigentlich 1 sein müsste
Ja, und warum hast du das Register dann mit 0 initialisiert?
Nachtrag: Während ich meine spontane Antwort mit dem DB vergleichen
habe, um peinliche Fehler zu vermeinden, haben andere schon schneller
geantwortet.
> Sollte 7 sein...
Die 7 musst Du mir erklären, vllt. liegt hier mein Missverständnis. Du
gibst 8 Pulse auf den T0, ich erwarte entsprechend ein r24=8.
Hab Deinen Vorschlag ausprobiert (es fehlt natürlich noch ein
1
sbi TIFR0, OCF0A
am Ende der Erkennung, um das gesetzte OCF0A wieder zu löschen) und das
Ergebnis ist nicht wie von Dir vorausgesagt.
>Ja, und warum hast du das Register dann mit 0 initialisiert?
Weil ich dem Diagramm aus dem DB gefolgt bin (nur, dass wir vom Gleichen
reden: Figure 15-11 im DB zum ATmega48A-328P) und ich ja auch schrieb:
>den ich auch für wahrscheinlich halte
Wie dem auch sei, auch die Initialisierung OCR0A=1 bringt nicht das zu
erwartende Ergebnis.
Und noch ein Punkt: das DB redet beim CTC-Mode (vgl. 15.7.2) von
Folgendem:
The waveform generated will have a maximum frequency of f OC0 = f
clk_I/O /2 when OCR0A is set to zero (0x00).
Maximum wohlgemerkt, nicht mimimum
S. Landolt schrieb:> Wie wäre es, ohne compare zu arbeiten? Also im normal mode den> TCNT0> mit 255 vorbelegen und auf TIFR0, TOV0 abfragen.
So einen ähnlichen Weg werde ich wohl einschlagen, ich werde
wahrscheinlich TCNT0 mit einem seinem zwischengespeicherten letzten Wert
vergleichen und bei Abweichung hab ich meine Flanke erkannt. Spart mir
auch das Neusetzen von TCNT0 zur Erkennung weiteren Flanken.
Aber es wurmt mich schon, dass es da keinen eleganteren Weg gibt, wie
beim INT0/1.
...und es erschüttert ein wenig mein Grundverständnis der AVR Timer.
Volker schrieb:> Tut es nicht, ich schrieb ja, dass ich auch diesen Fall geprüft habe und> es nicht funktionierte. Und dann wäre das referenzierte Diagramm im DB
Nochmal.
OCR0B bleibt auf 0.
OCR0A setzst du auf 1.
Bei 1 setzt OCR0A den Flag OCF0A.
Bei 0 setzt OCR0B den Flag OCF0B.
Einmal Dummy Puls am Anfang und dann läuft es.
Zum Probieren:
1
;PD4(=T0)alsAusgangundauflow
2
sbiDDRD,DDD4
3
cbiPORTD,PD4
4
5
;KeinInthandling,ErkennungueberAbfrageTIFR0
6
cli
7
8
;Timeraus,fallserlaeuft
9
ldir18,(0b000<<CS00)
10
outTCCR0B,r18
11
12
;Timer0vorbereiten:CTC,OCR0B=0,OCR0A=´1
13
ldir18,0
14
outTCNT0,r18
15
outOCR0B,r18
16
incr18
17
outOCR0A,r18
18
ldir18,(0b10<<WGM00)
19
outTCCR0A,r18
20
ldir18,(0<<WGM20)|(0b110<<CS00)
21
outTCCR0B,r18
22
23
;OCF0AundOCF0Bloeschen
24
sbiTIFR0,OCF0A
25
sbiTIFR0,OCF0B
26
27
nop
28
nop
29
nop
30
nop
31
nop
32
nop
33
34
rcallPulse;*DummyPulse
35
;**************TESTEN************************
36
ldir18,8
37
clrr24
38
clrr25
39
lp1:
40
rcallPulse
41
;Erkennung
42
Chk0A:
43
sbisTIFR0,OCF0A
44
rjmpChk0B
45
incr24
46
sbiTIFR0,OCF0A
47
rjmpLoop
48
Chk0B:
49
sbisTIFR0,OCF0B
50
rjmpLoop
51
incr25
52
sbiTIFR0,OCF0B
53
Loop:
54
decr18
55
brnelp1
56
57
Halt:rjmpHalt
58
59
Pulse:
60
;PulseaufT0generieren
61
sbiPORTD,PD4
62
nop
63
cbiPORTD,PD4
64
nop
65
;Wartenwg.EdgeDetector
66
nop
67
nop
68
nop
69
nop
70
nop
71
nop
72
nop
73
nop
74
ret
75
;*******************************************
Jetzt sollte sowohl r24 als auch r25 4 sein.
War mein Fehler vorher, hat nur jede 2te Flanke gezählt...
Marc V. schrieb:> Nochmal.>> Einmal Dummy Puls am Anfang und dann läuft es.
Warum ein Dummy Pulse?
Und r24=4 bei 8 Pulsen hat ja weiterhin nur jede zweite Flanke gezählt,
was ich nach meinen obigen Vermutungen auch angesichts von OCR0A=1
erwarten würde.
Verstehe ich Deinen Post richtig, dass es ein Vorschlag sein soll, wie
man mit dem Timer die fallenden Flanken erkennen könnte und weniger als
Argumentation, ob jetzt OCR0A 0 oder 1 sein muss?
Ich bin nun maximal verwirrt, wie und vor allem wann der Compare Match
funktioniert.
Was würdest Du denken, welchen Wert TCNT0 während der 8 Pulse hat?
Volker schrieb:> Und r24=4 bei 8 Pulsen hat ja weiterhin nur jede zweite Flanke gezählt,> was ich nach meinen obigen Vermutungen auch angesichts von OCR0A=1> erwarten würde.
Ja.
Nur ist r25 auch 4, ergibt zusammen 8, OK ?
Hätte ich bei OCF0B auch r24 anstatt r25 erhöht...
> Ich bin nun maximal verwirrt, wie und vor allem wann der Compare Match> funktioniert.
Dummy Pulse => Vorbereiten auf die nächste fallende Flanke.
Pulse Nr.1 => OC0A setzt OCF0A, TCNT0 geht auf 0.
Pulse Nr.2 => OC0B setzt OCF0B, TCNT0 geht auf 1.
Pulse Nr.3 => OC0A setzt OCF0A, TCNT0 geht auf 0.
...
...
So wie ich das in Erinnerung habe, zählen Timer Clocks, nicht die
CPU Clocks und da du auf fallende Flanke reagierst ist es OK so.
Volker schrieb:> // PD4 (=T0) als Ausgang und auf low> sbi _SFR_IO_ADDR (DDRD), DDD4> cbi _SFR_IO_ADDR (PORTD), PD4> ldi r18, (0 << WGM20) | (0b110 << CS00)> out _SFR_IO_ADDR (TCCR0B), r18>> // Pulse auf T0 generieren> sbi _SFR_IO_ADDR (PORTD), PD4> nop> cbi _SFR_IO_ADDR (PORTD), PD4> nop
Ob da der PD4 auf Ausgang bleibt und nicht rumfloatet? Er wird aber
außen beschaltet sein wie man der knappen Beschreibung nicht entnehmen
kann.
kalaus schrieb:> Volker schrieb:>>> // PD4 (=T0) als Ausgang und auf low>> sbi _SFR_IO_ADDR (DDRD), DDD4>> cbi _SFR_IO_ADDR (PORTD), PD4>>> ldi r18, (0 << WGM20) | (0b110 << CS00)>> out _SFR_IO_ADDR (TCCR0B), r18>>>> // Pulse auf T0 generieren>> sbi _SFR_IO_ADDR (PORTD), PD4>> nop>> cbi _SFR_IO_ADDR (PORTD), PD4>> nop>> Ob da der PD4 auf Ausgang bleibt und nicht rumfloatet? Er wird aber> außen beschaltet sein wie man der knappen Beschreibung nicht entnehmen> kann.
???
Es wird nur zu Beginn der DDRD gesetzzt, danach bleibt es ein Ausgang.
Volker schrieb:> kalaus schrieb:>> Volker schrieb:>>> ldi r18, (0 << WGM20) | (0b110 << CS00)>>> out _SFR_IO_ADDR (TCCR0B), r18>> Ob da der PD4 auf Ausgang bleibt und nicht rumfloatet? Er wird aber> ???> Es wird nur zu Beginn der DDRD gesetzzt, danach bleibt es ein Ausgang.
Ich weiß nicht, was passiert, wenn er zu dem TO INPUT gemacht wird. Wenn
es ein Input ist, schaltet ein CBI im PORTB den Pullup aus und der
Eingang floatet. Kann sein, daß di Interrupt Simulation dann nicht geht.
Nur eine Theorie.
kalaus schrieb:> Volker schrieb:>> kalaus schrieb:>>> Volker schrieb:>>>> ldi r18, (0 << WGM20) | (0b110 << CS00)>>>> out _SFR_IO_ADDR (TCCR0B), r18>>> Ob da der PD4 auf Ausgang bleibt und nicht rumfloatet? Er wird aber>>> ???>> Es wird nur zu Beginn der DDRD gesetzzt, danach bleibt es ein Ausgang.>> Ich weiß nicht, was passiert, wenn er zu dem TO INPUT gemacht wird. Wenn> es ein Input ist, schaltet ein CBI im PORTB den Pullup aus und der> Eingang floatet. Kann sein, daß di Interrupt Simulation dann nicht geht.> Nur eine Theorie.
... schaltet ein CBI im PORTD den Pullup aus ...
"If external pin modes are used for the Timer/Counter0, transitions on
the T0 pin will clock the counter even if the pin is configured as an
output. This feature allows software control of the counting."