Forum: Mikrocontroller und Digitale Elektronik ASM: Timer1 Comparebertrieb arbeitet falsch


von Julian R. (tuefftler)


Angehängte Dateien:

Lesenswert?

Hallo,
um den RC5 Code meiner Fernbedienung zu decoden, will ich nach 
einstellbarer Zeit(889µs wie bei RC5 üblich) ein Interupt. Das ganze 
soll auf dem Timer1 des ATmega88P ablaufen. Bisher habe ich versucht das 
Compareregister immer um 889µs weiter als den Timerstand zu stellen.
1
lds    tmp,     TCNT1L
2
lds    tmp2,    TCNT1H
3
ldi    tmp3,    111       ;in 889µs soll er auslösen!
4
                          ;Prescaler=64 bei 8MHz(->8µs)
5
add    tmp,     tmp3
6
clr    tmp3
7
adc    tmp2,    tmp3
8
sts    OCR1AL,  tmp
9
sts    OCR1AH,  tmp2

Mein Programm ablauf ist folgender:
1.Pinchangeinterupt->Pinchangeinterupts werden deaktiviert(PCMSK0);
  Timerinterupts aktiviert UND Compareregister wird um 444µs weiter als
  TCNT1 gestellt
2.Nach 444µs wird ein Timerinterupt ausgelöst; ab diesem Zeitpunkt läuft
  der Timer auf 889µs
3.Letztes Timerinterupt für diese RC5-Sequnz, weil danach vorerst
  Sendepause ist->Timerinterupt abgeschaltet; Pinchange an

Jetzt ist das Problem, dass bei einem erneuten Pinchangeinterupt der 
Timerinterupt nicht nach 444µs sondern 889µs auslöst!?
Beim ersten Pinchange funktioniert es richtig, beim zweiten löst er nach 
889µs aus.

Im Anhang finden sich der ASM-Code und zwei Screenschots vom Timing(mit 
Soundkarte aufgezeichent!!)

von Karl H. (kbuchegg)


Lesenswert?

Ich seh in deinem Code 2 Probleme

1
    ....
2
    sei
3
    reti

Tus nicht. Der AVR hat deswegen eine eigene reti Instruktion, damit du 
eben keinen sei brauchst. Und das ist auch gut so. Denn nur so ist 
gewährleistet, dass eine ISR auch tatsächlich komplett abgeschlossen 
ist, ehe der nächste Interrupt für den Aufruf der nächsten ISR sorgen 
kann.

Schwerwiegender allerdings (wenn ich mich nicht verschaut habe) ist es, 
dass die Anzahl der push/pop in der zweiten ISR nicht stimmt. Du popst 
einmal zu viel.
1
rc5_ir_over1:
2
3
    push  tmp2         ; 1
4
    push  tmp3         ; 2
5
    push  tmp          ; 3
6
7
    ....
8
9
10
    pop    tmp        ; 2
11
12
    ....
13
14
    pop    tmp3       ; 1
15
    pop    tmp2       ; 0
16
    pop    tmp        ;  ooops. Das war die Return Adresse
17
    sei
18
    reti


Und das SREG solltest du während einer ISR auch sichern.

von spess53 (Gast)


Lesenswert?

Hi

>lds    tmp,     TCNT1L
>lds    tmp2,    TCNT1H

Beim Schreiben von 16-Bit-Register erst H dann L. Beim Lesen umgedreht.

MfG Spess

von spess53 (Gast)


Lesenswert?

Hi

Sollte eigentlich

>sts    OCR1AL,  tmp
>sts    OCR1AH,  tmp2

sein.

von Peter D. (peda)


Lesenswert?

To do a 16-bit write, the high byte must be written before the low byte.


Peter

von Julian R. (tuefftler)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Schwerwiegender allerdings (wenn ich mich nicht verschaut habe) ist es,
> dass die Anzahl der push/pop in der zweiten ISR nicht stimmt. Du popst
> einmal zu viel.
Du hast dich leider verschaut bzw. ich zu wenig kommentiert.
Auf "rc5_ir_over1" wird nicht von außen gesprungen, sondern nur inerhalb 
der ISR namens: "rc5_ir_CM1A:"

> Und das SREG solltest du während einer ISR auch sichern.
Ja, das sollte ich wirklich tun..., Danke für den Hinweis!

Übrigens,
diese Zeilen stehen noch im Hautpprogramm
(Das ich aus Platzgründen weggelassen habe, sowie die restlichen 7 
files):
1
.cseg
2
.org$000
3
    rjmp  Reset
4
.org$003
5
    rjmp  rc5_ir_PCINT0  ;Includefile:"WC-RC5-IR.asm"
6
.org$00B
7
    rjmp  rc5_ir_CM1A    ;Includefile:"WC-RC5-IR.asm"
8
.org$01A
9
    ;Restliches Programm beginnt hier...

von Peter D. (peda)


Lesenswert?

Der Timer läuft nach dem Compare weiter. Wenn Du also den neuen 
Comparewert zum Timer addierst, dauert es länger bis zum nächsten 
Interrupt.

Besser daher die Zeit zum alten Comparewert addieren, dann stimmt die 
Zeit zwischen 2 Interrupts genau.


Peter

von Julian R. (tuefftler)


Lesenswert?

Peter Dannegger schrieb:
> To do a 16-bit write, the high byte must be written before the low byte.
Ich hab die Zeile drüber gelesen, wo in meinem Datasheet stand:

"Not all 16-bit accesses uses the temporary register for the high byte. 
Reading the OCR1A/B 16- bit registers does not involve using the 
temporary register."

