Topic: Software DDS in C!

Hallo Leute!

Heute wollte ich es wissen, ob die Idee von dk5pt mit einem ATtiny2313 umsetzbar ist.

http://sprint.no-ip.org/images/lowfer/softdds/IMG_0839_s.JPG

Tatsächlich! smile  Ich konnte 136.175kHz mit dem Soft-DDS erzeugen.

http://sprint.no-ip.org/images/lowfer/softdds/IMG_0840_s.JPG


Hier die Eckdaten:

  • Prozessor Takt: 14.4MHz

  • Phaseaccumulator Takt : 1/17 des Prozessortakts (~850kHz)

  • Bit-Breite: 24 Bit

  • Minimaler Step: ca. 0.05Hz

  • Stützpunkte: ca. 6

Und hier der C-Kode:

/*
        softdds ... a dds, implemented in software
        based on an idea from dk5pt, December 2000
        
        2011/11/12 OE1GCA

        avr-gcc -Os -mmcu=attiny2313 softdds.c -o softdds
        avr-objcopy -O ihex softdds softdds.hex
        avrdude -c stk500v2 -pt2313 -P/dev/ttyUSB0 -U hfuse:w:0xdb:m -U lfuse:w:0xef:m
        avrdude -c stk500v2 -pt2313 -P/dev/ttyUSB0 -U flash:w:softdds.hex
*/

#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>

/* Hardware connections */
/* ioport B: 8 bit DDS output */

const uint8_t  sinustabelle[256] PROGMEM = {
127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,
176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,
217,219,221,223,225,227,229,231,233,234,236,238,239,240,242,243,
244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,
254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,
244,243,242,240,239,238,236,234,233,231,229,227,225,223,221,219,
217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,
176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,
127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,
78,76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,
37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,
10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,
0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,
10,11,12,14,15,16,18,20,21,23,25,27,29,31,33,35,
37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,
78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124};


int main (void){

uint32_t x=0;   /* 24 bits  phase accumulator */

/* *******************************************
  fclk = 847235Hz (14.403MHz / 17 cycles), phase accu 24 bit
  m   = fout / 1/2^24*fclk
  fr    = 1/2^24*fclk 
*********************************************/

#define fxtl 14403300.0L                /* crystal frequency */
#define fout 136175.0L          /* desired output frequency */
#define bits 16777216UL         /* 2^24 */
#define cycles 17UL             /* current number of cycles */
#define fclk fxtl/cycles        /* calculate phase accumulator clock */
#define m (uint32_t)((fout*bits)/(fxtl/cycles)) /* calculate phase increment value */

        DDRB = 0xff;    /* port B is output */
        PORTB = 127;

        while (1) {
                x += m; /* add phase increment */
                PORTB = pgm_read_byte (&sinustabelle[(uint8_t )((x>>16)&0xFF)]);  /* ........ BBBBBBBB ........ ........ */
        }
}

Als DAC verwende ich einen ZN425E8 und sogar mit einem RC Tiefpass schaut das Signal akzeptabel am Oszilloskop aus.

http://sprint.no-ip.org/images/lowfer/softdds/IMG_0841_s.JPG

Der Kontrollempfänger (IC-R70) empfing einen schönen Pfeiton.

Jetzt muss man noch eine Interrupt-Routine für z.B.: Tasteneingaben für die Frequenz schreiben, dann hat man einen ultra-simplen Software-DDS.

73!
Gerhard

Re: Software DDS in C!

hallo gerhard

die idee scheint ja phaenomenal zu sein.
wenn ich das programm richtig interpretiere, wird in "m" die distanz zum naechsten wert aus der sinus tabelle berechnet.
und da ergibt sich ein minimaler step von 0.05 Hz ? erstaunlich.
wahrscheinlich nur in dem bereich um die 137 kHz.

wenn du eine interrupt routine fuer die eingabe dazu haengst musst du aber die while(1) schleife auch als interrupt implementieren. bzw. genau diese schleife muss als interrupt ausgefuehrt sein, denn die tastenabfrage kann ja asynchron erfolgen.

73 hans
oe1smc

Re: Software DDS in C!

Hallo Hans!
Die Schrittweite ist über den ganzen Abstimmbereich, wenn man das so nennen kann, gleich.

  • fstep = 1/2^24 x fclock

fclock ergibt sich aus CPU Clock / Anzahl der nötigen Maschinenbefehle.
Im obigen c-Programm, sind das nach der Optimierung, 17 Maschinenbefehle für eine Durchlauf. Eine kürzere Loop habe ich nicht zusammengebracht.

Das mit der Interruptroutine ist ganz schön verzwickt - d.h. die Loop bei max 17 Befehlen bleibt.
Man muss auch genau darauf achten, dass die Durchläufe immer gleiche Anzahl haben. Sonst gibt es Phasensprünge.

Eine Idee ist, nach dem Reset das 2. IO-Port einzulesen und damit die Frequenz (bis zum nächsten Reset) festzulegen. Damit könnte man mit dem ATtiny2313 127 Frequenzen definieren. Natürlich könnte man auch mit einem Shiftregister 8 oder mehr Bits einlesen, dann kann man auch die volle Auflösung des DDS's ausnutzen.

Vielleicht gibt es ja auch noch andere Ideen für die Abstimmung / Frequenzeingabe/?

73!
Gerhard

Re: Software DDS in C!

