wieder einmal dds

Gast #1220482
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
Gast #1220548
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
#1220556
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.
Gast #1220569
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
#1220605
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.
Gast #1220610
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
#1220629
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

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.