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
Matthias Stottmeister schrieb: > Das zurücksetzten der IR Flags mittels Oder-Maske Das setzt alle Flags zurück. Du mußt die 1 direkt reinschreiben.
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:
1 | TCC0.INTFLAGS = 1<<5; |
2 | // oder
|
3 | TCC0.INTFLAGS &= 1<<5; |
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...
Malte S. schrieb: > aber GCC übersetzt |= ziemlich sicher in ein > sbi Bei 'nem XMega und TCC0.Intflags auf Adresse 2060? Nicht wirklich...
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 ;)
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?
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.
Ich habe die unterschiedlichen Befehle für CCA bis CCD getestet : TCC0.INTFLAGS |= 0b10000000; TCC0.INTFLAGS &= 1<<7; es macht keinen Unterschied!
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.