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
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
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
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
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 ....
Danke für das tabellarische Beispiel. Jetzt ist der Groschen (so eine Art früher Cent) wirklich gefallen ;-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.