Habe einem mit 14,7456 Mhz (Baudratenquarz) getakteten ATMega8 auf Bus D ein R2R Netzwerk verpasst und möchte damit einen abstimmbaren Oszillator für Klangerzeugung programmieren. Zur Veranschaulichung wird eine Sinuskurve in einer indizierten Variablen abgespeichert und dann in der IRQ-Routine abgerufen. Mich verwundert, dass Bascom anscheinend doch wesentlich mehr Takte benötigt als für eine Klangerzeugung vom IRQ vorgegeben. So würde ich gern eine Hüllkurve mit reinprogrammieren oder bspw. einen Ringmodulator. Aber da kommt immer der nächste IRQ während der vorige noch abgearbeitet wird. Brauche ein paar Tipps. Unten der Bascom Quellcode. Meine Fragen: (1) grundsätzlich: Habe ich DDS richtig verstanden ? (2) Gibt es eine Methode ganzzahlig, im Rahmen von 8 Bit zu multiplizieren (für die Lautstärkenkontrolle und für DDS) ? Wenn ich bspw. in der IRQ Routine schreibe "IF Versatz > 255 then ..." dann reichen die 8 * 256 Takte bereits nicht mehr aus, auf die Timer0 eingestellt ist ! ~~~~~~~~~~~~~ $regfile = "m8def.dat" $crystal = 14745600 $hwstack = 32 ' default use 32 for the hardware stack $swstack = 10 ' default use 10 for the SW stack $framesize = 40 ' default use 40 for the frame space Config Timer0 = Timer , Prescale = 8 On Timer0 Tmr0 Config Portd = Output Dim A As Byte , B As Byte , Sinus(256) As Byte Dim C As Single , Laut As Single , Amplitude As Single , Freq As Byte , Versatz As Single B = 0 For A = 0 To 255 C = A * 360 C = C / 256 C = Deg2rad(c) C = Sin(c) C = C * 128 C = C + 128 Sinus(b) = Int(c) B = B + 1 Next Enable Timer0 Enable Interrupts Do Laut = 1 For Freq = 1 To 255 Waitms 5 Next For Freq = 255 To 1 Step -1 Waitms 5 Next Loop Tmr0: C = Freq \ 100 C = C + 1 Versatz = Versatz + C A = Int(versatz) If A > 255 Then Versatz = 0 Portd = Sinus(a) Return ~~~~~~~~~~ Danke und Gruß
Der BAscom Compiler ist nicht gerade der Schnellste. Bei ISRs kommt da noch ein relativ langer Teil zum retten und wiederherstellend er Register dazu. Es könnte nötig sein die ISR als ganzes als inline ASM zu schreiben. Immerhin geht das relativ einfach. Wenn man mutig ist, und in Kauf nimmt, dass das Programm eventuell nicht mehr so mit neuere Compilerversionen läuft, könnte man sogar ausnutzen das der Compiler einige Register gar nicht nutzt. Unabhäng davon sollte die ISR nicht mit Fließkomma arbeiten, und auch keine Division enthalten. Das allein kann die ISR schon über 10 mal schneller machen. Und auch so ist die ISR auch noch logisch falsch, beim Überlauf fängt man nicht wieder genau bei 0 an.
Ulrich schrieb: > Und auch so ist die ISR auch noch logisch falsch, beim Überlauf fängt > man nicht wieder genau bei 0 an. Danke Dir. Stimmt, bei Freq > 100 wird Sinus(0) nicht mehr aufgerufen. Komischerweise sieht es auf dem Oszi noch recht sauber aus. Man kann in Bascom bei den IRQ "nosave" angeben, dann werden die Register nicht auf den Stack geschoben. Als ich es probiert habe, ist nur Müll rausgekommen. Komischerweise hatte ich auch Müll, wenn ich die DDS-Division aus der IRQ Routine rausgenommen habe. Problematisch wird es bei der Hüllkurveneinstellung. Da sehe ich keine Möglichkeit, die Division aus der IRQ Routine zu entfernen. Daher nochmal meine Frage, wie man eine Division (oder Multiplikation mit dem Kehrwert) auf ganzzahlige Werte im 8-Bit-Raum beschränken kann ?
Die Option NOSAVE bei der SIR ist nur brauchbar, wenn man die ISR in inline ASM schreibt, und da die wrklich benötigsten Register von Hand rettet. Ohne geht es nicht (bis auf extreme Ausnahmen). So wie die ISR oben ist, könnte man die Division ganz einfach nach außen ziehen und eine Freq/100 als extra Variable speichern. Für eine DDS Funktion sollte die Variable für die Phase (versatz) vom Typ Word (oder ggf. dem 32 Bit equivalent) sein. Die addition dann auch mit einen Word Typen für die Frequenz, wobei der Wert ausherlalb der ISR berechent wird. Für die Sinustabelle wird dann nur das High-byte der Phase benutzt. Für das High byte kann man bei der Deklaration eine extra Varabel an der gleichen Postion wie die Phase extra definieren. Also C und versatz als WORD. und die ISR etwa so: versatz = verstatz + c A = versatz / 256 ( hier besser spez. Varablenzugriff) portd = sinus (A)
Für die Nutzung eines Kontrollers als DDS-IC muss die Grundoperation (Addierschleife) ohne Eingriff durch interupts ablaufen.Also als inline-ASM-Routine. Der Kontroller sollte NUR die DDS-Schleife arbeiten. Dann läuft diese Schleife mit etwa 6 bis 8 Takten ab und man kommt mit 14,..MHz bis etwa 50 kHz auf eine einigermaßen gute Kurvenform, kann also den NF-Bereich überdecken. Zusätzliche Operationen, wie Multiplikation wegen der Amplitude, sollte man nicht machen. Nicht nur,dass dann die DDS-Schleife verlangsamt wird und man nur maximal einige kHz erzeugen kann, auch die Auflösung von 256 Schritten vertikal wird zerstört. Die Steuerung, wie Eingabe der Sollfrequenz, Berechnung der Steuerzahl usw. sollte von einem zweiten Kontroller ausgeführt werden, der nach Änderungen die fertig berechnete Additionszahl an das "DDS-IC" übergibt, z.B über eine serielle Schnittstelle. google mal "poor man's DDS-synthesizer".
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.