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
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.
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).
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
Peter Dannegger schrieb:> Das setzt alle Flags zurück.> Du mußt die 1 direkt reinschreiben.
Aber das ist doch eine Oder-Maske, welche das Bit setzt, falls es noch
nicht gesetzt ist.
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:
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
Matthias Stottmeister schrieb:> Warum soll der Befehl> nicht funktionieren?
Weil mit jedem gesetztem Flag per "Oder" eine 1 auf sich selbst
geschrieben und damit alles gelöscht wird, was vorher gesetzt war. Also
nicht nur das, was in der Oder-Maske 1 ist.
Kann's grad nicht testen aber GCC übersetzt |= ziemlich sicher in ein
sbi und damit stellt sich der gewünschte Effekt ein. Bis du auf die Idee
kommst, mehrere Flags auf einmal löschen zu wollen. Also besser nicht
blind drauf verlassen...
Ja, sorry habe auch nach dem Posten gesehen, dass ich mich in der
Familie geirrt habe. Der Threadtitel war auf dem Handy nicht so
aufdringlich zu sehen ;)
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?
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?
Matthias Stottmeister schrieb:> Ich habs noch einmal mit nem Port ausprobiert:
Ein Port ist kein Flag-Register.
Beschäftige Dich mal mit den Grundlagen.
Matthias Stottmeister schrieb:> es macht keinen Unterschied!
Das bedeutet nur, daß die anderen Flags zu diesem Zeitpunkt entweder
nicht gesetzt sind oder egal sind.
Ich habe nie behauptet, daß das eine Rolle spielt, sondern nur, daß
dieser Code alle Flags des Registers löscht.
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?
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.