Forum: FPGA, VHDL & Co. DAC in VHDL für Spartan 3E


von Pusteblume (Gast)


Lesenswert?

Hallo zusammen,

ich bin ziemlicher Anfänger auf dem Gebiet FPGA. Ich möchte auf meinem 
Spartan 3e einen Sinus erzeugen und diesen mittels des DAC auf den 
J5-Headern analog abgreifen.

Der Sinus funktioniert soweit wunderbar, das Problem ist die 
Digital-Analog-Wandlung.
Ich habe mir schon das ug230 und einige Foren im Netz durchsucht, leider 
bin ich noch nicht sehr weit gekommen.

Meine Funktion hat folgenden Code:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.STD_LOGIC_ARITH.ALL;
4
use IEEE.STD_LOGIC_UNSIGNED.ALL;
5
use IEEE.numeric_std.all;
6
use work.sine_LUT.all;
7
8
---- Uncomment the following library declaration if instantiating
9
---- any Xilinx primitives in this code.
10
--library UNISIM;
11
--use UNISIM.VComponents.all;
12
13
entity Sinusgenerator is
14
    Port (   CLK : in  STD_LOGIC;
15
   
16
        SPI_SS_B   : out STD_LOGIC;
17
        AMP_CS     : out STD_LOGIC;
18
        AD_CONV     : out STD_LOGIC;
19
        SF_CE0     : out STD_LOGIC;
20
        FPGA_INIT_B : out STD_LOGIC;
21
        
22
        SPI_MOSI   : out STD_LOGIC;
23
        SPI_SCK     : out STD_LOGIC;
24
        DAC_CLR     : out STD_LOGIC;
25
        DAC_CS     : out STD_LOGIC;        
26
        
27
        SINE_OUT : out  STD_LOGIC_VECTOR (3 downto 0));
28
end Sinusgenerator;
29
30
architecture Behavioral of Sinusgenerator is
31
32
  signal table_index : table_index_type;
33
34
begin
35
36
  process(CLK)
37
  variable table_value : table_value_type;
38
  begin
39
    if rising_edge (CLK) then
40
      table_value := get_value(table_index);
41
    
42
      table_index <= table_index + 1;
43
    end if;
44
  
45
  SPI_SS_B <= '1';
46
  AMP_CS <= '1';
47
  AD_CONV <= '0';
48
  SF_CE0 <= '1';
49
  FPGA_INIT_B <= '1';
50
  
