Forum: FPGA, VHDL & Co. DDS Compiler und Phase Increment


von Hans-Werner (Gast)


Lesenswert?

Ich habe mittels des Core Generators von Xilinx ISE 10.1 einen DDS Core 
erzeugt. Mit folgenden Einstellungen: Frequency Resolution 10 kHz, 
Spurious Suppression 72dB bzw. 12bit Ausgangsbreite, Clock 300 MHz, 
Phase Increment Fixed, Phase Offset None.
Die 300 MHz sollen auf dem Spartan 3 AN Starter Kit mittels eines DCM 
Cores erzeugt werden. Maximal sind 330 MHz möglich.
Wie bestimmt sich der Wert für den Phasen Increment bei der Festlegung 
Fixed ? Im Menü des DDS Compilers wird der Wert 8000 Hex angegeben. Die 
automatisch erzeugt vdl-Datei (Wrapper) beinhaltet auch diesen Wert. Die 
Festlegung des Phasen Increments muß anscheinend durch nachträgliche 
Änderung in der Wrapper-Datei erfolgen.
Für eine Ausgabefrequenz von 1 MHz ergibt sich ein Phasen Increment von 
13,653. Lässt sich dieses nur ganzzahlig festlegen also 13 oder 14 ? 
Wenn ja, ergäbe sich eine grosse Abweichung gegenüber der gewünschten 
Frequenz.
In der Beschreibung des DDS Cores findet sich folgender Satz:
"Based on the Core customization parameters, the DDS core will 
automatically employ quarter-wave symmetry when appropriate1."
Unter welchen Umständen wird die Symmetrie ausgenutzt ?
Auch die Programmierung des Phase Increments und des Phase Offsets ist 
mir noch nicht klar. Werde die Beschreibung weiter durchforsten.

von Kurt Georg (Gast)


Lesenswert?

Der D/A-Wandler läuft?
Dann hast du sicherlich einen Sample-Takt von 1 bis 2 MHz.
Folgende DDS-Konfiguration wird fürs erste funktionieren:

System Clock 1 MHz (bzw. dein Sample-Takt)
SFDR 70 dB --> 12 Bit
Frq. Resolution 0.4 Hz
Phase Inkrement fixed
Phase Offset none
Output Frequency Ch 1 0.1 MHz
Auf Seite 4 brauchst du ein Clock Enable und das RDY
Das wars.

Nun hast du zwei Eingänge CLK und CE. An CLK legst du 50 MHz oder 100 
MHz oder was du auch immer für einen Systemtakt hast (300 MHz sind nicht 
sinnvoll). An CE legst du den Sampletakt (s.o.), der aber immer nur für 
eine einzige Systemtaktperiode aktiv sein darf.
Als Ausgang bekommst du 12 Bit die zur State-Machine des D/A-Wandlers 
als Daten hingehen. Das RDY benutzt du, um den Zustandsautomaten zu 
triggern, damit ein neuer Ausgabezyklus beginnt, es ist auch immer nur 
für eine Systemtaktperiode aktiv. Wenn alles klappt, bekommst du dann 
einen 100 kHz Sinus aus dem D/A-Wandler.

Viel Erfolg!

von Hans-Werner (Gast)


Lesenswert?

Hallo Kurt,

vielen Dank für die schnelle Antwort.
>> System Clock 1 MHz (bzw. dein Sample-Takt)
Warum 1 Mhz ? Hatte gedacht das je schneller die Clockfrequenz, desto 
höher die Ausgangsfrequenz. Je schneller, desto besser.
>> Frq. Resolution 0.4 Hz
Warum das ? Ist glaube ist der niedrigste Wert den man angeben kann.
>> Phase Inkrement fixed
Programmierbar wäre doch schöner. Laut Beschreibung A MSB = 0 für Phasen 
Increment und A MSB = 1 für Phasen Offset. Und die niedrigsten vier Bit 
für den Kanal. Wert über Data.

von Kurt Georg (Gast)


Lesenswert?

>Warum 1 Mhz ?
Die 1 MHz deswegen, weil du nicht mehr Werte erzeugen musst, als du 
ausgeben kannst, ich spiele auf deinen D/A-Wandler an.

