mikrocontroller.net

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


Autor: Pusteblume (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.numeric_std.all;
use work.sine_LUT.all;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Sinusgenerator is
    Port (   CLK : in  STD_LOGIC;
   
        SPI_SS_B   : out STD_LOGIC;
        AMP_CS     : out STD_LOGIC;
        AD_CONV     : out STD_LOGIC;
        SF_CE0     : out STD_LOGIC;
        FPGA_INIT_B : out STD_LOGIC;
        
        SPI_MOSI   : out STD_LOGIC;
        SPI_SCK     : out STD_LOGIC;
        DAC_CLR     : out STD_LOGIC;
        DAC_CS     : out STD_LOGIC;        
        
        SINE_OUT : out  STD_LOGIC_VECTOR (3 downto 0));
end Sinusgenerator;

architecture Behavioral of Sinusgenerator is

  signal table_index : table_index_type;

begin

  process(CLK)
  variable table_value : table_value_type;
  begin
    if rising_edge (CLK) then
      table_value := get_value(table_index);
    
      table_index <= table_index + 1;
    end if;
  
  SPI_SS_B <= '1';
  AMP_CS <= '1';
  AD_CONV <= '0';
  SF_CE0 <= '1';
  FPGA_INIT_B <= '1';
  
  SINE_OUT <= STD_LOGIC_VECTOR(to_unsigned(table_value, sine_vector_type'length));
  SPI_MOSI <= table_value; 
  
  SPI_SCK <= CLK;
  DAC_CLR <= '0';
  DAC_CS  <= '1'; 
  

  end process;  
  
    
end Behavioral;

Die .ucf Datei ist
NET "CLK" LOC = C9;
NET "SINE_OUT[0]" LOC = F12;
NET "SINE_OUT[1]" LOC = E12;
NET "SINE_OUT[2]" LOC = E11;
NET "SINE_OUT[3]" LOC = F11;

NET "SPI_SS_B"    LOC = U3;
NET "AMP_CS"    LOC = N7;
NET "AD_CONV"    LOC = P11;
NET "SF_CE0"    LOC = D16;
NET "FPGA_INIT_B" LOC = T3;

#NET "SPI_MISO"    LOC = N10  | IOSTANDARD = LVCMOS33 ;
NET "SPI_MOSI"    LOC = T4    | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8;
NET "SPI_SCK"    LOC = U16  | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8;
NET "DAC_CS"    LOC = N8    | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8;
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...

Autor: Na sowas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Pusteblume schrieb:
> Der Code ist wahrscheinlich schon prinzipiell falsch?
Da sieht man schon nach 4 Zeilen:
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
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
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
oder viel besser, weil genormt und herstellerunabhängig die
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.
  process(CLK)
  variable table_value : table_value_type;
  begin
    if rising_edge (CLK) then                 ------- getaktet
      table_value := get_value(table_index);
    
      table_index <= table_index + 1;
    end if;
  
  SPI_SS_B <= '1';                            ------- kombinatorisch
  AMP_CS <= '1';
  AD_CONV <= '0';
  SF_CE0 <= '1';
  FPGA_INIT_B <= '1';
  
  SINE_OUT <= STD_LOGIC_VECTOR(to_unsigned(table_value, sine_vector_type'length));
  SPI_MOSI <= table_value; 
  
  SPI_SCK <= CLK;
  DAC_CLR <= '0';
  DAC_CS  <= '1'; 
  
  end process;  

Richtig müsste das so aussehen:
signal table_value : table_value_type;
:
:
  process(CLK)
  begin
    if rising_edge (CLK) then      ------- getaktet
      table_value <= get_value(table_index);
      table_index <= table_index + 1;
    end if;
  end process;  
   
  SPI_SS_B <= '1';                 ------- concurrent kombinatorisch
  AMP_CS <= '1';
  AD_CONV <= '0';
  SF_CE0 <= '1';
  FPGA_INIT_B <= '1';
  
  SINE_OUT <= STD_LOGIC_VECTOR(to_unsigned(table_value, sine_vector_type'length));
  SPI_MOSI <= table_value; 
  
  SPI_SCK <= CLK;  ----- kann das dein FPGA überhaupt? Einen Takt auf einem Pin ausgeben?
  DAC_CLR <= '0';
  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.

Autor: Anguel S. (anguel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guckst Du auch hier:

Beitrag "Spartan 3e - DAC"

Autor: Kim33 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke schonmal für die Kommentare.

Ich habe meinen Code noch einmal umgeschrieben.
entity Converter is
    Port (   CLK   : in  STD_LOGIC;
   
        CS   : out STD_LOGIC;
        SYNC   : out STD_LOGIC;
        SCLK   : out STD_LOGIC;       -- DAC
 
        dout   : out  STD_LOGIC;    -- DAC
        
        -- Disabled Devices on the SPI Bus
        SPI_SS_B   : out STD_LOGIC;
        AMP_CS     : out STD_LOGIC;
        AD_CONV     : out STD_LOGIC;
        SF_CE0     : out STD_LOGIC;
        FPGA_INIT_B : out STD_LOGIC);
end Converter;

architecture Behavioral of Converter is

  type state_type is (read, write);            -- Statemachine with 4 states
  signal state : state_type := read;            -- first state = read

  -- internal signals
  signal table_index   : table_index_type;          -- x_value of Sine-Wave
  signal data        : STD_LOGIC_VECTOR(11 downto 0);    -- data in Sine-Wave
  signal cnt         : integer range 0 to 32 := 0;
  signal newclk       : STD_LOGIC := '0';
  signal reset       : STD_LOGIC := '0';
  
  
begin
  -- drive the DAC clock pins
  SCLK     <= newclk;
  SPI_SS_B <= '1';
  AMP_CS   <= '1';
  AD_CONV   <= '0';
  SF_CE0   <= '1';
  FPGA_INIT_B <= '1';
  

  converter : process(CLK, reset)
    -- internal variables
    variable temp : integer;
    variable table_value : table_value_type;
  
  begin
    if(reset = '1') then
    elsif(rising_edge(CLK)) then
      case state is
        
        -- read state: read 12 Bits from Source
        when read =>
          CS <= '0';
          SYNC <= '1';
          if(cnt < 8) then                -- stay for 4 cycles in read-mode without doing anything. 
            cnt <= cnt + 1;
                                    -- read out 12 Bits from Source (MSB first)
            table_value := get_value(table_index);
    
            table_index <= table_index + 1;
            
            data <= STD_LOGIC_VECTOR(to_unsigned(table_value, sine_vector_type'length));
            state <= read;
          elsif (cnt = 8) then            -- got all data --> goto next state
            state <= write;
          end if;
        
        
        -- write state: outout of the results
        when write =>
          CS <= '1';
          SYNC <= '0';
          if (cnt = 8 or cnt = 9) then          -- send Command '0011'
            cnt <= cnt + 1;
            dout <= '0';
            state <= write;
          elsif (cnt = 10 or cnt = 11) then      -- send Command '0011'
            cnt <= cnt + 1;
            dout <= '1';
            state <= write;
          elsif (cnt = 12 or cnt = 13 or cnt = 14 or cnt = 15) then      -- send Address to select the output channels
            cnt <= cnt + 1;
            dout <= '0';
            state <= write;
          elsif(cnt > 15 and cnt < 28) then      -- output: 12 Databits (MSB first)
            cnt <= cnt + 1;
            dout <= data(27 - cnt);
            state <= write;
          elsif(cnt > 27 and cnt < 32) then      -- output: 4 don't cares
            cnt <= cnt + 1;
            state <= write;
          else
            cnt <= 0;                    -- return to write mode
            state <= read;
          end if;
      end case;
    end if;
  end process converter;
  
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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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
dout <= data(27 - cnt);
So in etwa wie auf meiner HP:
http://www.lothar-miller.de/s9y/categories/45-SPI-Master

Autor: Kim33 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

zunächst danke für die schnelle Antwort.
Ich habe dout einem Pin zugewiesen:
NET "CLK" LOC = C9;
NET "CS" LOC = N8;
NET "SCLK" LOC = U16;
NET "SYNC" LOC = P8;
NET "dout" LOC = T4;
NET "AD_CONV" LOC = P11;
NET "AMP_CS" LOC = N7;
NET "FPGA_INIT_B" LOC = T3;
NET "SF_CE0" LOC = D16;
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

Autor: Duke Scarring (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Kim33 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
 
ENTITY Testbench IS
END Testbench;
 
ARCHITECTURE behavior OF Testbench IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT Converter
    PORT(
         CLK : IN  std_logic;
      
         CS : OUT  std_logic;
         SYNC : OUT  std_logic;
         SCLK : OUT  std_logic;
         dout : OUT  std_logic;
         SPI_SS_B : OUT  std_logic;
         AMP_CS : OUT  std_logic;
         AD_CONV : OUT  std_logic;
         SF_CE0 : OUT  std_logic;
         FPGA_INIT_B : OUT  std_logic
        );
    END COMPONENT;
    

   --Inputs
   signal CLK : std_logic := '0';

   --Outputs
   signal CS : std_logic;
   signal SYNC : std_logic;
   signal SCLK : std_logic;
   signal dout : std_logic;
   signal SPI_SS_B : std_logic;
   signal AMP_CS : std_logic;
   signal AD_CONV : std_logic;
   signal SF_CE0 : std_logic;
   signal FPGA_INIT_B : std_logic;
 
BEGIN

  clk <= not clk after 20 ns;
 
  -- Instantiate the Unit Under Test (UUT)
   uut: Converter PORT MAP (
          CLK => CLK,
          CS => CS,
          SYNC => SYNC,
          SCLK => SCLK,
          dout => dout,
          SPI_SS_B => SPI_SS_B,
          AMP_CS => AMP_CS,
          AD_CONV => AD_CONV,
          SF_CE0 => SF_CE0,
          FPGA_INIT_B => FPGA_INIT_B
        );
 
 
END;

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
Viel hilft viel, oder wie?
Schreib da mal besser nur
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
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?

Autor: Kim33 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Kim33 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Kim33 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.