Forum: Mikrocontroller und Digitale Elektronik Verständnisfrage zu AVR ASM-Code


von Harri (Gast)


Lesenswert?

Hallo zusammen,

ich hab mal eine Frage zu einem Assembler-Code für den ATtiny2313. Und
zwar geht es um die Firmware für diesen AVR-basierten Signalgenerator:
http://www.myplace.nu/avr/minidds/index.htm
Firmware: http://www.myplace.nu/avr/minidds/minidds.asm

Verstanden habe ich folgendes:
Ab 0x100 steht eine 256 Byte lange vorberechnete Tabelle mit den
Ausgabecodes für ein Sinusignal. Weiter hinten kommen die Tabellen für
Dreieck, Rechteck usw.
Bleiben wir beim Sinus. Diverse Register werden initialisiert, die
Serielle Schnittstelle aktiviert und dann läuft irgendwann diese
Mainloop und gibt die Daten aus:

LOOP1:
 add  r28,r24     ; 1
 adc  r29,r25     ; 1
 adc  r30,r26     ; 1
 lpm              ; 3
 out  PORTB,r0    ; 1
 rjmp  LOOP1      ; 2 => 9 Taktzyklen

Der Befehl lpm lädt die über r30/r31 adressierten Daten aus dem Speicher 
in r0, danach wird r0 auf dem Port ausgegeben. R30 wird durch den lpm um 
eins erhöht, also wird beim nächsten Durchlauf das nächste Byte der 
Tabelle gelesen.
So lange r26=0x00 ist wird die Tabelle komplett ausgegeben, was bei 
einem CPU-Takt von 20MHz eine Ausgabefrequenz des Sinussignals von 20MHz 
: 9 : 256 = 8680Hz geben müsste. Wenn in r26 eine 0x01 steht, dann wird 
nur jeder zweite Wert der Tabelle ausgegeben und wir erhalten die 
doppelte Ausgabefrequenz. Höhere Frequenzen werden also durch eine 
unvollständige Ausgabe der Sinustabelle erreicht, es gibt keine 
zeitbestimmenden Befehle in der Loop.

Ich verstehe jetzt nicht wie der Inhalt von r24 und r25 auf die Ausgabe 
wirkt. Laut Beschreibung soll man die Ausgangsfrequenz ja in sehr 
kleinen Schritten um ca. 1Hz einstellen können.

Was genau machen die ersten beiden Befehle der Loop? Wie werden 
Frequenzen unter 8kHz erzeugt und wie entstehen die Frequenzen 
dazwischen?

mfg
Harri

von Michael U. (amiga)


Lesenswert?

Hallo,

Harri schrieb:
> Bleiben wir beim Sinus. Diverse Register werden initialisiert, die
> Serielle Schnittstelle aktiviert und dann läuft irgendwann diese
> Mainloop und gibt die Daten aus:
>
> LOOP1:
>  add  r28,r24     ; 1
>  adc  r29,r25     ; 1
>  adc  r30,r26     ; 1
>  lpm              ; 3
>  out  PORTB,r0    ; 1
>  rjmp  LOOP1      ; 2 => 9 Taktzyklen
>
> Der Befehl lpm lädt die über r30/r31 adressierten Daten aus dem Speicher
> in r0, danach wird r0 auf dem Port ausgegeben. R30 wird durch den lpm um
> eins erhöht, also wird beim nächsten Durchlauf das nächste Byte der
> Tabelle gelesen.

lpm erhöht Z nicht.

> So lange r26=0x00 ist wird die Tabelle komplett ausgegeben, was bei
> einem CPU-Takt von 20MHz eine Ausgabefrequenz des Sinussignals von 20MHz
> : 9 : 256 = 8680Hz geben müsste. Wenn in r26 eine 0x01 steht, dann wird
> nur jeder zweite Wert der Tabelle ausgegeben und wir erhalten die
> doppelte Ausgabefrequenz. Höhere Frequenzen werden also durch eine
> unvollständige Ausgabe der Sinustabelle erreicht, es gibt keine
> zeitbestimmenden Befehle in der Loop.
>
> Ich verstehe jetzt nicht wie der Inhalt von r24 und r25 auf die Ausgabe
> wirkt. Laut Beschreibung soll man die Ausgangsfrequenz ja in sehr
> kleinen Schritten um ca. 1Hz einstellen können.

Naja, offenbar enthält ja r28-30 einen 24Bit Wert, der den Low-Teil der 
Adresse für LPM bestimmt. Dazu wird dann ein 24Bit Offset in r24 - r26 
befindet.
Genutzt wird nur das Ergebnis in r30 als Low-Byte der Adresse, der 
H-Teil in r31 wird zumindest hier ja nicht gesetzt.
Wenn r26 > 0 ist und ein Übertrag der Rechnung aus r24/r25 stattfindet, 
wird dann natürlich 2 addiert.

Das Problem ist also dann schon vorher der Wertebereich von r24-r26, der 
ist offenbar zu groß.

Gruß aus Berlin
Michael