Die Frequenzauflösung bestimmt die Bitbreite des Phasenakkumulators. 
Angenommen du hättest ein FTW von 0x66666, dann würde 0x66667 eine um 
nicht mehr als 0,4 Hz höhere Frequenz erzeugen, also fein aufgelöst. Bei 
10 kHz Auflösung kannst du die Frequenz nur sehr grob einstellen.

>Programmierbar wäre doch schöner.
Das wäre die nächste Baustelle auf der anderen Seite des DDS-Cores, dazu 
brauchst du etwas, das dir die Frequenztuningworte generiert bzw. 
ausrechnet (Mikrocontroller).

von Hans-Werner (Gast)


Lesenswert?

>Warum 1 Mhz ?
Die 1 MHz deswegen, weil du nicht mehr Werte erzeugen musst, als du
ausgeben kannst, ich spiele auf deinen D/A-Wandler an.

Ich denke der DA-Wandler kann, laut Datenblatt, 50 MHz verkraften.
Soweit verstanden bezieht sich das auf die einzelnen Bits des 24 Bit 
bzw. 32 Bit Datenwortes an den DA-Wandler. Wie schnell jeweils die 24 
Bits mit dem 12 Bit DA-Wert angelegt werden können, habe ich noch nicht 
herausgefunden.

>Programmierbar wäre doch schöner.
Das wäre die nächste Baustelle auf der anderen Seite des DDS-Cores, dazu
brauchst du etwas, das dir die Frequenztuningworte generiert bzw.
ausrechnet (Mikrocontroller).

Also allein mit dem FPGA kann ich nur einen fixen Phasen Offset und ein 
fixes Phasen Increment angeben ? Das lässt sich nicht mittels VHDL 
verändern ? Das bedeutet ich bin an eine feste Ausgangsfrequenz 
gebunden. Was muß dann da gerechnet werden ? Beispielsweise a*b/c ?

Die Frequenzauflösung bestimmt die Bitbreite des Phasenakkumulators.
Angenommen du hättest ein FTW von 0x66666, dann würde 0x66667 eine um
nicht mehr als 0,4 Hz höhere Frequenz erzeugen, also fein aufgelöst.

FTW ???

Bei 10 kHz Auflösung kannst du die Frequenz nur sehr grob einstellen.

Die Frequenz ergibt sich doch aus dem Phasen Increment. Wie du zuvor 
erklärt hast lässt das Phasen Increment nicht verändern, also wie kann 
ich diese dann einstellen ? Ich verstehe das als Widerspruch oder was 
ist hier mit "einstellen" gemeint ?

Und zu guter letzt. Wie verwende ich jetzt die vom Core Generator 
erzeugte Sinuscore.vhd Datei für die Synthese ? Simulieren funktioniert. 
VHDL Text in eine eigene Datei kopieren oder irgendwie anders einbinden 
? Der Wrapper wird unter Implementation nicht angezeigt. Beim Versuch 
die Datei zum Projekt hinzuzufügen erhalte ich die Fehlermeldung das 
diese schon im Projekt enthalten ist. Da die Datei nicht aufgeführt 
wird, kann ich doch auch nicht die Synthese durchführen.

Schon mal im voraus: Vielen Dank für Deine Hilfe

von Kurt Georg (Gast)


Lesenswert?

Hans-Werner, der Grundgedanke meines Vorschlags war, den DDS-Core und 
den D/A-Wandler erstmal in einfachster Konfiguration und mit wenigen, 
überschaubaren Problemen (mit einer festen Frequenz) zum laufen zu 
bringen. Das Verständnis für die Funktion und wie man das dann 
erweitert, kommt dann fast von selbst.

>Wie schnell jeweils die 24 Bits mit dem 12 Bit DA-Wert angelegt
>werden können, habe ich noch nicht herausgefunden.
Das ist der springende Punkt: 50 MHz / 24 ist rund 2 MHz.

>Also allein mit dem FPGA kann ich nur einen fixen Phasen Offset und ein
>fixes Phasen Increment angeben ? Das lässt sich nicht mittels VHDL
>verändern ? Das bedeutet ich bin an eine feste Ausgangsfrequenz
>gebunden. Was muß dann da gerechnet werden ? Beispielsweise a*b/c ?
Da musst du nochmal lesen, wie DDS geht, aber s.o.

>FTW ???
FTW heisst Frequency Tuning Word, ich glaube nur ein anderer Ausdruck 
für das Phasen-Inkrement.

>Die Frequenz ergibt sich doch aus dem Phasen Increment. Wie du zuvor
>erklärt hast lässt das Phasen Increment nicht verändern, also wie kann
>ich diese dann einstellen ? Ich verstehe das als Widerspruch oder was
>ist hier mit "einstellen" gemeint ?
Einstellen vorerst mit dem Core-Generator durch Angabe der festen 
Frequenz.

>Und zu guter letzt. Wie verwende ich jetzt die vom Core Generator
>erzeugte Sinuscore.vhd Datei für die Synthese ?
Gar nicht. Nimm die XCO-Datei.
Rechte Maustaste in dein Projekt, "Add Source" und die vom 
Core-Generator erzeugte XCO-Datei wählen.
Deine oberste VHD-Datei sollte folgendes in ähnlicher Form enthalten, 
schau dir dazu auch die VHO-Datei an:
1
component dds_test1
2
   port ( ce      : IN  std_logic;
3
          clk     : IN  std_logic;
4
          rdy     : OUT std_logic;
5
          sine    : OUT std_logic_vector(11 downto 0));
6
end component;
7
8
   dds_block: dds_test1
9
      port map(
10
      ce => sample_clk,
11
      clk => system_clk,
12
      rdy => da_new_data_trig,
13
      sine => da_data);

Vorschlag für den nächsten Schritt: Erzeuge einen Takt von 1 MHz und gib 
mit diesem Takt abwechselnd 000h und fffh an den Zustandsautomaten des 
D/A-Wandlers aus. Erst wenn das klappt, ist die Einbindung des DDS-Cores 
sinnvoll.

von Hans-Werner (Gast)


Lesenswert?

Als Ausgang bekommst du 12 Bit die zur State-Machine des D/A-Wandlers
als Daten hingehen. Das RDY benutzt du, um den Zustandsautomaten zu
triggern, damit ein neuer Ausgabezyklus beginnt, es ist auch immer nur
für eine Systemtaktperiode aktiv. Wenn alles klappt, bekommst du dann
einen 100 kHz Sinus aus dem D/A-Wandler.

Ein etwas verschliffener Rechteck lässt sich erzeugen.
Also das RDY in die Sensitivitätsliste des Prozesses mit dem 
Zustandsautomaten für die DA-Konvertierung ?

An CE legst du den Sampletakt (s.o.), der aber immer nur für
eine einzige Systemtaktperiode aktiv sein darf.

Also einen eigenen Prozess für den Sampletakt parallel zum 
Zustandsautomaten der DA-Konvertierung ? Der Sampletakt kann also 
unabhängig von dem Takt des Zustandsautomaten gewählt werden ?

von Hans-Werner (Gast)


Lesenswert?

Hallo Kurt,

meintes du es vielleicht so ?

1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;
4
5
6
entity adc_out is
7
  port (
8
      clock     : in std_logic;   -- 50 MHz Clock
9
      SPI_SCK    : out std_logic;
10
      SPI_MOSI   : out std_logic;
11
      DAC_CLR    : out std_logic;
12
      DAC_CS      : out std_logic;
13
      led         : out std_logic_vector(7 downto 0)
14
      );
15
end entity adc_out;
16
17
architecture rtl of adc_out is
18
  
19
  -- Der Core soll einen Sinus mit 1 MHz erzeugen
20
  component Sinuscore
21
  port 
22
  (
23
        ce: IN std_logic;
24
        clk: IN std_logic;
25
        rdy: OUT std_logic;
26
        sine: OUT std_logic_vector(11 downto 0)
27
  );
28
  end component;
29
    
30
  type dacStateType is (idle, sendBit, clockHigh, csHigh);
31
  signal dacState   : dacStateType;
32
  signal clock_enable     : std_logic;
33
  signal ready : std_logic;
34
  
35
  signal sine_out  : std_logic_vector(11 downto 0);
