DDS-Generator

Med microkontrollers som går snabbare och snabbare blir det möjligt att göra mer och mer avancerade saker. Ett av mina senaste projekt var en DDS-generator. Hjärtat är en ATMega88, och den innehåller också ett R/2R motståndsnät för D/A-omvandling, samt lite operationsförstärkare för att anpassa utgångssignalen.

Disposition

Först kommer en allmän beskrivning av grundprincipen för DDS-generering av signaler. Därefter beskriver jag schemat för den digitala delen och DA-omvandlaren. I stycket därefter beskriver jag den analoga delen av bygget, som jag tycker blev väldigt bra. Sist lite om "användarinterfacet".

Grunden för DDS-generering

DDS-generatorer innehåller en digital del samt en analog del. Den analoga delen utgörs helt enkelt av en DA-omvandlare. Allt som har med signalgenerering sker i den digitala delen. Jag kommer att visa hur man digitalt genererar en ramp-funktion (alla värden från 0 till 255). När man kan generera en ramp-funktion med rätt frekvens, kan man generera vilken godtycklig vågform som helst. Man slår helt enkelt upp värdet av den andra funktion mha värdet från rampfunktionen.

DDS-generatorn innehåller två register, ett register som ökas med ett speciellt värde vid varje klockcykel (AUTOINC), samt ett register som anger hur stor ökningen skall vara (INC). I detta exempel låter jag registerna vara bara 24 bitar långa. Utsignalen (rampfunktionen) får man faktiskt från alla bitarna i AUTOINC. Men har AD-omvandlaren man använder färre bitars upplösning än registret, så använder man bara de högsta bitarna i registret AUTOINC. I mitt fall är bara de högsta åtta bitarna intressanta.

Tänk er att ni vill öka utsignalens värde ett steg vid varje klockcykel. Det kan man göra genom att sätta INC=0x010000. Var AUTOINC nollställt från början så ändras dess värde vid varje klockcykel enligt följande 0x00000 0x010000 0x020000 osv. Utsignalen ökar alltså med ett vid varje klockcykel. Det går inte att generera signaler med högre frekvens än detta utan att hoppa över vissa av värdena i utsignalen.

Vill man generera en signal med halva frekvensen som signalen ovan, sätter man INC=0x008000. AUTOINC's värde ändras vid varje klockcykel enligt följande 0x00000 0x008000 0x010000 0x018000 0x020000 osv. Den högsta byten (utsignalen) var 0x00 0x00 0x01 0x01 0x02 osv. Alltså halverades utfrekvensen när man halverade värdet på INC. I utsignalens värden ser man också att varje värde repeteras flera gånger i rad. Detta sker alltid vid låga frekvenser. Vid höga frekvenser kan det i stället bli så att man hopper över värden i stället, och man kan ofta nöja sig med bara 10-20 utmatade värden per cykel vid t.ex sinusvåg.

Formler som ger värdet på INC-registret:

utfrekvens:             fut (KÄND)
värde till INC          INC (SKA BERÄKNAS)
-----------------------------------------------------
Microcontrollerklocka:  mcu_clk   = 20E6 Hz
Cykler i DDS-slinga:    dds_ticks = 9 cykler
DDS-clocka:             fddsclk   = mcu_clk/dds_ticks
bitar i registren:      bits      = 24 bitar
-----------------------------------------------------
faktor=2^(bits)/fddsclk

INC = faktor*fut

För att använda heltal i mikrokontrollern kan man multiplicera faktorn med t.ex 65536, och använda den nya faktorn (0x78CBC) för att räkna ut INC, och sen kasta bort de två sista byten man får i resultatet.

Digital del och AD

Microkontrollern är en ATMega88 med en 20MHz-kristall. Den är kopplad till en LCD, några knappar, en vridencoder, samt en R/2R DA-omvandlare. PGA brist på pinnar, används samma pinnar till både LCD och tangenter. Detta är schemat:

FIXME infoga schema