Durch verlesen glaubte ich des gilt auch für schreiben


Peter Dannegger schrieb:
>Der Timer läuft nach dem Compare weiter. Wenn Du also den neuen
>Comparewert zum Timer addierst, dauert es länger bis zum nächsten
>Interrupt.

>Besser daher die Zeit zum alten Comparewert addieren, dann stimmt die
>Zeit zwischen 2 Interrupts genau.
Kling gut, werd ich umsetzen. Aber ist das bei einem Prescaler von 64 
nicht egal?


Ich schreibs um und meld mich dann nochmal, Danke für eure Hilfe!
julian

von spess53 (Gast)


Lesenswert?

Hi

Wie wäre es mal mit einem assemblierbaren Code.

MfG Spess

von Julian R. (tuefftler)


Angehängte Dateien:

Lesenswert?

Hier nochmal der überarbeitete Code(s. Anhang)

>Wie wäre es mal mit einem assemblierbaren Code.
Ich hab eine Datei, die ich auf die schnelle gebaut hab angehängt.
Jedoch ist das Problem, dass ich das ganze auf meiner WordClock 
Variante1 zugeschnitten programmiere.

Zum Timing:
irgendwie bricht der µC die Analyse nach dem 6.Mal ab, bis auf den 
PinChange-interupt rührt sich nichts mehr!
Auserdem besteht weiterhin das Problem, das sich die allererste Sequenz 
von den folgenden im 1Timer-Interupt unterscheidet. In der 1.Sequenz 
läuft nalles so wie geplant, und ab dann wird der 1.Timerinterupt, der 
auf den Pinchange folgt, ignoriert, jedoch werden die 680µs zu den 889µs 
dazugezählt.
Eigentlich könnte ich diesen Effekt nutzen und die 1.Sequenz als 
"falsch" ansehehn.

julian

von Julian R. (tuefftler)


Angehängte Dateien:

Lesenswert?

Guten morgen,
hab mich heute gleich hingesetzt und noch etwas die FB gedrückt und 
meinen Code etwas umgeschrieben.

Ich hab geschrieben:
>Zum Timing:
>irgendwie bricht der µC die Analyse nach dem 6.Mal ab, bis auf den
>PinChange-interupt rührt sich nichts mehr!
Hab dieses Problem gelöst, der Fehler lag daran, dass ein Codeteil den 
Timercounter zurüpckgesetzt hat. Hab diesen Codeteil entfert und jetzt 
ist das Problem Geschichte!!

Bei erneute Aufzeichnungen ist mir das im Anhang gezeigte Bild ins Auge 
gefallen:
blau:680µs
grün:889µs
braun:680µs+889µs ungefähr 1,6µs
rot-vertikal:Fehler ist aufgetreten!

Erstaunlicherweise kommt mitten!! in der Sequenz dieses Bild zum 
Vorschein.
Darauf sieht man dass nach vielen Anaysen, jetzt bei einer Schlechten 
Übertragung auf einmal die gewünschten 680µs zwischen dem Pinchange und 
dem Timerinterupt sind. Ich hab leider keine Erklärung für dieses 
Phänomen.

Kompletter Code(inklusive Projektdateien des AVR-Studios) gezippt 
ebendfalls Angehängt!

julian

von Julian R. (tuefftler)


Lesenswert?

Eigentlich wollte ich den CTC-mode nicht verwenden, weil ich dann das 
zweite Comparegister vergessen kann. Da das ganze jedoch nicht so funzt 
wie es soll, find ich es eigentlich gar keine schlechte Idee mehr, CTC 
zu verwenden.

Was würdet ihr an folgendem Programmablauf verbessern:
Die Struktur meines Programms kann ich ja im groben beibehalten(?)
1.bei einem Pinchange-INT muss ich meine 680µs einstellen, und TCNT1 auf
  null setzen.
2.Beim ersten CTC-INT muss ich die Comparezeit hochstellen, TCNT1 kan 
ich
  lassen, das es sowieso null ist!?
3.Jetzt meine 27 CTC-INT abwarten und dann
4.PinChange-INT wieder freigeben

julian

von Julian R. (tuefftler)


Lesenswert?

Um euch auf dem laufendem zu halten:
CTC-mode vergess ich wieder, ich hab jetzt rausgefunden, warums nach dem 
PinChange Interupt 680µs+ 889µs waren, und das nie beim ersten 
PinCHange-INT:

Wurde einmal der TimerINT aufgerufen, und danach beendet, so ist nach 
889µs die OC1A-Flag gesetzt gewesen. Ist jetz wieder die PinChangeISR 
aufgerufen worden, wurde der TimerINT enabled und direkt nach der PC-ISR 
ist ein OC-ISR gestartet, die nochmal 889µs zum OCR1A dazugezählt hat. 
Somit waren zwischen zwei OC-ISR's 680µs(von PC-ISR eingestellt) plus 
die 889µs(von OutputCompare-ISR eingestellt) 1,5ms zwischen Zwei 
Timerinterupts, die ich auf meiner Aufzeichnung(über Soundkarte) sehen 
konnte.
Der Spuk lässt sich durch hinzufügen folgender Zeile ans Ende der PC-ISR 
beheben:
1
ldi    tmp,   0x02
2
out    TIFR1, tmp

Schaut man 1000 Mal über den Code, so entdeckt man immer etwas neues!

julian

von Julian R. (tuefftler)


Lesenswert?

GELÖST!!!
Alles arbeitet so wie es soll, wenn ich alles fertig kommentiert hab, 
stell ichs auf meine Seite und hier rein.

DANKE an EUCH, für die Tipps!
julian

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.