Wr hat schon einmal den DA und den AD-Wandler auf dem Spartan 3 Starter Kit angesteuert ? Ich habe mit Mühe und Not im Internet ein Beispiel zur DA-Ausgabe gefunden, welches jedoch nicht funktioniert. Das von mir erwartete Rechtecksignal erscheint leider nicht am Oszi. Hat jemand ein funktionierendes Beispiel ?
Poste hier doch einfach mal deinen Code - ich denke dann bekommst du mehr Antworten... Ich habe schon mal DACs mit einem XC9572 angesteuert - vielleicht kann ich ja was zu deinem VHDL-Code sagen...
Na schön. Hier die Entity für die Ausgabe an den DA-Wandler. Alles andere habe ich weggelassen. Es geht um den letzten Prozess. "output" enthält den 12bit Wert der ausgegeben werden soll. Bis auf den Ausgang des DA-Wandlers kann ich ja alles mittels Simulation überprüfen. Danach geht es nur per Hardware (Oszi).
1 | library ieee; |
2 | use ieee.std_logic_1164.all; |
3 | use ieee.numeric_std.all; |
4 | use work.sine_package.all; |
5 | |
6 | entity adc_out is |
7 | port ( |
8 | clock : in std_logic; |
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 | BTN_SOUTH : in std_logic; -- enable |
15 | BTN_EAST : in std_logic; -- reset |
16 | Rot_Center : in std_logic |
17 | );
|
18 | end entity adc_out; |
19 | |
20 | architecture rtl of adc_out is |
21 | |
22 | component sekunden_takt |
23 | port
|
24 | (
|
25 | clock : in std_logic; |
26 | takt : out std_logic |
27 | );
|
28 | end component sekunden_takt; |
29 | |
30 | component square_wave |
31 | port ( |
32 | clock : in std_logic; -- Systemclock Pin |
33 | wave_out : out signed(11 downto 0) |
34 | );
|
35 | end component square_wave; |
36 | |
37 | component sine_wave |
38 | port
|
39 | (
|
40 | clock : in std_logic; |
41 | reset : in std_logic; |
42 | enable : in std_logic; |
43 | wave_out : out signed(11 downto 0) |
44 | );
|
45 | end component sine_wave; |
46 | |
47 | type wave_mod is (sine_wave_mod, square_wave_mod); |
48 | signal modus : wave_mod := square_wave_mod; |
49 | |
50 | type dacStateType is (idle, sendBit, clockHigh, csHigh); |
51 | signal dacState : dacStateType := idle; |
52 | signal enable : std_logic := '1'; |
53 | signal old_BTN_SOUTH : std_logic; |
54 | signal old_Rot_Center : std_logic; |
55 | signal reset : std_logic := '0'; |
56 | signal sine_wave_out : signed(11 downto 0); |
57 | signal square_wave_out : signed(11 downto 0); |
58 | signal output : unsigned(11 downto 0); |
59 | -- 32 Bit Format
|
60 | signal dacCounter : integer range 0 to 31; |
61 | signal DAC_OUT : unsigned(31 downto 0); |
62 | signal takt : std_logic; |
63 | |
64 | begin
|
65 | |
66 | takt_teiler : sekunden_takt |
67 | port map |
68 | (
|
69 | clock => clock, |
70 | takt => takt |
71 | );
|
72 | |
73 | square_wave_label : square_wave |
74 | port map |
75 | (
|
76 | clock => clock, |
77 | wave_out => square_wave_out |
78 | );
|
79 | |
80 | sine_wave_label : sine_wave |
81 | port map |
82 | (
|
83 | clock => clock, |
84 | reset => BTN_EAST, |
85 | enable => enable, |
86 | wave_out => sine_wave_out |
87 | );
|
88 | |
89 | ----------------------------------------------------------------------------------------
|
90 | |
91 | process (clock, BTN_SOUTH) |
92 | begin
|
93 | if rising_edge(clock) |
94 | then
|
95 | old_BTN_SOUTH <= BTN_SOUTH; |
96 | -- Erkennung der steigenden Flanke
|
97 | if old_BTN_SOUTH = '0' and BTN_SOUTH = '1' |
98 | then
|
99 | if enable = '0' |
100 | then
|
101 | enable <= '1'; |
102 | else
|
103 | enable <= '0'; |
104 | end if; |
105 | end if; |
106 | end if; |
107 | end process; |
108 | |
109 | process (clock, BTN_EAST) |
110 | begin
|
111 | if rising_edge(clock) |
112 | then
|
113 | if BTN_EAST = '1' |
114 | then
|
115 | reset <= not reset; |
116 | end if; |
117 | end if; |
118 | end process; |
119 | |
120 | ----------------------------------------------------------------------------------------
|
121 | |
122 | leds : process (clock) |
123 | begin
|
124 | if rising_edge(clock) |
125 | then
|
126 | if modus = square_wave_mod |
127 | then
|
128 | led(7 downto 6) <= "10"; |
129 | elsif modus = sine_wave_mod |
130 | then
|
131 | led(7 downto 6) <= "01"; |
132 | end if; |
133 | led(5 downto 2) <= "0000"; |
134 | led(1) <= enable; |
135 | led(0) <= reset; |
136 | end if; |
137 | end process; |
138 | |
139 | -- rotary_knob : process (clock)
|
140 | -- begin
|
141 | -- if rising_edge(clock)
|
142 | -- then
|
143 | -- old_Rot_Center <= Rot_Center;
|
144 | -- -- Erkennung der Taktflanke
|
145 | -- if old_Rot_Center = '0' and Rot_Center = '1'
|
146 | -- then
|
147 | -- if modus /= wave_mod'high
|
148 | -- then
|
149 | -- modus <= wave_mod'succ(modus);
|
150 | -- else
|
151 | -- modus <= wave_mod'low;
|
152 | -- end if;
|
153 | -- end if;
|
154 | -- end if;
|
155 | -- end process;
|
156 | |
157 | ----------------------------------------------------------------------------------------
|
158 | |
159 | process(clock, enable) |
160 | begin
|
161 | if enable = '0' |
162 | then
|
163 | dacState <= idle; |
164 | elsif rising_edge(clock) |
165 | then
|
166 | -- Wellenform berücksichtigen
|
167 | if modus = sine_wave_mod |
168 | then
|
169 | output <= unsigned(sine_wave_out); |
170 | elsif modus = square_wave_mod |
171 | then
|
172 | output <= unsigned(square_wave_out); |
173 | end if; |
174 | |
175 | -- Daten an den ADC senden
|
176 | case dacState is |
177 | when idle => |
178 | -- if takt = '1'
|
179 | -- then
|
180 | DAC_CS <= '0'; |
181 | SPI_SCK <= '0'; |
182 | dacState <= sendBit; |
183 | dacCounter <= 31; |
184 | -- 32 Bit Format
|
185 | -- 4Bit Dont care & output & Address & Command & 8Bit Dont care
|
186 | DAC_OUT <= "0000" & output & "1111" & "0011" & "00000000"; |
187 | -- end if;
|
188 | when sendBit => |
189 | SPI_SCK <= '0'; |
190 | -- SPI_MOSI <= DAC_OUT(23);
|
191 | SPI_MOSI <= DAC_OUT(31); |
192 | DAC_OUT <= DAC_OUT(30 downto 0) & "0"; |
193 | dacState <= clockHigh; |
194 | when clockHigh => |
195 | SPI_SCK <= '1'; |
196 | if dacCounter = 0 |
197 | then
|
198 | dacState <= csHigh; |
199 | else
|
200 | dacCounter <= dacCounter - 1; |
201 | dacState <= sendBit; |
202 | end if; |
203 | when csHigh => |
204 | DAC_CS <= '1'; |
205 | dacState <= idle; |
206 | end case; |
207 | end if; |
208 | end process; |
209 | |
210 | DAC_CLR <= '1'; |
211 | |
212 | end architecture rtl; |
Hans-Werner, du hast zwei Probleme zu lösen, die du klar voneinander trennen musst: 1. Stelle den Ausgabewert bereit, und zwar nicht schneller, als der D/A-Wandler kann. Z.B. zum Anfang alle 10 Mikrosekunden einen Neuen. 2. Sobald ein neuer Ausgabewert bereitsteht, triggere einen Zustandsautomaten, der den Ausgabewert an den D/A-Wandler raustaktet. Der Zustandsautomat könnte mit folgenden Zuständen arbeiten (nur ungefähr, da ich die genauen Notwendigkeiten für deine D/A-Wandler nicht kenne): a) idle b) Zusammenstellung der auszugebenden Bitfolge c) Ausgabe eines Bits mit Takt L (oder umgekehrt) d) Takt H (oder umgekehrt) ----(c) und d) werden so oft wiederholt, wie Bits in der Bitfolge, dazu brauchst du einen Zähler 0 bis 23 (oder ähnlich) e) Rückkehr in a) Der Übergang von a) nach b) erfolgt, wenn ein neuer Ausgabewert bereitsteht. In jedem Zustand sind die Steuersignale an den D/A-Wandler definiert. Schaffe dir Debug-Möglichkeiten, dass du z.B. siehst, wie oft ein neuer Ausgabewert erscheint. Prüfe, ob die Steuersignale an den D/A-WAndler ok sind (siehe dessen Datenblatt). Viel Erfolg!
Ich muß Kurt Georg noch ergänzen: Schreibe Dir eine Testbench, die u.a. so tut als wenn sie ein DA-Wandler wäre. Die muß auch nicht synthetisierbar sein. Damit kannst Du erstmal solange simulieren/rumnspielen, bis dein "DA-Wandler" was erkennt. Duke
1 | entity dac_spi is |
2 | port ( |
3 | SPI_SCK : in std_logic; |
4 | SPI_MOSI : in std_logic; |
5 | DAC_CLR : in std_logic; |
6 | DAC_CS : in std_logic |
7 | );
|
8 | end entity dac_spi; |
9 | |
10 | architecture testbench of dac_spi is |
11 | begin
|
12 | ...
|
13 | process (DAC_CS, DAC_CLR. SPI_SCK, SPI_MOSI) |
14 | variable out_value : integer := 0; |
15 | variable old_value : integer := integer'low; |
16 | begin
|
17 | if DAC_CS = '0' then -- low active |
18 | if DAC_CLR = '0' then |
19 | out_value := 0; |
20 | else
|
21 | -- catch here new output value
|
22 | -- google for spi slave or something
|
23 | out_value := ...; |
24 | end if; |
25 | end if; |
26 | |
27 | if old_value /= out_value then |
28 | report "new DAC output value: " & integer'image(out_value); |
29 | old_value := out_value; |
30 | end if; |
31 | |
32 | end process; |
33 | |
34 | end architecture testbench; |
Ja, Testbench ist vorhanden. Inzwischen habe ich auch ein Signal auf dem Oszi. Ich hatte die Bits in der verkehrten Reihenfolge an den DAC geschoben. Ist aber noch nicht der erwartete Sinus, sieht eher wie eine Überlagerung mehrerer Sinusschwingungen aus. Könnte natürlich sein das ich den DAC zu schnell ansteuere. Momentan gebe ich alle 1/(50MHz/256) Sekunden einen 24 Bit Wert aus. Die einzelnen Bits werden mit 50 MHZ getaktet. Wann muss ich das Clear Signal (Aktive Low) zum Rücksetzen der DAC Ausgänge auf 0 Volt setzen ? Ist dieses überhaupt erforderlich ?
Mir ist mal wieder ein Kronleuchter aufgegangen. Der Sinus ist in einer Tabelle enthalten. Jeden 50 MHz Takt wird ein Wert gelesen. Der DA Wandler benötigt im 24bit Format für die Umsetzung der 12bit jedoch 48 Takte. Daher wird aus der Tabelle nur jeder 48 Eintrag verwendet. Bei 128 Einträgen für einen Quadranten werden somit nur 2-3 Werte je Quadrant in den entsprechenden Analogwert ungesetzt. Daher das verstümmelte Ausgangssignal. Das kann nicht funktionieren. Der Prozess für die DA-Wandlung muss sich nach jeder Wandlung den nächsten Wert aus der Tabelle holen. Noch eine Frage an alle Intelligenzbestien: Wie kann ich eine Sinusschwingung mit unterschiedlichen Frequenzen ausgeben ? a) Jeweils n Werte in der Tabelle überspringen. Der Sinus wird immer ungenauer. b) Die Tabelle mit einem schnelleren Takt auslesen. Für jede Ausgabefrequenz würde dadurch ein eigener Taktgenerator benötigt. Man könnte mit einem DCM einen sehr hohen Takt erzeugen und diesen dann unterschiedlich teilen. c) Noch andere Ideen ?
@Hans-Werner: 1. Wer eine (richtige) Testbench (tm) hat, braucht kein Oszi :-( 2. Für verschiedene Frequenzen such mal nach den Stichworten DDS und phase accumulator. Duke
> a) Jeweils n Werte in der Tabelle überspringen. > b) Die Tabelle mit einem schnelleren Takt auslesen. Eine Kombination aus a) und b) wird zum Erfolg führen. Die Stichworte dazu wurden schon genannt. > Ich hatte die Bits in der verkehrten Reihenfolge an den DAC geschoben. Das hätte man schon mit einer einfachen TB erkannt... > Wer eine (richtige) Testbench (tm) hat, braucht kein Oszi :-( Naja, dann muß die Simulation aber schon tief ins Layout gehen... Aber mit einer TB spart man sich oft das Einschalten des Oszis ;-)
> Der Sinus wird immer ungenauer.
Deswegen brauchst du ja auch ein analoges Tiefpassfilter hinter dem
D/A-Wandler. Dieses Filter sollte alles oberhalb der halben Samplerate
wegfiltern.
halo hanz-werner, kannst du auch bitte die codes deiner drei componenten jeweils posten.. danke schonmal im voraus gruss: Franz
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.