Själva DDS-genereringen sker i en slinga, som adderar två 24-bitars tal, och slår upp utsignalens värde i en tabell, så att godtyckliga värden kan genereras. All inmatning från knappar eller vridenkoder bryter slingan genom hårdvaruinterrupt, och gör att utsignalens värde tillfälligt står stilla medan insignalerna tas om hand. En stor del av tiden utanför slingan går åt till att vänta på displayen (för att visa ny frekvens, vågform, etc). När mjukvaran blir färdig, kan man göra så att DDS-slingan körs medan man väntar på displayen, och man kommer då att få nästan kontinuerliga utsignaler.

DDS-slingan tar 9 klockcykler per varv, så klockan till DDS:en som den är beskriven i avsnittet ovan blir 20/9 MHz. Det innebär att den inte skippar steg i genereringen vid frekvenser under 8680 Hz, och att den vid frekvensen 222 KHz bara har med 10 värden per cykel av utsignalen. Ett utdrag av koden för huvudslingan följer:

;lite av initieringen innan huvudslingan som är nödvändig för att förstå den:

.def cnt_hihi = R27  ;definierad på samma ställe som höga delen av register X
.def cnt_hilo = R26  ;definierad på samma ställe som låga delen av register X

ldi cnt_hihi,high(wavetable) ; wavetable är en 256 byte lång uppslagstabell i SRAM
                             ; vars första posts adress ligger på en 256byte-gräns.
                             ; Tabellen är fylld med vågformen att generera

;Själva huvudslingan

loop:                        ;       (tar totalt 9 klockcykler när den inte ska avbrytas)
   add cnt_lolo, inc_lolo    ;1 clk
   adc cnt_lohi, inc_lohi    ;1 clk
   adc cnt_hilo, inc_hilo    ;1 clk

   ld tmp,X                  ;2 clk  (X är ekvivalent med [cnt_hihi:cnt_hilo])
   out PORTD,tmp             ;1 clk
   sbrs status,0             ;1 clk  (1 ckl då man inte ska bryta slingan, annars fler)
                             ;       (status sätts av interruptrutin om vi bör hoppa ur slingan)
   rjmp loop:                ;2 clk

Analoga delen

Syftet med den analoga delen är att kunna justera utsignalens amplitud samt DC-offset. För att klara av det kombinerade jag olika standardkopplingar med operationsförstärkare. Under konstruktionen fick man tänka på att inte överstyra operations-förstärkarna, och just därför drev jag ned nivån i punkten XXX i schemat nedan. I schemat är de olika funktionsblocken utmarkerade. Utgången kan inte driva mer än XXX mA, men ska tydligen vara kortslutningsskyddad DUBBELKOLLA, så jag kommer nog att använda samma analoga konstruktion så fort jag vill justera DC-offset och amplitud i andra byggen.

Användarinterface

LCD + vridencoder + 6 knappar + potentiometrar för offset och gain, samt BNC-anslutning av utsignal.

FIXME fyll i mer om mjukvaran och knappfunktioner när mjukvaran helt klar

Uppdatering 2006-12-05:

Har använt DDS-generatorn något år nu, och har haft väldigt mycket nytta av den fastän mjukvaran inte är helt färdig (saknas justering för symmetri). Hårdvaran saknar ett dämpsteg på 20db (blir för mycket brus när man bara minskar topp-till-topp-amplituden. Numera skulle man också behöva en bättre avstudsning av den mekaniska rotationsavkodare som används för att ställa in frekvensen. Den mjukvaru-avstudsning jag använde fungerade väldigt bra i början, men allt eftersom rotationsavkodaren blivit mer och mer sliten, så börjar den vara i behöv av en ny avstudsnings-algoritm, eller avstudsning i hårdvaran. Jag funderar mest på avstudsning med hårdvara, för då kan jag tillåta snabbare vridning av enkodern än vad nuvarande avstudsning klarar.

OBS! Du bygger alltid på egen risk, jag garanterar inte att något fungerar för dig.
Du ansvarar själv för risken att skada dig själv/andra/saker/datorer/eller annat!