von Karl H. (kbuchegg)


Lesenswert?

Harri schrieb:

> Ich verstehe jetzt nicht wie der Inhalt von r24 und r25 auf die Ausgabe
> wirkt.

Das realisiert offenbar so etwas wie 'Kommastellen'


Wenn du in eine Tabelle indizierst und den Index nur in Einerschritten 
erhöhen kannst, dann kannst du natürlich nicht sehr fein abstufen.

Nimmst du aber künstlich noch 2 'Nachkommastellen' dazu, dann kannst du 
den Inkrement viel feiner erhöhen. Du kannst zwar immer noch nur auf die 
in der Tabelle vorhandenen Werte zugreifen, aber die Indexsteuerung wird 
feiner. Genau das was du brauchst, damit zumindest die Länge einer 
Einzelschwingung stimmt auch wenn die Form der Kurve nicht ganz exakt 
ist.

Stell es dir so vor:
Deine Tabelle hat 100 Einträge.
Anstatt einem Index der von 0 bis 99 zählen kann, machst du einen Index 
der Werte von 0 bis 9900 annehmen kann, wobei du nur den Teil der 
Hunderter aufwärts als Index in deine Tabelle nimmst. Steh dein Indedx 
beispielsweise auf 5623, dann holst du damit aus der Tabelle den Wert an 
Position 56. Aber: Du kannst den Index in 'Hunderstelschritten' erhöhen

von Harri (Gast)


Lesenswert?

Alles klar. Das mit dem 24 Bit Wert und den Kommastellen hab ich 
verstanden. Passt auch zum Rest des Quellcodes.

Mann also die gewünschte Frequenz mit einer 24 Bit Genauigkeit und 1Hz 
Schritten einstellen aber in Wirklichkeit können wohl nur Frequenzen in 
ca. 8kHz Schritten erzeugt werden, weil die niedrigeren Bits gar nicht 
für den Index genutzt werden.

Am besten steck ich es mal zusammen und mess nach :-)

mfg
Harri

von Karl H. (kbuchegg)


Lesenswert?

Harri schrieb:

> Mann also die gewünschte Frequenz mit einer 24 Bit Genauigkeit und 1Hz
> Schritten einstellen aber in Wirklichkeit können wohl nur Frequenzen in
> ca. 8kHz Schritten erzeugt werden, weil die niedrigeren Bits gar nicht
> für den Index genutzt werden.

Die Frequenz kannst du schon einigermassen genau einstellen. Alles was 
du brauchst ist ein Incrementwert, der ein paar Nachkommastellen 
aufweist. Und natürlich auch ein Index, der mit diesen Nachkommastellen 
incrementiert werden kann.

Aber die Kurvenform wird dann kein 'Sinus' mehr sein, sondern etwas 
Sinusähnliches, welches aber gut genug ist

Annahme, wieder die 100 Werte in der Tabelle.
Ein Index mit 2 künstlichen Nachkommastellen (d.h. der eigentliche Index 
beginnt an der Hunderterstelle). Aus der Frequenzberechnung hast du 
erhalten, dass du bei 100 Tabellenwerten du den Index um jeweils 0.6 
erhöhren musst, damit die 100 Werte bei bekannter Schleifenzeit in dem 
Tempo ausgegeben werden, damit sich die gewünschte Frequenz einstellt

Also läuft die Schleife

Index    Increment    neuer Index      Index in die Tabelle
  0         60             60                 0
 60         60            120                 1
120         60            180                 1
180         60            240                 2
240         60            300                 3
300         60            360                 3
360         60            420                 4
420         60            480                 4
480         60            540                 5
540         60            600                 6
.....

Siehst du, wie sich das Zugriffsmuster in die Tabelle an die '0.6 
anpasst. Manchmal werden Indizes doppelt generiert, manchmal nicht. Je 
nachdem wie sich das mit den 'Nachkommastellen' ausgeht.

Bei einer anderen Frequenz hast du eventuell errechnet, dass du den 
Index mit dem Wert 8.76 erhöhen müsstest, damit sich das Timing für die 
gewünschte Frequenz wieder ausgeht. In deiner 'Fixed Point Welt' (denn 
genau darum handelt es sich letzten Endes: Fixed Point Arithmetik) sind 
die 8.76  876 und du hast

Index    Increment    neuer Index      Index in die Tabelle
   0       876           876                 8
 876       876          1752                17
1752       876          2628                26
1628       876          3504                35
3504       876          4380                43
....

von Harri (Gast)


Lesenswert?

Danke für das tabellarische Beispiel.
Jetzt ist der Groschen (so eine Art früher Cent) wirklich gefallen ;-)

von Karl H. (kbuchegg)


Lesenswert?

Harri schrieb:
> Danke für das tabellarische Beispiel.
> Jetzt ist der Groschen (so eine Art früher Cent

Du meinst: Den kleinsten Wert eines 'Fixed Point Arithmetik' - Euro mit 
2 künstlichen Nachkommastellen :-)

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.