ATXmega: Compare Werte nach Überlauf ohne Funktion

OP #3063207
Lesenswert?

Hallo,

ich erstelle gerade ein Programm, welches ein Signal an einem Pin und 
definiert Zeitvesetzt an einem anderem Pin ausgeben soll.

Basis ist AVR Studio 6 und das XPLAINED-Board (ATXmega128A1), welches 
ich mit C programmiere.

Der Timer0 läuft mit 1MHz Takt. Den Zeitversatz möchte ich in µs 
Schritten vorgeben. Die Grundfunktion ist, dass ich den Zeitversatz / 
2^16 teile, dies ist dann die Anzahl der Überläufe des Timers die ich 
abwarten muss, um dann die Compare Werte (Rest der Division durch 2^16) 
für die Timer zu setzten und freizugeben.

Soweit so gut. Das Programm funktioniert solange richtig, bis der erste 
Compare Wert nach einem Überlauf statt finden soll. Danach werden die 
CCn Werte quasi nicht mehr beachtet.

Anbei ist das Programm und ein Bild. Das Bild zeigt, wie ich 100ms 
Zeitversatz zwischen den steigenden Flanken vorgebe: also 1 Überlauf 
abwarte und dann den Compare Wert von
ca. 35.000 für die Taktflanke nutzen möchte. Leider kommt wie ihr seht 
die Flanke schon beim Überlauf. An der Umrechnung liegt es leider nicht, 
wenn ich von Hand die Werte den Registern direkt zuweise hat das 
ebenfalls keinen Einfluss auf das Signal.

Ich hoffe jemand kann mir irgendwie helfen!

Vielen Dank im Voraus.

Gruß,
Matze
Angehängte Dateien:
#3063823
Lesenswert?

Ich sehe nur einen problematischen Punkt: Du veränderst das 
INTCTRLB-Register in der Schleife und in den Interrupts, diese Operation 
ist aber nicht elementar, so dass sich die Zuweisungen gegenseitig 
unterbrechen und garantiert nicht das gewünschte rauskommt.

Ansonsten versuche das Problem mal nur mit einem Compare-Channel zu 
reproduzieren, da findet sich die Ursache dann sicher leichter.
#3063837
Lesenswert?

Wenn Du einen Interrupt erst später im Programm enablest, solltest Du 
vorher dessen Pending-Bit löschen.

Einige AVRs haben asynchrone Timer, z.B. ATtiny261. Da muß man nach dem 
Löschen und vor dem Enable noch 3 NOPs einfügen, ehe es wirklich als 
gelöscht angekommen ist.

Achso, Löschen durch 1 reinschreiben (sollte ja bekannt sein).
OP #3067197
Lesenswert?

Hallo,

Vielen Dank schon einmal für die Antworten.
Das zurücksetzten der IR Flags mittels Oder-Maske
1
TCC0.INTFLAGS |= 0b00010000;
hat mich auf jeden Fall weiter gebracht.

Leider ist gerade am Anfang gerade im kleinen Bereich noch irgendetwas 
nicht ganz sauber. Also, wenn sich der erste Überlauf anbahnt. Später 
wenn alle Teile des Signals sich in den Überläufen zu befinden scheint 
es zu funktionieren.

Ich habe an allen erdenklichen Stellen schon _delay_us(5); einfügt 
gehabt, um asynchrone Abhandlungen abzufangen, das hatte aber leider 
keine Auswirkungen auf das Ergebnis. Das Ausführen wenigerer Compare IR 
hatte für mich kein Unterschied auf das Verhalten gemacht.

Habt ihr noch eine Idee?

Anbei nochmal das jetzige C-File.

Gruß und ein schönes Wochenende!

Matze
Angehängte Dateien:
#3068162
Lesenswert?

Das hat sich ein Scherzkeks bei Atmel eben so ausgedacht, damit jeder 
Anfänger darauf hereinfällt.

Überlege mal, was 1 OR irgendwas aus der 1 macht.
Folgende Ausdrücke machen daher exakt dasselbe:
1
  TCC0.INTFLAGS |= irgendwas;
2
// oder
3
  TCC0.INTFLAGS = 0xFF;
4
// oder
5
  TCC0.INTFLAGS = TCC0.INTFLAGS;
Sie löschen alle gesetzten Flags.

Um z.B. Flag 5 zu löschen geht nur das:
1
  TCC0.INTFLAGS = 1<<5;
2
// oder
3
  TCC0.INTFLAGS &= 1<<5;
OP #3068355
Lesenswert?

Ich mache das seit jeher mit der Oder Maske und das funktioniert ja 
auch.
1
var =  0b10101010;
2
var |= 0b11110000; 
3
//     0b11111010; //Ergebnis in var
1 mit Irgendwas verodert ergibt an der Stelle immer eine 1 und die 
möchte ich ja auch an der Stelle jeweils haben. Warum soll der Befehl 
nicht funktionieren?

Ich habe die Möglichkeiten von dir getestet und leider keine 
Unterschiede zu meinen vorherigen Befehlen festgestellt.

Gruß,
Matze
OP #3068406
Lesenswert?

Ich habs noch einmal mit nem Port ausprobiert:
1
i=  0b10101010;
2
i|= 0b11110000;
3
PORTE_OUT=i;
jetzt leuchten 2 LEDs (Pin0 und Pin2) -> 0b11111010 (LEDs hängen an VCC 
Low-aktiv).
Was soll daran jetzt falsch sein?

Außerdem habe ich es doch getestet, und es hätte dann ja einen 
Unterschied geben müssen, oder?
Persönliche Seite #3068418
Lesenswert?

Matthias Stottmeister schrieb:
> Außerdem habe ich es doch getestet, und es hätte dann ja einen
> Unterschied geben müssen, oder?

Die INTFLAG Register verhalten sich halt anders. Ein Flag wird 
zurückgesetzt, indem eine 1 reingeschrieben wird.
Wenn du jetzt das INTFLAG Register ausliest, mit einem Bit veroderst und 
zurückschreibst, werden alle gesetzten Interrupt Flags automatisch 
wieder gelöscht, weil sie eben eine 1 an der entsprechenden Position 
hatten.

Was ist denn daran so schwer?
OP #3068514
Lesenswert?

Okay, dann hat man auf jeden Fall ein definiertes Verhalten. Ich habe 
das jetzt mit deinem Code gemacht. Das ist auf jeden Fall gut zu wissen 
und eine verdammt verflixte Sache. Da muss man erst einmal drauf kommen. 
Danke!

Betrifft dieses Verhalten nur die Flagregister, oder auch die 
Kontrollregister wie z.B. INTCTRLB?
Gast #3069075
Lesenswert?

Matthias,

das Problem wurde Dir hier bereits gelöst:

Peter Dannegger schrieb:
> Wenn Du einen Interrupt erst später im Programm enablest, solltest Du
> vorher dessen Pending-Bit löschen.

Das Verhalten das Du feststellst, ist ganz normal, denn Interrupt-Flags 
werden im AVR bereits dann gesetzt, wenn die betreffende Bedingung 
eingetreten ist, unabhängig davon ob der betreffende Interrupt erlaubt 
ist oder nicht.

Das passiert bei den Compare-Ints das erste Mal innerhalb des Bereichs 
bis zum ersten Timerüberlauf. Das betreffende Compare-Flag ist also dann 
bereits gesetzt. Sobald nun der entsprechende Compare-Int freigegeben 
wird, löst dieser sofort aus und wird dann in Folge gesperrt. Damit hat 
die Höhe des Comparewertes keinerlei Wirkung.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren