Zurück (C) Christof Ermer, Regensburg

Gratis Counter 20.02.2011
2018


Phasen Akkumulator
DDS = 

Direct Digital Synthesis



PDFs: ddsgenerator
Links:
http://de.wikipedia.org/w/index.php?title=Datei:Frequency-tunable_DDS_system.png&filetimestamp=20080910153940


Die direkte digitale Synthese basiert auf einem digitalen Addierwerk, kombiniert mit einem Register samt Rückkopplung, das einen Speicher für diePhasenlage darstellt und in nebenstehender Abbildung dargestellt ist. Die angegebenen Bitbreiten in der Abbildung sind beispielhaft und verdeutlichen die in den einzelnen Stufen unterschiedlichen Wortbreiten.

Dieser sogenannte Phasenakkumulator addiert zyklisch, pro Taktschritt, den links zugeführten Eingabewert, der indirekt proportional die Frequenz einstellt. Der momentane Zählerstand entspricht dann einem Phasenwinkel, und ein Überlaufen des Phasenakkumulators (automatischer Rücksprung auf Null) entspricht dabei einen vollen Umlauf des Phasenzeigers von 2·π.


Der zu einem bestimmten Phasenwert gehörende Signalwert wird durch eine weitere Funktion gebildet, die einem Phasenwert einen Signalwert zuordnet. Ist beispielsweise ein sinusförmiger (harmonischer) Signalverlauf gewünscht, stellt dieser Block die Sinusfunktion dar. Die Abbildung kann bei kleinen Bitbreiten in der digitalen Schaltung in Form einer bereits im Voraus berechneten ROM-Tabelle erfolgen. Alternativ können die Ausgabewerte für einen sinusförmigen Signalverlauf auch zur Laufzeit mit Algorithmen wie dem CORDIC-Algorithmus in der Schaltung berechnet werden. Wird lediglich eine Sägezahnschwingungbenötigt (beispielsweise für einen Synthesizer), so kann der Phasenwert direkt als Signalwert ausgegeben werden, da die Phase innerhalb jeder Periode linear ansteigt und dann auf Null zurückspringt. Eine Dreieckschwingung, die für einige Anwendungen einen Sinus ersetzen kann, lässt sich erzeugen, indem man den Phasenwert als vorzeichenbehaftete Binärzahl (Zweierkomplement) interpretiert und deren Absolutwert berechnet.

Das digitale Signal kann dann weiteren Stufen zur Verarbeitung zugeführt werden, beispielsweise für eine analoge Ausgabe dem in der Abbildung rechts außen dargestellten Digital-Analog-Umsetzer.

Die mit dem Verfahren erreichbare Frequenzauflösung hängt ausschließlich von der Wortbreite des Phasenakkumulators ab. Eine typische Wortbreite ist 32 bit, damit beträgt die Frequenzauflösung bei 100 MHz Systemtakt etwa 0,023 Hz bei einer maximalen Ausgangsfrequenz von theoretisch der halben Taktfrequenz (50 MHz).

Die Qualität des Ausgangssignals hängt im Wesentlichen von der Qualität des Taktgenerators, dessen möglichst geringem Jitter und der Genauigkeit des Digital-Analog-Umsetzers ab. Je höher die Frequenz (= kleinerer Teiler), desto gröber wird die Abtastung der Tabelle und desto wichtiger werden dem DA-Umsetzer nachgeschaltete Filter. In der Praxis ist ein Kompromiss zwischen der Bandbreite und der Genauigkeit zu schließen. Im Frequenzbereich unter 100 MHz lassen sich, mit Stand 2008, Sinussignale mit Nebenwellenabständen von ca. 80 dB realisieren. DDS-Schaltkreise mit integriertem D/A-Umsetzer sind heute mit Taktfrequenzen bis ca. 1000 MHz verfügbar.

Die Implementierung des DDS (ohne analogen Wandler) kann sehr einfach sowohl in einem FPGA, DSP oder auch ASIC erfolgen. Durch entsprechende funktionale Erweiterungen der DDS ist auch eine Winkelmodulation oder Amplitudenmodulation des Ausgangssignals realisierbar.



; Datei minidds.asm angepasst für AVR Studio
;
;  Copyright (C) 2000 Jesper Hansen <jesperh@telia.com>.
;
;  This program is free software; you can redistribute it and/or
;  modify it under the terms of the GNU General Public License
;  as published by the Free Software Foundation; either version 2
;  of the License, or (at your option) any later version.
;
;  This program is distributed in the hope that it will be useful,
;  but WITHOUT ANY WARRANTY; without even the implied warranty of
;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;  GNU General Public License for more details.
;
;  You should have received a copy of the GNU General Public License
;  along with this program; if not, write to the Free Software Foundation,
;  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
;
;
;*******************************************************************
;*******************************************************************
;
;Description
;
; Poor-mans DDS Synthesizer
;
; Author = Jesper Hansen
; Target = AT90S2313
; Date   = 2001-02-15
;
; Code is written for use with AVR-GCC in assembler mode
; flag:  -x assembler-with-cpp
;
;
; PB0..7 = D/A Data out
;
; PD0        RXD
; PD1        TXD
; PD2..6    not used
;

;*******************************************************************
;*******************************************************************
;
;
;
; Output frequency (using 24 bit accumulator) :
;
;    f = deltaPhase * fClock/2^24
;
;   fClock is in this case the CPU clock divided by the
;    number of cycles to output the data ( 9 cycles )
;
;    f = r24/r25/r26 * (11059200/9)/16777216
;
;    f = r24/r25/r26 * 0.073242188
;
;    fMax (theoretical) = 0.5 * fClock
;


;******************************************************************************
; start of code
;******************************************************************************



.include "2313def.inc"   

;    .section     .text

    .org 0
        rjmp    RESET

    .org 14
        rjmp    RX_COMPLETE_INT


;******************************************************************************
; data tables
;******************************************************************************

    ; force table to begin at 256 byte boundary

    .org 0x100

sine:        ; 256 step sinewave table
    .DB 0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae
    .DB    0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8
    .DB    0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5
    .DB    0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff
    .DB    0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7
    .DB    0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc
    .DB    0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3
    .DB    0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83
    .DB    0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51
    .DB    0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27
    .DB    0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a
    .DB    0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00
    .DB    0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08
    .DB    0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23
    .DB    0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c
    .DB    0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c

sawtooth:    ; 256 step sawtoothwave table
    .DB    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
    .DB    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
    .DB    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
    .DB    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
    .DB    0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
    .DB    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
    .DB    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
    .DB    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
    .DB    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
    .DB    0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
    .DB    0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
    .DB    0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
    .DB    0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf
    .DB    0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf
    .DB    0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef
    .DB    0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff

triangle:    ; 256 step trianglewave table
    .DB    0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e
    .DB    0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e
    .DB    0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e
    .DB    0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e
    .DB    0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e
    .DB    0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe
    .DB    0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde
    .DB    0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe
    .DB    0xff,0xfd,0xfb,0xf9,0xf7,0xf5,0xf3,0xf1,0xef,0xef,0xeb,0xe9,0xe7,0xe5,0xe3,0xe1
    .DB    0xdf,0xdd,0xdb,0xd9,0xd7,0xd5,0xd3,0xd1,0xcf,0xcf,0xcb,0xc9,0xc7,0xc5,0xc3,0xc1
    .DB    0xbf,0xbd,0xbb,0xb9,0xb7,0xb5,0xb3,0xb1,0xaf,0xaf,0xab,0xa9,0xa7,0xa5,0xa3,0xa1
    .DB    0x9f,0x9d,0x9b,0x99,0x97,0x95,0x93,0x91,0x8f,0x8f,0x8b,0x89,0x87,0x85,0x83,0x81
    .DB    0x7f,0x7d,0x7b,0x79,0x77,0x75,0x73,0x71,0x6f,0x6f,0x6b,0x69,0x67,0x65,0x63,0x61
    .DB    0x5f,0x5d,0x5b,0x59,0x57,0x55,0x53,0x51,0x4f,0x4f,0x4b,0x49,0x47,0x45,0x43,0x41
    .DB    0x3f,0x3d,0x3b,0x39,0x37,0x35,0x33,0x31,0x2f,0x2f,0x2b,0x29,0x27,0x25,0x23,0x21
    .DB    0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x11,0x0f,0x0f,0x0b,0x09,0x07,0x05,0x03,0x01



square:        ; 256 step squarewave table
    .DB    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    .DB    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    .DB    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    .DB    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    .DB    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    .DB    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    .DB    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    .DB    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    .DB    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
    .DB    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
    .DB    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
    .DB    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
    .DB    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
    .DB    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
    .DB    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
    .DB    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff



;******************************************************************************
; code
;******************************************************************************


RESET:
        ldi        r16, RAMEND
        out        SPL, r16        ; setup stack pointer

        ldi        r16,0x05        ; set uart speed to 115.2 kbps
        out        UBRR,r16

        ldi        r16,0x98        ; enable RXint and enable tx/rx
        out        UCR,r16

        sei                        ; global enable interrupts

        ser        r16                ;
        out        DDRB,r16        ; set all PORTB bits as output
   

        ; set sinewave output as default
       
        ldi        r31,high(sine)    ; setup Z pointer hi
        ldi        r30,low(sine)    ; setup Z pointer lo

        ; clear accumulator

        ldi     r29,0x00        ; clear accumulator
        ldi     r28,0x00        ; clear accumulator

        ; setup adder registers       
       
        ldi     r24,0x55        ; setup adder value
        ldi     r25,0x35        ; to 1 kHz
        ldi     r26,0x00        ;



; main loop
;
;    r28,r29,r30 is the phase accumulator
;      r24,r25,r26 is the adder value determining frequency
;
;     add value to accumulator
;    load byte from current table in ROM
;    output byte to port
;    repeat
;
LOOP1:
        add        r28,r24            ; 1
        adc        r29,r25            ; 1
        adc        r30,r26            ; 1
        lpm                        ; 3
        out        PORTB,r0        ; 1
        rjmp    LOOP1            ; 2 => 9 cycles


