Hallo Ich habe Jespers MiniDDS gefunden http://www.myplace.nu/avr/minidds/index.htm Die Idee finde ich ganz interessant. Allerdings verstehe ich nur C und kein Assembler und schon gar nicht das Registergetrickse. Kann mir jemand das Prinzip seines Codes erklären? So weit ich verstehe, gibt er einen Analogwert gemäß der Datentabelle aus. Aber wie werden die Taktschritte berechnet? Bzw. wann welches Datum dran ist.
:-) Ein guter C Programmierer ist meist auch in Assembler fit... mal so am Rande. Die Lösung werde ich dir nicht komplett verraten, wäre ja witzlos. Aber soviel: (Funzt in C analog dazu) - Definiere einen Vektor mit Werten (Tabelle, x Array) - Setze einen Pointer auf den Vektor, und lasse es wandern. - Wandergeschwindigkeit des Pointers = Frequenz - Die Taktschritte ergeben sich zwingend aus dem Quarz, das "Registergetrickse" ist im Gegensatz zu C genau voraussagbar... Gruss
@ Florian (Gast) >kein Assembler und schon gar nicht das Registergetrickse. Kann mir >jemand das Prinzip seines Codes erklären? So weit ich verstehe, gibt er Kennst du das Prinzip von DDS? http://www.analog.com/en/subCat/0,2879,770%255F843%255F0%255F%255F0%255F,00.html DDS ist im Prinzip nur eine Tabelle, die ausgegeben wird. Normalerweise ist in der Tabelle ein Sinus kodiert, aber auch andere Formen sind machbar. Im MiniDDS gibts Sinus, Dreieck und Rechteck. Adressiert wird diese Tabelle über den Z-Pointer. Der Trick ist dabei, dass der eigentliche DDS-Akkumulator über den Z-Pointer gelegt wird. Dadurch spart man das umkopieren und das Ganze ist ziemlich schnell. Vom 24 Bit DDS-Akku in R28,29 und r30 werden nur die oberen 8 Bit zur Adressierung der Tabelle mit je 256 Einträgen genutzt. Der Trick ist, dass diese obere Byte gleichzeitig das niederwertige Byte vom Z-Pointer ist. Das klappt aber nur durch die Ausrichtung der Tabellen auf einer 256 Byte Adresse. Das macht .org 0x100 >einen Analogwert gemäß der Datentabelle aus. Aber wie werden die >Taktschritte berechnet? Bzw. wann welches Datum dran ist. In jeder Schleife. Ist einfach nur ein Akku, zu dem ein bestimmter Wert immer wieder hinzuaddiert wird. Hier eben in 24 Bit. MfG Falk
Genau, ein R2R-Netzwerk setzt den aus der Tabelle ausgelesenen Wert in eine Spannung um. Die ist also proportional zum Wert in der Tabelle. Wie er herausfindet, welche Zelle er nehmen soll: Er zählt eine 24-bit-Variable hoch (addiert immer einen festen Wert drauf, je höher desto höher die Frequenz) und nimmt das höchstwertige Byte ("zufällig" r30), um die Tabellenposition zu bestimmen. Recht effizient denke ich. Über r31 wird die Tabelle ausgewählt, r30 ist die Position in der Tabelle. [Edit] argl Da freut man sich mal, dass man selbst was verstanden hat, und dann waren andere schneller![/Edit]
Also bei der Initialisierung sezt du das Z Register (R30,R31) auf die (16bit) Addresse deiner Tabelle, da die Tabelle "nur" 256 Daten hat kannst du R31 somit auch schon wieder Vergessen das würde aber bei einer Inkrementierung von R30 auch automatisch nachgeführt werden. Die Eigentlich Magie findet hier statt:
1 | LOOP1: |
2 | add r28,r24 ; 1 |
3 | adc r29,r25 ; 1 |
4 | adc r30,r26 ; 1 |
5 | lpm ; 3 |
6 | out PORTB,r0 ; 1 |
7 | rjmp LOOP1 ; 2 => 9 cycles |
Hier wird der 24bit Inkrementierungswert (Proportional zur Frequenz) der in R24,R25,R26 gespeichert ist auf den Zeiger im Phasenraum (R28,R29,R30) aufaddiert, das ist erstmal einfach eine Zahl die immer grösser wird, umso schneller je grösser unsere Frequenz/Inkrement. Somit zählt er bis zum Überlauf und fängt dann wieder bei 0 an. Die MSBs dieses Zeigers im Phasenraum sind, oh wie praktisch, auch gleichzeitig unser Z Register, d.h. Z zeigt an die entsprechende Stelle unserer Tabelle und legt diesen Wert nach einem LPM, freundlich für uns in R0 (und R1 für 16bit Werte) ab, wo wir es dann sogleich verwenden könnne. Daher muss bei dieser Implementierung auch eine volle Periode in der .db sein. Wenn man jetzt z.B. immer nur mit 1 inkrementiert, würde man 65535 mal den ersten Wert der Tabelle erhalten dann 65536 man den 2ten usw. bei einem Inkrementierungswert > 65535, erhält man nicht einmal mehr jeden Wert der Tabelle sondern eben nur noch einen Bruchteil, was aber natürlich Sinn ergibt, da wir dann eine Frequenz erreicht haben die wir gar nicht mehr mit 256 Samplen abarbeiten könnten. Am Ende kann man die Frequenz fein in 24bit Auflösung einstellen, von dem ersten Beispiel in dem man 256*65535 Takte braucht um die Tabelle auch nur ein einziges mal auszulessen bis hin zu 1Takt pro Tabelle auslesen (was natürlich nicht mehr sinnvoll ist, da es ja dann ein DC wäre). -wiebel
Danke für Beantwortung der Frage, auch wenn mal wieder einige nicht lesen wollten und mir DDS erklären, auch wenn ich sagte, daß ich das verstanden habe... :-) Jetzt verstehe ich die Registerschieberei.
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.