Hallo!
Ich suche eine Möglichkeit, um mit dem ATmega328 einen Manchester Code
mit exaktem Timing zu erzeugen.
Bisher habe ich dazu Timer 1 verwendet und bei einem Überlauf das
entsprechende Muster am Ausgang erzeugt.
Nachdem der Code aber immer komplexer wurde und viele Interrupt Routinen
mehr Zeit benötigen, treten vereinzelt Phasen mit zu langer Bitdauer
auf.
Ich habe es bereits mit der Compare Match Output Unit versucht, aber das
Register ist nicht gebuffert und ich kann die Flanke nicht zum Zeitpunkt
des Compare Events umstellen.
Gibt es eine andere Möglichkeit, einen exakten Code mittels Timer zu
erzeugen?
Vielen Dank,
Andreas
Welche Frequenz, wie genau, wie lang, was muss der AVR nebenbei noch
machen?
z.B. : Schnell, auf den Takt genau, aber keine Zeit für was anderes:
Abgezählte ASM-Instruktionen bei abgeschalteten Interrupts...
Auch schnell & genau, aber wohl zu kurz: Das USI-Schieberegister
missbrauchen.
Hallo,
der Timer Interrupt kommt alle 417us, das Ausgangssignal darf max. 10%,
d.h. 40us abweichen. Im Normalfall ist das auch kein Problem, aber
manchmal kommt der Timer Interrupt viel zu spät dran.
Der Controller soll nebenbei noch die serielle Schnittstelle mit
115kBit/s bedinen und einige andere Dinge per Interrupt verwalten, daher
kann ich die Interrupts nicht sperren.
Ich hätte gehofft, ich könnte es mit der internen Hardware lösen, aber
das scheint nicht zu funktionieren.
Der Mega328 besitzt leider kein USI, und die Länge würde nicht
ausreichen.
Gruß,
Andreas
Andreas schrieb:> ich kann die Flanke nicht zum Zeitpunkt> des Compare Events umstellen.
Es reicht, wenn Du die Flanke irgendwann vor dem nächsten Compare
umstellst.
Conny G. schrieb:> Ist denn sonst nur in Interrupt Routinen, was da unbedingt sein muss?
Die sind leider mit fortlaufender Projektdauer etwas angewachsen.
Vermutlich läufts auf eine Optimierung dieser hinaus...
Peter Dannegger schrieb:> Es reicht, wenn Du die Flanke irgendwann vor dem nächsten Compare> umstellst.
Leider nicht, das schlägt sofort auf den Ausgang durch. Steht auch im
Datenblatt in Kapitel 16.7.3.
Andreas schrieb:> Conny G. schrieb:>> Ist denn sonst nur in Interrupt Routinen, was da unbedingt sein muss?>> Die sind leider mit fortlaufender Projektdauer etwas angewachsen.> Vermutlich läufts auf eine Optimierung dieser hinaus...
Genau das meine ich, dass evtl. das der bessere Weg ist.
Im Grunde sollte man immer so wenig wie möglich an Takten in den ISRs
haben, sonst es nicht mehr überschaubar wieviel für die einzelnen
eigentlich bleiben und es kommt zu zunehmenden Konflikten.
Oder die Generierung des Manchester auf den kleinsten Attiny auslagern
und dem per SPI oder einem Protokoll ähnlich der Shift Register das
Ganze rüberschieben. :-)
Andreas schrieb:> der Timer Interrupt kommt alle 417us, das Ausgangssignal darf max. 10%,> d.h. 40us abweichen.
Mit dem Compare Output hast Du entweder 0µs oder 417µs Abweichung (oder
834µs usw.), 40µs geht nicht.
Du mußt mindestens alle 417µs den Interrupt behandeln können. Bei
18,432Mhz sind das 7686 Zyklen Zeit. Darfst halt in den anderen
Interrupts nicht soviel float rechnen.
Conny G. schrieb:> Oder die Generierung des Manchester auf den kleinsten Attiny auslagern
Nur mal eine Anregung: Normalerweise reicht doch ein XOR-Gatter, warum
dann zur "Auslagerung" einen Prozessor verwenden?
Wie oft muss denn der Code gesendet werden?
Eventuell ließe sich Dein Programm umstricken
loop
manchesterflanke ( state machine dependend )
timer reload
read/write serial interface ( state machine dependend )
end loop
Das Timing dürfte damit wesentlich besser als Deine geforderten 40us
Genauigkeit werden.
ich schrieb:> Conny G. schrieb:>> Oder die Generierung des Manchester auf den kleinsten Attiny auslagern>> Nur mal eine Anregung: Normalerweise reicht doch ein XOR-Gatter, warum> dann zur "Auslagerung" einen Prozessor verwenden?
Das XOR-Gatter muss man ja auch mit einem Takt ansteuern und dem TO geht
es genau darum, dass er vor lauter anderer Interrupts diesen Takt nicht
mehr genau einhalten kann.
Eine Variante ist die anderen ISRs etwas reduzieren im Takte-Bedarf, die
andere: er schiebt die Bytes raus an einen Attiny und der hat dann alle
Zeit der Welt für sein Timing.
chris_ schrieb:> Wie oft muss denn der Code gesendet werden?>> Eventuell ließe sich Dein Programm umstricken>> loop> manchesterflanke ( state machine dependend )> timer reload> read/write serial interface ( state machine dependend )> end loop>> Das Timing dürfte damit wesentlich besser als Deine geforderten 40us> Genauigkeit werden.
Das ist eine Variante von dem was ich sagte: ISRs entschlacken und mehr
Arbeit in der Hauptloop verrichten.
Conny G. schrieb:> Das XOR-Gatter muss man ja auch mit einem Takt ansteuern und dem TO geht> es genau darum, dass er vor lauter anderer Interrupts diesen Takt nicht> mehr genau einhalten kann.
Stimmt auch wieder. Das hatte ich nicht bedacht. Asche auf mein Haupt
:-)
Conny G. schrieb:> Das XOR-Gatter muss man ja auch mit einem Takt ansteuern und dem TO geht> es genau darum, dass er vor lauter anderer Interrupts diesen Takt nicht> mehr genau einhalten kann.> Eine Variante ist die anderen ISRs etwas reduzieren im Takte-Bedarf, die> andere: er schiebt die Bytes raus an einen Attiny und der hat dann alle> Zeit der Welt für sein Timing.
der XmegaE hat die tolle Funktion dass man das XCL Modul zu einem XOR
konfigurieren kann, dieses dann mit dem USART verbindet und schwups gibt
es einen HW manchester encoder/decoder - und das mit minimalem CPU
aufwand.
schau mal app note:
http://www.atmel.com/Images/Atmel-42164-AT03335-Manchester-Transceiver-using-the-USART-and-XCL-Modules-on-XMEGA-E_Application-Note.pdf
vielleicht macht es sinn hier weiterzumachen
Andreas schrieb:> Der Mega328 besitzt leider kein USI
Aber mindestens eine USART, die fähig ist, im SPI-Mode zu arbeiten.
Damit kann man natürlich auch Manchestercode 100%ig exakt ausgeben.
> und die Länge würde nicht> ausreichen.
Es gibt keine Längenbegrenzung. Du mußt es nur schaffen, ungefähr alle
8 Brutto-Bit (im Falle von Manchester also alle vier Netto-Bit) ein Byte
in's UDR-Register schreiben.
Das sollte bei den bescheidenen Bitraten, um die es hier wohl geht,
selbst in einem völlig vergurkten C-Programm irgendwie realisierbar
sein.
Andreas schrieb:> Peter Dannegger schrieb:>> Es reicht, wenn Du die Flanke irgendwann vor dem nächsten Compare>> umstellst.>> Leider nicht, das schlägt sofort auf den Ausgang durch. Steht auch im> Datenblatt in Kapitel 16.7.3.
Doch, Peter Dannegger hat Recht. Wahrscheinlich hast Du den letzten
Absatz des Kapitels falsch verstanden.
Eine Änderung von COM1x ändert nicht sofort den Ausgang, sondern wirkt
sich auf den nächsten Compare Match aus. "double buffered together with
the compare value." würde bedeuten, daß die neuen COM1x-Werte erst nach
dem nächsten Compare Match übernommen werden.
Danke für die zahlreichen Hinweise!
Ich werde es nochmal mit der Compare Match Output Unit versuchen und
zusätzlich die Interrupt Funktionen optimieren (obwohl sie nicht
besonders groß sind und auch keine Floats beinhalten ;-)
Grüße,
Andreas
Andreas schrieb:> besonders groß sind und auch keine Floats beinhalten ;-)
Aber selbst C-Standard-String-Funktionen oder bestimmte Integer
Multiplikationen/Divisionen können ziemlich viel Zeit verbrauchen.
Es gibt für manche Dinge wie z.B. Zahl-nach-String-Umwandlung spezielle
µC-optimierte Implementationen, die nicht alles können, dafür aber ein
Vielfaches schneller sind.