;**********************************************************************
; communication functionality
;**********************************************************************

;
; get char in r16
;
get_char:
        in         r16,USR            ; wait for a byte to be ready
        sbrs    r16,7            ; ready ?
        rjmp    get_char        ; no, wait some more
        in        r16,UDR            ; get the byte
        ret                        ; and return
       
;
; send char in r16
;
send_char:
        push    r16                ; save r16
send_c2:
        in         r16,USR            ; wait for the transmitter to be ready
        sbrs    r16,5            ; ready ?
        rjmp    send_c2            ; no, wait some more
        pop        r16                ; restore r16
        out        UDR,r16            ; send char
        ret                        ; ans return

;
; send the current frequency to the PC
; as a 5 byte sequence :
; 'F' folowed by a 32 bit phase accumulator value
;
;
send_data:
        push    r16                ; save r16
        ldi        r16,'F'            ; flag
        rcall    send_char

        clr        r16                ; zero byte for 32-bit compatibility
        rcall    send_char        ; MSB

        mov        r16,r26
        rcall    send_char        ; high add

        mov        r16,r25
        rcall    send_char        ; mid add

        mov        r16,r24
        rcall    send_char        ; low add

        ldi        r16,0x0a
        rcall    send_char        ; terminator
        pop        r16
        ret


; add 1 to the phase accumulator       
up_one:
        adiw    r24,1   
        clr        r23
        adc        r26,r23
        ret

; add 10 to the phase accumulator       
up_ten:
        adiw    r24,10   
        clr        r23
        adc        r26,r23
        ret

; add 100 to the phase accumulator       
up_hundred:
        ldi        r23,0x64
        add        r24,r23
        clr        r23
        adc        r25,r23
        adc        r26,r23
        ret

; subtract 1 from the phase accumulator       
down_one:
        sbiw    r24,1       
        clr        r23
        sbc        r26,r23
        ret

; subtract 10 from the phase accumulator       
down_ten:
        sbiw    r24,10       
        clr        r23
        sbc        r26,r23
        ret

; subtract 100 from the phase accumulator       
down_hundred:
        clr        r23
        subi    r24,0x64       
        sbc        r25,r23
        sbc        r26,r23
        ret

;
; read in 4 characters from the serial link
;
read_4:
        rcall    get_char        ; read and ignore bits 32..24
        rcall    get_char        ; read bits 23..16
        mov        r26,r16
        rcall    get_char        ; read bits 15..8
        mov        r25,r16
        rcall    get_char        ; read bits 7..0
        mov        r24,r16
        ret

;
; Interrupt routine for incoming bytes on the RS232 link
;
   
RX_COMPLETE_INT:
        push    r16
        in         r16,UDR
        cpi        r16,'+'                ; up one
        brne    tx_2
        rcall    up_one
        rjmp    tx_exit       
tx_2:
        cpi        r16,'u'                ; up ten
        brne    tx_3
        rcall    up_ten
        rjmp    tx_exit       
tx_3:
        cpi        r16,'U'                ; up hundred
        brne    tx_4
        rcall    up_hundred
        rjmp    tx_exit       
tx_4:
        cpi        r16,'-'                ; down one
        brne    tx_5
        rcall    down_one
        rjmp    tx_exit       
tx_5:
        cpi        r16,'d'                ; down ten
        brne    tx_6
        rcall    down_ten
        rjmp    tx_exit       
tx_6:
        cpi        r16,'D'                ; down hundred
        brne    tx_7
        rcall    down_hundred       
        rjmp    tx_exit       
tx_7:
        cpi        r16,'s'                ; frequency setting
        brne    tx_8
        rcall    read_4       
        rjmp    tx_exit       
tx_8:
        cpi        r16,'?'                ; just force a reply
        brne    tx_9
        rjmp    tx_exit       
tx_9:   
        cpi        r16,'1'                ; request sinewave output
        brne    tx_10
        ldi        r31,high(sine)        ; setup Z pointer hi
        ldi        r30,low(sine)        ; setup Z pointer lo
        rjmp    tx_exit
tx_10:
        cpi        r16,'2'                ; request sawtooth output
        brne    tx_11
        ldi        r31,high(sawtooth)    ; setup Z pointer hi
        ldi        r30,low(sawtooth)    ; setup Z pointer lo
        rjmp    tx_exit
tx_11:
        cpi        r16,'3'                ; request triangle output
        brne    tx_12
        ldi        r31,high(triangle)    ; setup Z pointer hi
        ldi        r30,low(triangle)    ; setup Z pointer lo
        rjmp    tx_exit
tx_12:
        cpi        r16,'4'                ; request squarewave output
        brne    tx_13
        ldi        r31,high(square)        ; setup Z pointer hi
        ldi        r30,low(square)        ; setup Z pointer lo
        rjmp    tx_exit

; unknown command, just ignore it
tx_13:


; always reply with the current frequency
tx_exit:
        rcall    send_data
        pop        r16
        reti





;******************************************************************************
; end of file   
;******************************************************************************