51
  SINE_OUT <= STD_LOGIC_VECTOR(to_unsigned(table_value, sine_vector_type'length));
52
  SPI_MOSI <= table_value; 
53
  
54
  SPI_SCK <= CLK;
55
  DAC_CLR <= '0';
56
  DAC_CS  <= '1'; 
57
  
58
59
  end process;  
60
  
61
    
62
end Behavioral;

Die .ucf Datei ist
1
NET "CLK" LOC = C9;
2
NET "SINE_OUT[0]" LOC = F12;
3
NET "SINE_OUT[1]" LOC = E12;
4
NET "SINE_OUT[2]" LOC = E11;
5
NET "SINE_OUT[3]" LOC = F11;
6
7
NET "SPI_SS_B"    LOC = U3;
8
NET "AMP_CS"    LOC = N7;
9
NET "AD_CONV"    LOC = P11;
10
NET "SF_CE0"    LOC = D16;
11
NET "FPGA_INIT_B" LOC = T3;
12
13
#NET "SPI_MISO"    LOC = N10  | IOSTANDARD = LVCMOS33 ;
14
NET "SPI_MOSI"    LOC = T4    | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8;
15
NET "SPI_SCK"    LOC = U16  | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8;
16
NET "DAC_CS"    LOC = N8    | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8;
17
NET "DAC_CLR"    LOC = P8    | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8;

Der Code ist wahrscheinlich schon prinzipiell falsch?
Ich hoffe jemand kann mir helfen, da ich im Moment ziemlich im Dunkeln 
tappe!

Vielen Dank schonmal...

von Na sowas (Gast)


Lesenswert?

Pusteblume schrieb:
> Der Code ist wahrscheinlich schon prinzipiell falsch?
Da sieht man schon nach 4 Zeilen:
1
use IEEE.STD_LOGIC_ARITH.ALL;
2
use IEEE.STD_LOGIC_UNSIGNED.ALL;
3
use IEEE.numeric_std.all;
Sieh dir an, welche Datentypen und Funktionen dort jeweils definiert 
sind, und welche Probleme dir das bringen kann/wird.

Kurz und Knackig: nur die
1
use IEEE.STD_LOGIC_ARITH.ALL;
2
use IEEE.STD_LOGIC_UNSIGNED.ALL;
oder viel besser, weil genormt und herstellerunabhängig die
1
use IEEE.numeric_std.all;

Gut, weiter zum nächsten Punkt:
Wozu brauchst du eine Variable?
Kannst du dir selber einen guten Grund dafür nennen?
Als Anfänger brauchst du das erste viertel Jahr garantiert keine 
Variable. Und wenn doch, dann machst du etwas falsch.

Dieser Prozess hier ist überaus ungünstig. Denn er beinhaltet einen 
getakteten Teil und einen kombinatorischen Teil.
1
  process(CLK)
2
  variable table_value : table_value_type;
3
  begin
4
    if rising_edge (CLK) then                 ------- getaktet
5
      table_value := get_value(table_index);
6
    
7
      table_index <= table_index + 1;
8
    end if;
9
  
10
  SPI_SS_B <= '1';                            ------- kombinatorisch
11
  AMP_CS <= '1';
12
  AD_CONV <= '0';
13
  SF_CE0 <= '1';
14
  FPGA_INIT_B <= '1';
15
  
16
  SINE_OUT <= STD_LOGIC_VECTOR(to_unsigned(table_value, sine_vector_type'length));
17
  SPI_MOSI <= table_value; 
18
  
19
  SPI_SCK <= CLK;
20
  DAC_CLR <= '0';
21
  DAC_CS  <= '1'; 
22
  
23
  end process;

Richtig müsste das so aussehen:
1
signal table_value : table_value_type;
2
:
3
:
4
  process(CLK)
5
  begin
6
    if rising_edge (CLK) then      ------- getaktet
7
      table_value <= get_value(table_index);
8
      table_index <= table_index + 1;
9
    end if;
10
  end process;  
11
   
12
  SPI_SS_B <= '1';                 ------- concurrent kombinatorisch
13
  AMP_CS <= '1';
14
  AD_CONV <= '0';
15
  SF_CE0 <= '1';
16
  FPGA_INIT_B <= '1';
17
  
18
  SINE_OUT <= STD_LOGIC_VECTOR(to_unsigned(table_value, sine_vector_type'length));
19
  SPI_MOSI <= table_value; 
20
  
21
  SPI_SCK <= CLK;  ----- kann das dein FPGA überhaupt? Einen Takt auf einem Pin ausgeben?
22
  DAC_CLR <= '0';
23
  DAC_CS  <= '1';

> das ug230 und einige Foren im Netz durchsucht
Wie wäre es mit dem Datenblatt des DACs?
Dort steht das Timing, das du einhalten mußt.



> Meine Funktion hat folgenden Code...
Und jetzt müsste kommen:
>>>>> Das ist die Testbench dazu... <<<<<<

Stattdessen kommt:
> Die .ucf Datei ist...
Diese Vorgehensweise ist falsch. Du mußt zuerst mal das Verhalten 
deiner Beschreibung kontrollieren. Wenn die passt, dann kann man mal ans 
Implementieren in realer Hardware denken.

von Anguel S. (anguel)


Lesenswert?

Guckst Du auch hier:

Beitrag "Spartan 3e - DAC"

von Kim33 (Gast)


Lesenswert?

Danke schonmal für die Kommentare.

Ich habe meinen Code noch einmal umgeschrieben.
1
entity Converter is
2
    Port (   CLK   : in  STD_LOGIC;
3
   
4
        CS   : out STD_LOGIC;
5
        SYNC   : out STD_LOGIC;
6
        SCLK   : out STD_LOGIC;       -- DAC
7
 
8
        dout   : out  STD_LOGIC;    -- DAC
9
        
10
        -- Disabled Devices on the SPI Bus
11
        SPI_SS_B   : out STD_LOGIC;
12
        AMP_CS     : out STD_LOGIC;
13
        AD_CONV     : out STD_LOGIC;
14
        SF_CE0     : out STD_LOGIC;
15
        FPGA_INIT_B : out STD_LOGIC);
16
end Converter;
17
18
architecture Behavioral of Converter is
19
20
  type state_type is (read, write);            -- Statemachine with 4 states
21
  signal state : state_type := read;            -- first state = read
22
23
  -- internal signals
24
  signal table_index   : table_index_type;          -- x_value of Sine-Wave
25
  signal data        : STD_LOGIC_VECTOR(11 downto 0);    -- data in Sine-Wave
26
  signal cnt         : integer range 0 to 32 := 0;
27
  signal newclk       : STD_LOGIC := '0';
28
  signal reset       : STD_LOGIC := '0';
29
  
30
  
31
begin
32
  -- drive the DAC clock pins
33
  SCLK     <= newclk;
34
  SPI_SS_B <= '1';
35
  AMP_CS   <= '1';
36
  AD_CONV   <= '0';
37
  SF_CE0   <= '1';
38
  FPGA_INIT_B <= '1';
39
  
40
41
  converter : process(CLK, reset)
42
    -- internal variables
43
    variable temp : integer;
44
    variable table_value : table_value_type;
45
  
46
  begin
47
    if(reset = '1') then
48
    elsif(rising_edge(CLK)) then
49
      case state is
50
        
51
        -- read state: read 12 Bits from Source
52
        when read =>
53
          CS <= '0';
54
          SYNC <= '1';
55
          if(cnt < 8) then                -- stay for 4 cycles in read-mode without doing anything. 
56
            cnt <= cnt + 1;
57
                                    -- read out 12 Bits from Source (MSB first)
58
            table_value := get_value(table_index);
59
    
60
            table_index <= table_index + 1;
61
            
62
            data <= STD_LOGIC_VECTOR(to_unsigned(table_value, sine_vector_type'length));
63
            state <= read;
64
          elsif (cnt = 8) then            -- got all data --> goto next state
65
            state <= write;
66
          end if;
67
        
68
        
69
        -- write state: outout of the results
70
        when write =>
71
          CS <= '1';
72
          SYNC <= '0';
73
          if (cnt = 8 or cnt = 9) then          -- send Command '0011'
74
            cnt <= cnt + 1;
75
            dout <= '0';
76
            state <= write;
77
          elsif (cnt = 10 or cnt = 11) then      -- send Command '0011'
78
            cnt <= cnt + 1;
79
            dout <= '1';
80
            state <= write;
81
          elsif (cnt = 12 or cnt = 13 or cnt = 14 or cnt = 15) then      -- send Address to select the output channels
82
            cnt <= cnt + 1;
83
            dout <= '0';
84
            state <= write;
85
          elsif(cnt > 15 and cnt < 28) then      -- output: 12 Databits (MSB first)
86
            cnt <= cnt + 1;
87
            dout <= data(27 - cnt);
88
            state <= write;
89
          elsif(cnt > 27 and cnt < 32) then      -- output: 4 don't cares
90
            cnt <= cnt + 1;
91
            state <= write;
92
          else
93
            cnt <= 0;                    -- return to write mode
94
            state <= read;
95
          end if;
96
      end case;
97
    end if;
98
  end process converter;
99
  
100
end Behavioral;

Der Code kann nun ohne Fehler implementiert werden.
Jedoch kommt der gewünschte Ausgang nicht an meinem DAC an. Das heißt 
mit dem Oszi kann ich kein Signal erkennen.

Wo liegt denn der Fehler, ich hoffe es kann mir jemand weiter helfen?

Grüße

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Kim33 schrieb:
> Das heißt mit dem Oszi kann ich kein Signal erkennen.
Auf dout?
Was sagt die Simulation?
Hast du dout einem Pin zugewiesen?

BTW: warum verwendest du für eine serielle synchrone Kommunikation nicht 
einfach ein Schieberegister? Dort lädst du ganz einfach den gesamten 
Bitstrom rein und schiebst das dann mit jedem Takt eins weiter. Damit 
ersparst du dir die ganzen Zählermanipulationen und insbesondere den 
aufwendigen Multiplexer und die Subtraktion in der Zeile
1
dout <= data(27 - cnt);
So in etwa wie auf meiner HP:
http://www.lothar-miller.de/s9y/categories/45-SPI-Master

von Kim33 (Gast)


Lesenswert?

Hallo,

zunächst danke für die schnelle Antwort.
Ich habe dout einem Pin zugewiesen:
1
NET "CLK" LOC = C9;
2
NET "CS" LOC = N8;
3
NET "SCLK" LOC = U16;
4
NET "SYNC" LOC = P8;
5
NET "dout" LOC = T4;
6
NET "AD_CONV" LOC = P11;
7
NET "AMP_CS" LOC = N7;
8
NET "FPGA_INIT_B" LOC = T3;
9
NET "SF_CE0" LOC = D16;
10
NET "SPI_SS_B" LOC = U3;

Die Simulation ergibt bei mir einen Fehler:
   ERROR:Simulator:861 - Failed to link the design
   Error: fuse executable failed
Kann das daran liegen, dass ich keine TB geschrieben habe?

Das mit dem Schieberegister werde ich mir anschauen. Ist bestimmt ne 
bessere Idee als meine, das Problem mit dem DAC wird es aber nicht 
lösen?

Was könnte ich denn noch tun?

Grüße

von Duke Scarring (Gast)


Lesenswert?

Kim33 schrieb:
> Was könnte ich denn noch tun?

Erstmal eine Testbench schreiben. Erst wenn die Simulation läuft, kannst 
Du auf die Hardware gehen.

Duke

P.S.: Mit Testbench hätten auch wir eine Chance nachzuvollziehen, was 
Dein Code macht.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Kann das daran liegen, dass ich keine TB geschrieben habe?
Ähm... erwartest du dazu eine Antwort?
Eine Simulation besteht aus deinem Modul und einer Testbench.

> Was könnte ich denn noch tun?
Simulier das Modul erst mal. Vergleiche dann das Timing der Simulation 
mit dem Datenblatt des DAC.
Gerade solche einfachen Module lassen sich schön und übersichtlich sogar 
als Waveform darstellen. Da sieht man sofort, ob irgendwas nicht 
passt...

>> Das heißt mit dem Oszi kann ich kein Signal erkennen.
Auf dout?  Oder am Ausgang des DAC?

von Kim33 (Gast)


Lesenswert?

Ich habe eine einfache Testbench geschrieben. Diese passiert den 
Syntaxtest ohne Fehler jedoch kommt bei der Simulation ein Fehler:

ERROR:Simulator:861 - Failed to link the design
Error: fuse executable failed

Woher kann dieser kommen? Kann dies an einem prinzipiellen Problem in 
meinem Projekt liegen oder ein Anwendungsfehler?

Vielen Dank für die Hilfe!

Hier noch meine TB:
1
LIBRARY ieee;
2
USE ieee.std_logic_1164.ALL;
3
USE ieee.std_logic_unsigned.all;
4
USE ieee.numeric_std.ALL;
5
 
6
ENTITY Testbench IS
7
END Testbench;
8
 
9
ARCHITECTURE behavior OF Testbench IS 
10
 
11
    -- Component Declaration for the Unit Under Test (UUT)
12
 
13
    COMPONENT Converter
14
    PORT(
15
         CLK : IN  std_logic;
16
      
17
         CS : OUT  std_logic;
18
         SYNC : OUT  std_logic;
19
         SCLK : OUT  std_logic;
20
         dout : OUT  std_logic;
21
         SPI_SS_B : OUT  std_logic;
22
         AMP_CS : OUT  std_logic;
23
         AD_CONV : OUT  std_logic;
24
         SF_CE0 : OUT  std_logic;
25
         FPGA_INIT_B : OUT  std_logic
26
        );
27
    END COMPONENT;
28
    
29
30
   --Inputs
31
   signal CLK : std_logic := '0';
32
33
   --Outputs
34
   signal CS : std_logic;
35
   signal SYNC : std_logic;
36
   signal SCLK : std_logic;
37
   signal dout : std_logic;
38
   signal SPI_SS_B : std_logic;
39
   signal AMP_CS : std_logic;
40
   signal AD_CONV : std_logic;
41
   signal SF_CE0 : std_logic;
42
   signal FPGA_INIT_B : std_logic;
43
 
44
BEGIN
45
46
  clk <= not clk after 20 ns;
47
 
48
  -- Instantiate the Unit Under Test (UUT)
49
   uut: Converter PORT MAP (
50
          CLK => CLK,
51
          CS => CS,
52
          SYNC => SYNC,
53
          SCLK => SCLK,
54
          dout => dout,
55
          SPI_SS_B => SPI_SS_B,
56
          AMP_CS => AMP_CS,
57
          AD_CONV => AD_CONV,
58
          SF_CE0 => SF_CE0,
59
          FPGA_INIT_B => FPGA_INIT_B
60
        );
61
 
62
 
63
END;

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

1
LIBRARY ieee;
2
USE ieee.std_logic_1164.ALL;
3
USE ieee.std_logic_unsigned.all;
4
USE ieee.numeric_std.ALL;
Viel hilft viel, oder wie?
Schreib da mal besser nur
1
LIBRARY ieee;
2
USE ieee.std_logic_1164.ALL;
3
USE ieee.numeric_std.ALL;
sonst hast du ein paar Funktionsdefinitonen doppelt drin...


>  jedoch kommt bei der Simulation ein Fehler:
Welcher Simulator?
Ist das Projekt richtig aufgesetzt?

von Kim33 (Gast)


Lesenswert?

Ich versuche das ganze mit der ISE von Xilinx zu Simulieren.

Lothar Miller schrieb:
>>> Das heißt mit dem Oszi kann ich kein Signal erkennen.
> Auf dout?  Oder am Ausgang des DAC?

Ich möchte das Signal dout auf den Ausgang des DACs (A) leiten und von 
dort mit dem Oszi abgreifen. Jedoch fehlt mir dazu eine UCF-Loc-Angabe!

Ich denke schon, dass das Projekt richtig aufgesetzt ist. Wie erkenne 
ich, ob es das nicht ist?

Grüße und vielen Dank!

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Wie erkenne ich, ob es das nicht ist?
Dass du Fehler bekommst...

> Ich möchte das Signal dout auf den Ausgang des DACs (A) leiten und von
> dort mit dem Oszi abgreifen. Jedoch fehlt mir dazu eine UCF-Loc-Angabe!
Du selbst hast dout doch lokalisiert (T4)  :-o

Das weitere Vorgehen muß sein:
1. Simulation
2. Synthese und Kontrolle des dout Signals
3. Kontrolle am DAC-Ausgang
Wenn bei 1. die Signale mit dem Datenblatt übereinstimmen, und bei 2. 
der entsprechende Bitstrom herauskommt, dann funktioniert automatisch 
auch 3.

von Kim33 (Gast)


Lesenswert?

danke für die schnelle Antwort.

Lothar Miller schrieb:
>> Wie erkenne ich, ob es das nicht ist?
> Dass du Fehler bekommst...
Fehler bekomme ich keine, außer den besagten bei der Simulation. Die 
Implementierung läuft fehlerfrei ab.
Auch die Analyse in ChipScope Pro liefert das gewünschte Ergebnis.


Lothar Miller schrieb:
>> Ich möchte das Signal dout auf den Ausgang des DACs (A) leiten und von
>> dort mit dem Oszi abgreifen. Jedoch fehlt mir dazu eine UCF-Loc-Angabe!
> Du selbst hast dout doch lokalisiert (T4)  :-o

Ist T4 die richtige Pin-Loc für den DAC. Da bin ich mir nämlich nicht so 
sicher. Im Datenblatt steht, das dies der Eingang des Slaves ist (also 
meines DACs). Ich kann jedoch keine Pin-Loc für den DAC-Ausgang im 
Datenblatt finden.


Die Simulation läuft immer noch nicht aufgrund dieses Fehlers:
Waiting for 1 sub-compilation(s) to finish...
ERROR:Simulator:861 - Failed to link the design
Error: fuse executable failed

Woher kann dies kommen?

Grüße

von Kim33 (Gast)


Lesenswert?

Die Simulation läuft jetzt.
Vielen Dank an deine Mühe.
Ich werde nun versuchen die anderen Fragen mithilfe der Simulation zu 
klären!

Grüße

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Die Simulation läuft jetzt.
Gut.

>> Ich kann jedoch keine Pin-Loc für den DAC-Ausgang im Datenblatt finden.
Das wirst du auch mit ausgiebigster Suche nicht schaffen, denn der 
Analogausgang des DACs hat überhaupt nichts mehr mit dem FPGA zu tun...

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.