Forum: Mikrocontroller und Digitale Elektronik wieder einmal dds


von technikus (Gast)


Lesenswert?

Hallo,

ich möchte einen Signal mit dem dds Verfahren auf meinem ATmega32 
ausgeben.

Jetzt habe ich hier im Forum folgende Formel zur Bestimmung des 
Additionswertes (Tabellenzähler):
1
Additionswert = Ausgabefrequenz * Auflösung Tabellenzähler * Nachladewert_Timer / F_CPU

Nutze ich einen 16Bit Tabellenzähler
1
 //Timer ISR
2
Tabellenzaehler+=Additionswert;
3
//Auf Tabellenlänge 2048
4
OFFSET= STEP / 32;
5
OCR1BL=pgm_read_byte(&signal[OFFSET]);

funktioniert alles einwandfrei. Ich bekomme das Signal mit relativ 
genauer Frequenz ausgegeben.

Nun möchte ich aber einen 32Bit Tabellenzähler nutzen um die Auflösung 
der Wunschfrequenz zu erhöhen.

Wenn ich die oben angegebene Formel benutze und folgendes Rechne:
1
 (50 * 0xFFFFFFFF * 256)/16000000UL)

komme ich auf einen Wert (Taschenrechner) von: 3435974

Soweit so gut

Tabellenzähler deklariere ich jetzt als uint32_t und den Additionswert 
habe ich zum Test als Konstante mit dem Ausgerechneten Additionswert 
festgelegt.

Die ISR sieht so aus:
1
 //Timer ISR
2
Tabellenzaehler+=3435974;
3
//von 32 Bit auf Tabellenlänge 2048 
4
OFFSET= (uint16_t)(Tabellenzaehler / 2097152UL); 
5
OCR1BL=pgm_read_byte(&signal[OFFSET]);

Leider stimmt die Frequenz des Ausgegebenen Signals nicht mehr.


Jetzt habe ich den Additionswert mit zwei Tastern (Additionswert+=10 
bzw. Additionswert-=10) einstellbar gemacht und den Additionswert bei 
50Hz mit JTAG Debugger ermittelt. Der Wert liegt bei ~50Hz bei 4026386.
Eingesetzt in die ISR komme ich lässt sich das Ergebnis bestätigen.


Leute, kann mir jemand erklären wo mein (Denk)Fehler liegt ?
Bitte keine Diskussionen um das Konzept (Tabellenlänge, 32Bit 
Tabellenzähler, etc.).



Danke
technikus

von Benedikt K. (benedikt)


Lesenswert?

Es liegt eventuell daran, dass aufgrund der 32bit Division die 
Interruptfrequenz runter geht, da der AVR zu langsam ist.

von technikus (Gast)


Lesenswert?

Hallo,

ich sehe gerade das durch das ganze Probieren mein Sprachzentrum gestört 
wird ;-)
Da der Controller recht "lahm" geworden ist, habe ich mir mal das AVR 
Studio .lss File  angeschaut.
In der ISR zähle ich 67 Assembler Befehle. Ich habe zwar wenig Ahnung 
von Assembler, da im Programm aber sonst nichts passiert, denke ich das 
hier jede ISR sauber durchgearbeitet wird und dann noch einige Takte 
zwischendurch "übrig" sind.

Trotzdem DANKE für deinen Ansatz!


LG
technikus

von Benedikt K. (benedikt)


Lesenswert?

Einer der Assembler Befehle dürfte ein rcall sein. Dahinter steht dann 
vermutlich irgendwas mit udivmod4 oder so was in der Richtung. Die 
Division dauert aus meiner Erfahrung irgendwas um die 50-100µs.
Bei 32bit benutzt der Compiler nämliche gerne Biblotheksfunktionen oder 
optimiert das ganze sonstwie nicht optimal, da hier (im Gegensatz zu 
16bit Operationen) nicht so viele Optimierungsvarianten einprogrammiert 
sind.

von Ulrich (Gast)


Lesenswert?

Wenn man Glück hat, erkennt der Compiler die Zahl bei der Division als 
2er Potenz. trotzdem wird dann wohl eine schleife mit Shifts übrig 
bleibe. Besser ist es statt der Division einen Bitweise UND Verknüßfung 
zu nutzen:
also eher

OFFSET= Tabellenzaehler & 255

oder Offset gleich als unsigned Char definieren und nur

OFFSET= Tabellenzaehler

von technikus (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

im Anhang mal das was der Compiler aus der ISR macht.

LG
technikus

von Benedikt K. (benedikt)


Lesenswert?

OK, er ist immerhin so intelligent und erkennt die 2^n Division und 
macht da eine Schiebeoperation draus:
1
 8f8:  25 e1         ldi  r18, 0x15  ; 21
2
 8fa:  b6 95         lsr  r27
3
 8fc:  a7 95         ror  r26
4
 8fe:  97 95         ror  r25
5
 900:  87 95         ror  r24
6
 902:  2a 95         dec  r18
7
 904:  d1 f7         brne  .-12

Aber diese Schleife wird 21x durchlaufen -> 147 Takte

Insgesamt komme ich auf über 250 Takte.

von technikus (Gast)


Lesenswert?

O.K.

147 Takte hört sich überhaupt nicht gut an :-(


Wie kriege ich denn soetwas
1
//von 32 Bit auf Tabellenlänge 2048 
2
OFFSET= (uint16_t)(Tabellenzaehler / 2097152UL);

knapper hin ?

Gruß
technikus

von Falk B. (falk)


Lesenswert?

@  technikus (Gast)

>Wie kriege ich denn soetwas

>//von 32 Bit auf Tabellenlänge 2048
>OFFSET= (uint16_t)(Tabellenzaehler / 2097152UL);

>knapper hin ?

Wozu? Die Berechung des Frequenzeinstellwortes erfolgt EINMAL, die 
Akkumulation einer Variabelen ständig.

DDS_akku += Frequenzeinstellwort.

Einfacher gehts nicht. Aber das macht man nicht in C, sondern in ASM, 
sonst wird das alles reichlich albern und langsam. Das Programm kan man 
ja in C machen, die Hauptschleife aber als reinen ASM-Block.

Siehe DDS und

http://www.myplace.nu/avr/minidds/index.htm

MfG
Falk

von Hans L. (hansl)


Angehängte Dateien:

Lesenswert?

Also ich hab das mal mit einem 3 Byte-Zähler auf dem Tiny2313 und R2R-
Netzwerk gemacht. Daher auch die Grundlagen.

(Das Einlesen über RS232 habe ich mal kurz entfernt.Hier wird nur
der Additionswert gesetzt.)

Man sieht, wie die DDS in Asembler sehr einfach zu realisieren ist.

gruß hansl

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.