36
  -- 24 Bit Format
37
  signal dacCounter : integer range 0 to 23;
38
  signal DAC_OUT    : std_logic_vector(23 downto 0);
39
  
40
  constant teiler : positive := 1;
41
  signal zaehler : integer range 0 to teiler := 0;
42
  type states is (one, two);
43
  signal state : states;
44
   signal takt : std_logic;
45
begin
46
47
  sine_wave_label : Sinuscore
48
  port map
49
  (
50
    ce => takt,
51
    clk => clock,   -- 50 MHz Clock
52
    rdy => ready,
53
    sine => sine_out
54
  );
55
  
56
  ----------------------------------------------------------------------------------------
57
  
58
  leds : process (clock)
59
  begin
60
    if rising_edge(clock)
61
    then  
62
      led(7 downto 2) <= "000000";  
63
      led(1) <= clock_enable;
64
      led(0) <= ready;    
65
    end if;
66
  end process;
67
  
68
  ----------------------------------------------------------------------------------------
69
  
70
  -- Bei 1 MHz sollte ein Sampletakt von 50 MHz möglich sein
71
    -- Hier 50 Mhz des Boards durch 2
72
   Sampletakt : process (clock)
73
   begin
74
    if rising_edge(clock)
75
    then
76
      case state is
77
        when one =>    if zaehler < teiler
78
                  then 
79
                    takt <= '0';
80
                    zaehler <= zaehler + 1;
81
                  else
82
                    state <= two;
83
                  end if;
84
        when two =>     takt <= '1';
85
                  zaehler <= 0;
86
                  state <= one;
87
                
88
      end case;
89
      end if;
90
    end process;
91
   
92
   
93
  process(clock, ready)
94
   begin
95
     if rising_edge(clock) 
96
    then
97
        -- Daten an den ADC senden
98
        case dacState is
99
           when idle =>
100
                   if ready = '1'
101
                then
102
                  DAC_CS <= '0';
103
                  SPI_SCK <= '0';              
104
                  -- dacCounter <= 31;
105
                  dacCounter <= 23;
106
                  -- 32 Bit Format 
107
                  -- 8Bit Dont care & Command & Address & Output & 4Bit Dont care                        
108
                  -- DAC_OUT <= "00000000" & "0010" & "1111" & output & "0000";
109
                  -- 24 Bit Format
110
                  -- Sinus auf DAC Channel A
111
                  DAC_OUT <= "0011" & "0000" & sine_out & "0000";                
112
                  dacState <= sendBit;
113
                end if;
114
           when sendBit =>
115
               
116
              SPI_SCK <= '0';
117
              -- SPI_MOSI <= DAC_OUT(31);
118
              SPI_MOSI <= DAC_OUT(23);
119
              -- DAC_OUT <= DAC_OUT(30 downto 0) & "0";
120
              DAC_OUT <= DAC_OUT(22 downto 0) & "0";
121
              dacState <= clockHigh;
122
           when clockHigh =>
123
              SPI_SCK <= '1';
124
              if dacCounter = 0 
125
              then
126
                dacState <= csHigh;
127
              else
128
                dacCounter <= dacCounter - 1;
129
                dacState <= sendBit;
130
              end if;
131
           when csHigh =>
132
              -- Digital-Analog-Wandlung
133
              DAC_CS <= '1';          
134
              dacState <= idle;             
135
        end case;
136
      
137
    end if; -- if rising_edge
138
  end process;
139
    
140
  DAC_CLR <= '1';
141
  
142
end architecture rtl;

von Kurt Georg (Gast)


Lesenswert?

Setze teiler vorerst auf 50 und generiere den DDS-Core für eine Frequenz 
von nicht mehr als 100 kHz mit Sampletakt von 1 MHz. Nähere dich der 
maximal möglichen Frequenz von unten und nicht von oben, das ist 
übersichtlicher.
Das ready gehört m.E. nicht in die Sensitivitätsliste (getakteter 
Prozess).
Experimentiere etwas mit dem Wert für teiler, der Wert 50 setzt voraus, 
der Zustandsautomat für den D/A-Wandler in 50 Takten abgelaufen ist.

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.