Forum: Mikrocontroller und Digitale Elektronik Wer kann mir das Prinzip des Codes erklären?


von Florian (Gast)


Lesenswert?

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.

von Carbolo C. (carbolo)


Lesenswert?

:-)

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

von Falk B. (falk)


Lesenswert?

@  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

von Johannes S. (johanness)


Lesenswert?

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]

von Michael W. (wiebel42)


Lesenswert?

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

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Siehe auch den Artikel Digitaler Funktionsgenerator.

von Florian (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.