Wow, das nenne ich effizientes bauen !
Das mit dem interrupt für die up/down tasten könntest du schon in einer eigen ISR regeln. Du mußt ja eigentlich nur die interrupts sperren wenn du einen step für den sinusgenerator abarbeitest. Danach wieder freigeben .. und dann kommt halt die taste dran .. oder einfach pollen, wenn nix anderes zu tun ist .. vermutlich noch einfacher.
Wenn du jetzt noch im nulldurchgang 2 weitere ports togglst, dann haben wir den steuergenerator für die "schaltnetz-PA" auch schon.
:-) Wolfgang

Re: Software DDS in C!

Hallo Wolfgang!

Ich glaube nicht, dass das so einfach geht (oder es übersteigt gerade mein Vorstellungsvermögen).

Warum:

  • Jeder zusätzliche Befehl verringert natürlich die DDS-Clock (CPU-Clock/Anzahl der Befehle).

  • Die Adressen, die die Lookup-Table ansteuern "wandern" - d.h. es werden nicht immer die gleichen Stützpunkte adressiert

  • 850kHz Interruptfrequenz a bisserl viel ist

Gut, für den 1. Punkt könnte man eine schnellere CPU nehmen (ATxmega mit 32MHz).
Der 2. Punkt macht mir eher Kopfzerbrechen. Dadurch, dass die Stützpunkte sozusagen wandern, wird das Rechtecksignal einen Jitter aufweisen.

Ich glaube, mann muss das mal ausprobieren und testen ob sich dieser Jitter störend auswirkt.
Die Anzahl der Stützpunkte ist ja nicht sehr berauschend.

Konkret:

  • 14.4MHz/17 Befehle = 847kHz

  • 847kHz / 136.175kHz = 6.2 Stützpunkte für 2π -> ~16% Jitter (?)

Hm .... vielleicht nur ein Denkfehler ....

73!
Gerhard

Re: Software DDS in C!

Hallo Gerhard!

Das mit dem Jitter kann ich nachvollziehen. Im Prinzip hast Du eine konstante Frequenz aber mit einer PWM drauf. Also zeitweise die obere Halbwelle verlängert, zeitweise die untere. Inwieweit das störend ist, müsste man sich ansehen. Ich sehe das mal so: Was dabei entsteht ist eigentlich eine Schwebung aus den gewollten 136,175 und dem nächsten ganzzahligen Teil von 847 kHz, also 847/6= 141,167 kHz. Wäre interessant sich das Spektrum anzusehen. Ich vermute mal, dass ein Signal mit 136,175 kHz herauskommt, welches amplitudenmoduliert ist (PWM) mit 4,992 kHz (141,167-136,175). Diese Nebensignale könnten schon störend herauskommen über die bei diesen Frequenzen nicht mehr ganz optimal abgestimmte Antenne.

... oder denke ICH da jetzt falsch?

73 de Andreas, oe3dmb

Re: Software DDS in C!

So, hab mir jetzt den Spaß gemacht, das mal in Excel zu verarbeiten:

http://dl.dropbox.com/u/24166452/dds_ji … chteck.xls

Die Kurven zeigen:
1. Den "Quasi-Sinus" bzw. Cosinus errechnet mit der gegebenen Anzahl der Stützpunkte
2. Das jitternde Rechtecksignal
3. Den Mittelwert über eine Jitterschwingung (6 Punkte weil 6,2 geht schwer), zeigt praktisch die Schwebungsfrequenz.

73 de Andreas, oe3dmb

Re: Software DDS in C!

Ich hab mir das jetzt nochmal durch überlegt. Also die Amplitude verändert sich ja nicht. Also kann es weder Schwebung noch Amplituden modulation sein. Viel mehr denke ich handelt es sich um einen, sich langsam ändernden, gleichanteil. Oder anders gesagt, ein niederfrequentes Signal, das man vermutlich mit einen hochpass wegbring falls das überhaupt nötig ist.
73 oe3dmb

Re: Software DDS in C!

Hab heute den Arbitrary Generator im QRL mit Gerhards Parametern gefüttert und ein jitterndes Rechteck produziert:

jitter_square_time


Das Spektrum ist noch viel schlimmer als ich es mir ausgemalt habe:

jitter_square_spectrum


Jetzt weiss ich warum bei mir im Labor PWMs immer so viel Mist machen ....

Zum Vergleich ein sauberes Rechteck:

square_spectrum


und ein Sinus:

sinus_spectrum


73 de Andreas, oe3dmb

Re: Software DDS in C!

Hi DDS-Bauer!

Die "Profis"  wink  umgehen das Problem, indem sie das Ausgangssignal (sinus) durch ein LPF schicken und danach mit einem Komparator ein Rechtechk daraus machen.

Mit dem, vom Andi simulierten "Lattenzaun", kann man ja nicht wirklich was machen.

Ein interessanters Dokument zum Thema ist hier zu finden: http://www.analog.com/static/imported-f … MT-085.pdf
oder auch hier http://www.analog.com/static/imported-f … 2-2-99.pdf

Mit 2 Komparatoren und 2 etwas auseinanderliegenden Referenzspannungen könnte man die Totzeiten für die Endstufenansteuerung bewerkstelligen. Die "etwas auseinanderliegenden Referenzspannungen", müssten symmetrisch um den "Nulldurchgang" liegen, sonst hat man einen DC-Anteil im Kern - falls einer zur Anwendung gelangt.

Der Aufwand wäre immer noch akzeptabel - oder ?

73!
Gerhard

Re: Software DDS in C!

... simuliert ....

Naja stimmt schon, hab ja keinen DDS aufgebaut, sondern einen arbitrary Generator mit einem in Excel berechneten Signal gefüttert.

Aber es handelt sich nicht um eine reine Simulation, sondern schon um eine echte Messung eines echten Signals.

Nur um alle Klarheiten zu beseitigen wink

73 de Andreas, oe3dmb