Forum: FPGA, VHDL & Co. Der vhdl-Schnipsel-Anfängerfragen Thread


von J.H. (Gast)


Lesenswert?

Ich mache einfach mal so einen thread auf, wo Anfänger wie ich einfach 
kompakte, kleine und schnell zu beantwortende fragen reinstellen.
Soll ein zumüllen der Übersicht verhindern - kA obs klappt.

Fange also mal an: meine aktuelle Frage bezieht sich auf folgendes. 
Sinnlose Ideen zu haben ist gar nicht so leicht, aber ich versuche mini 
problemchen auszuprobieren. Vielleicht wachsen die ja mal zu einem 
großen Projekt an.
Also der Versuch aus einer Adresse "A" ein Chipselect zu erzeugen. mehr 
nicht. Sollen an 8 Adressen 2 Teilnehmer der Länge 7 hängen. na gut.
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
6
entity codier1 is
7
    Port ( A : in  std_logic_vector (7 downto 0); --Eingangsadresse
8
           C : out std_logic_vector (1 downto 0)); --2 Chip selects. 
9
end codier1;
10
11
architecture Behavioral of codier1 is
12
13
begin
14
  with A(7) select 
15
    C <= "01" when '0',
16
         "10" when '1';
17
end Behavioral;

Syntax check gibt folgenden Fehler aus: "Enumerated value U is missing 
in select.

Nun wenn ich statt "10" when '1' auf "10" when others gehe, gibts nichts 
zu beanstanden.

Also Einleitende frage: was steckt hinter dem enum U?
Und korrektur der CS-Denkweise natürlich auch willkommen.

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


Lesenswert?

1
C : out std_logic_vector (1 downto 0)
c ist ein Vektor aus 2 std_logic.

Was ist ein std_logic, welche Werte kann der haben?
Ein std_logic kann 9 Zustände annehmen:
{'1','0','H','L','X','U','W','Z','-'}

Du hast in deinem Original nur 2 der möglichen 81 Zustände
"11" ... "-U" ... "ZW" ... "1L" ... "--" dargestellt.

Du hast also die ganzen anderen Kombinationen ausser "01" und "10" 
ignoriert.

> Und korrektur der CS-Denkweise natürlich auch willkommen.
So gehts kürzer:
1
begin
2
    C(0) <= not A(7);
3
    C(1) <= A(7);
4
end Behavioral;

von nixda (Gast)


Lesenswert?

oder auch,

 C <= "01" when A(7)='0' else "10";

/mfg

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


Lesenswert?

Oder
1
    C(1) <= A(7);
2
    C(0) <= not C(1);


Ach, übrigens:
> Du hast also die ganzen anderen Kombinationen ausser "01" und "10"
> ignoriert.
Das war ein Lesefehler :-/

Richtig müsste es heißen:
A(7) kann 9 Zustände annehmen, du hast 7 davon ignoriert.
Komplett ausgeschrieben könnte deine Zuweisung so aussehen:
1
  with A(7) select 
2
    C <= "01" when '0',
3
         "10" when '1',
4
         "UU" when 'H',
5
         "UU" when 'L',
6
         "UU" when 'W',
7
         "UU" when 'Z',
8
         "UU" when 'X',
9
         "UU" when 'U',
10
         "UU" when '-';
Denn in den letzten 7 Fällen kannst du getrost von einem undefinierten 
Ergebnis ausgehen. Damit sparst du dir das when others.

Aber in der Praxis gibt es nur die ersten beiden (zumindest innerhalb 
des FPGAs) und deshalb kannst du die anderen in einem (1) when others 
Fall zusammenfassen.
Du könntest also auch so schreiben:
1
  with A(7) select 
2
    C <= "01" when '0',
3
         "10" when '1',
4
         "UU" when others;
Das ist formal richtig, simuliert richtig und lässt sich synthetisieren.

von J.H. (Gast)


Lesenswert?

Muss pushen:

der Schnipsel: Lauflicht
1
entity test_vhd is
2
  generic(bitbreite : natural := 4);
3
    Port ( clk : in  STD_LOGIC;
4
        load : in STD_LOGIC_VECTOR;
5
        outp: out STD_LOGIC_VECTOR(bitbreite-1 downto 0);
6
        inp : in  STD_LOGIC_VECTOR(bitbreite-1 downto 0));
7
end test_vhd;
8
9
architecture Behavioral of test_vhd is
10
  signal outp_int : STD_LOGIC_VECTOR(bitbreite-1 downto 0);
11
begin
12
13
  schieben: process begin
14
    wait until rising_edge(clk);
15
    
16
    if (load = '1') then
17
      outp_int <= inp;
18
    else
19
      outp_int <= outp_int(0) & outp_int(outp_int'left downto 1);
20
    end if;
21
  end process schieben;
22
  
23
  outp <= outp_int;
24
end Behavioral;

Warum die Warnung : Line 23. = can not have such operands in this 
context.

Außerdem Frage zum wait_until rising_edge. Das habe ich öfter als 
Alternative zum if (rising_edge) gelesen. Hat es Vorteile? Und das darf 
man anscheinend nur ohne sensitivitäts liste machen. Ist das dann ein 
Problem falls ich irgendwann größeres Simulieren will?

von Stefan Salewski (Gast)


Lesenswert?

>load : in STD_LOGIC_VECTOR;

Soll das so sein ohne Bereichsangabe, oder meinst Du STD_LOGIC;

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


Lesenswert?

> Außerdem Frage zum wait_until rising_edge. Hat es Vorteile?
Siehe:
http://www.lothar-miller.de/s9y/archives/16-Takt-im-Prozess.html

> Ist das dann ein Problem falls ich irgendwann größeres Simulieren will?
Nein, es hat sogar den unschlagbaren Vorteil, dass die Simulation 
garantiert richtig ist, weil keine Signale in der Sensitiv-Liste 
fehlen können.

von J.H. (Gast)


Lesenswert?

Oh mein Gott.... in der Tat. Vector ist natürlich Schwachsinn......

Ich fühle mich wie in den ersten c tagen. Ein Instikt was welche 
Fehlermeldungen verursacht fehlt mir ja noch völlig. Und -nun ja- sehr 
trickreich ist obiger Fehler ja nicht gerade. :-(

@Lothar. Ja danke. Deine ganze Seite ist doch intensiveres Studium wert. 
Wenn man sich dann noch im entscheidenden Moment an die relevanten Infos 
erinnert, steht sehr viel drin.

Eine Frage möchte ich direkt noch los werden weil ich sie auch in einem 
Codefragment gesehen habe.

Ich habe ein internes Signal
1
signal xyz : STD_LOGIC_VECTOR(3 downto 0) := "0000";

a) ist das "Initialilsieren" auch für synthetisierte Hardware gültig?

b) wie schreibe ich das in Abhängigkeit mit einem generic der die 
Bitbreite definiert?
1
signal xyz : STD_LOGIC_VECTOR(3 downto 0) := (others->0);
klappte nicht. Ich hoffe da war nicht wieder ne Dummheit der Grund.

von J.H. (Gast)


Lesenswert?

Ich sollte für heute abschalten und ein Bierchen trinken gehen - klar im 
zweiten Beispiel hab ich den generic (breite -1 downto 0) verschlabbert.

Auch wenns euch sicher klar ist : wollte das der Vollständigkeit halber 
noch korrigieren.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

J.H. schrieb:
> Ich habe ein internes Signal
>
1
> signal xyz : STD_LOGIC_VECTOR(3 downto 0) := "0000";
2
>
>
> a) ist das "Initialilsieren" auch für synthetisierte Hardware gültig?
Bei Xilinx ja. Die Inistialisierung gehört zum "Programmiervorgang"

> b) wie schreibe ich das in Abhängigkeit mit einem generic der die
.
> klappte nicht. Ich hoffe da war nicht wieder ne Dummheit der Grund.
1
 signal xyz : STD_LOGIC_VECTOR(b-1 downto 0) := (others->'0');

"bits" in ' .. ' "vektoren" in "...." (Warum auch immer man das so 
festgelegt hat)

von J.H. (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe eine Frage zur compoments; anbei ein Testprojekt an dem ich 
gestern geübt habe und nun nciht mehr weiter komme.

Plan war: eine entity für eine 7-Segmentanzeige. Die dann (später) evtl. 
in eine Entity Anzeige als Component(s) übernehmen. Diese Anzeige würde 
ich dann ganz gern wenn ich mal Hardware besitze auch zum debuggen 
nehmen. Vielleicht umschaltbar dezimal/hex.
Ok erste Frage: muss ich die Anzahl von components exakt angeben oder 
kann ich irgendwie auch eine Art Array von compoments machen? Aus 
folgendem grund. Wenn ich eine allgemeine Anzeige haben möchte ist die 
Stellenzahl ja so was wie ein generic und für eine 16-Bit anzeige sind 
entsprechend meh components notwendig.

Das ist aber eh noch Zukunftsmusik. Siehe Datei :-(

Um etwas zur Anzeige bringen zu können, wollte ich einen Impulsgeber 
verwenden und der Einfachheit halber erst mal einen Zähler. Also die 
Idee: eine Stelle der 7-Segment entity als component in den Zähler, und 
den Zählstand an den Dateneingang. Fertig. Enttäuschung.
Wie mache ich das denn mit ALLEN Signalen. Müssen eine 'top' entity 
definiert werden, in der alle externen Signale vorhanden sind? Wie oe 
oder die Signale zu den Segmenten? Kann ich so eine Anzeige gar nciht 
mal schnell mit einem counter verknüpfen?

Ich hoffe sehr ihr könnt mein Problem verstehen und mir einen Rat geben, 
wie ich in dem Code vorgehen müsste. Der wird ja noch deutlich 
komplexer.

Ach ja: und irgendwelche libraries muss ich noch nciht in den Kopf 
nehmen? work ist immer das vhd file? Bzw. könnte ich die 7Segemnt Stelle 
und ggf. daraus entstandene Anzeige in ein einzelnes file schreiben udn 
einfach in ein Projekt hängen. Würde das gefunden?

danke

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


Lesenswert?

> Müssen eine 'top' entity
> definiert werden, in der alle externen Signale vorhanden sind?
Es gibt nur 1 Top-Level, der letztlich nach aussen verbunden (an Pins 
angeschlossen) werden kann. Und die Pinzuordnung ist sowieso mit 
manueller Arbeit im UCF-File verbunden.


> Wenn ich eine allgemeine Anzeige haben möchte ist die
> Stellenzahl ja so was wie ein generic und für eine 16-Bit anzeige sind
> entsprechend meh components notwendig.
Was du suchst geht in die Richtung eines Generate zusammen mit einer 
Loop
http://wwwlrh.fh-bielefeld.de/vhdl_vor/VHDL_V_B.htm

> Ach ja: und irgendwelche libraries muss ich noch nciht in den Kopf
> nehmen?
Nein.

BTW: Libraries....
Man kanns offenbar nicht oft genug sagen ;-)
Verwende statt der herstellerabhängigen
1
use IEEE.STD_LOGIC_ARITH.ALL;
2
use IEEE.STD_LOGIC_UNSIGNED.ALL;
besser die genormte
1
use IEEE.numeric_std.ALL;

von Anfänger (Gast)


Angehängte Dateien:

Lesenswert?

Ich häng mich hier auch mal mit rein :)

Habe versucht, anhand des Timing-Diagramms (S. 9 DB) mein erstes Modul 
zu erstellen, das dazu dienen soll, Werte vom ADC in einen 
(SRAM-)Speicher zu schreiben.
(HW wird das Spartan3E-Dev Board mit dem ADC von Linear.)

Bekomme jetzt den Fehler:
> line 71: Multi-source on Integers in Concurrent Assignment.

Offensichtlich ist die Prozess-Deklaration fehlerhaft - aber ich weiß 
nich weiter.

Über etwas Nachhilfe würde ich mich sehr freuen.

von Gast (Gast)


Lesenswert?

1.  laß bloß die "shared variable" weg - ganz schlecht !
2. "counter" wird in Zeile 35 UND 60/62 ein Wert zugewiesen
      genauer: in zwei verschiedenen Prozessen
      genau DAS is Dein Problem...

      was soll denn die arme Hardware damit Deiner Meinung nach tun?

von Anfänger (Gast)


Angehängte Dateien:

Lesenswert?

Danke für den Tip.
Ich habe dann versucht, es soweit umzustellen, dass ...

Naja - jetzt bekomme ich diesen Fehler, wenn auch erst in der 
HDL-Analyse:

> line 47: Signal aclk cannot be synthesized, bad synchronous description.

Dann dachte ich, ok, versuch es eben mit mehreren kleinen Modulen, die 
dann im toplevel-Teil verbunden werden ...

Habe also nur mal die Taktleitung mit enable als entity geschrieben und 
übersetzt, mit dem Resultat:
1
Compiling vhdl file "S:/win/vhdl/sr_clk_route.vhdl" in Library MyStuff.
2
Entity <sr_clock_router> compiled.
3
Entity <sr_clock_router> (Architecture <behavioral>) compiled.
4
vhdtdtfi:Declaration (Module sr_clock_router) not found.
5
tdtfi(vhdl) completed with errors.

Muss ich Entitäten in (m)einer Bibliothek noch bekannt machen (ala 
Protoyping in C)? - oder was wird für ein Modul gesucht?

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


Lesenswert?

> HW wird das Spartan3E-Dev Board mit dem ADC von Linear.
Das hat Dual-Edge FFs nur in den IO-Zellen. Du kannst sowas nicht 
machen:
1
      if (cs = '0') then
2
         aclk  <= '0';
3
         counter := 0;
4
      elsif (run = '1') then <-- eine etwas ungewöhnliche Clock-Enable Beschreibung
5
         if (gclk'event and gclk = '1') then     <--------- solche FFs gibts nicht 
6
         elsif (gclk'event and gclk = '0') then  <--------- innerhalb des FPGAs
7
         end if;
8
      end if;
Am einfachsten könntest du den Takt gclk mit einem DCM verdoppeln und 
dann nur mit der steigenden Flanke arbeiten.


Das hier ist eine ganz üble asynchrone Rücksetzerei und wird dich noch 
einige Haare kosten:
1
      if (cs = '0') then
2
        :
3
      elsif (counter < 3) then
4
        :
5
      elsif (counter = 16 or counter = 32) then   
6
        :
7
      elsif (counter = 17 or counter = 33) then
8
        :
9
      elsif (counter = 19 or counter = 35) then
10
        :
11
      elsif falling_edge(gclk) then
12
         lpm_sr <= lpm_sr(14 downto 0) & adata;
13
      end if;
Denn schon der kleinste Glitch beim Übergang von einem Zählerwert zum 
nächsten kann recht unverhoffte Dinge hervorrufen. Wenn dein Zähler z.B. 
gerade mal von 15 nach 16 zählt, dann könnte das so aussehen:
001111 -> 000000 -> 010000
Der Zählerwert 0 ist zwar nur ein Bruchteil einer ns zu sehen, aber er 
ist da. Und wenn deine Abfrage (counter < 3) gut implementiert ist, dann 
wird die zuschlagen :-o

Dann machs doch besser so:
1
    if falling_edge(gclk) then
2
      if (cs = '0') then
3
        :
4
      elsif (counter < 3) then
5
        :
6
      elsif (counter = 16 or counter = 32) then   
7
        :
8
      elsif (counter = 17 or counter = 33) then
9
        :
10
      elsif (counter = 19 or counter = 35) then
11
        :
12
      end if;
13
      lpm_sr <= lpm_sr(14 downto 0) & adata;
14
    end if;
Das ist synchron und Glitches können sich dadurch nicht auswirken.

von Anfänger (Gast)


Lesenswert?

Hallo Lothar,

danke für Deine Unterstützung!

Das mit dem Counter ist eine Unachtsamkeit. Du hattest es mir ja schon 
mal geschrieben. Sorry - ich habe es noch nicht ganz verinnerlicht, aber 
gelobe Besserung :)

Bei dem Takt habe ich vermutlich einen Denkfehler. Das 'sr_adc' sollte 
ein Modul werden, welches ich später in einem neuen top-level verwenden 
kann.
Für das Modul habe ich mir so vorgestellt, dass der Takt von außen (über 
DCM oder wie auch immer) erzeugt wird, dass also quasi der Anwender von 
sr_adc den Takt anhand der gewünschten Samplerate festlegt.

Innerhalb des Moduls wollte ich den Takt ein und ausschalten können - 
eben nach Vorgabe des ADCs. Ich fände es jetzt extrem suboptimal, wenn 
ich bei Verwendung des Moduls den doppelten Takt vorgeben, bzw. erzeugen 
müsste.

Gibt es noch eine andere Möglichkeit, den Takt bedingt weiter zu 
reichen, ohne ein Dual-Edge-FF verwenden zu müssen?

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


Lesenswert?

> Ich fände es jetzt extrem suboptimal,
Naja, wenn es nicht implementiert werden kann, ist es m.E. noch deutlich 
suboptimaler :-/

> Gibt es noch eine andere Möglichkeit, den Takt bedingt weiter zu
> reichen, ohne ein Dual-Edge-FF verwenden zu müssen?
Machs doch auf die harte Art mit einem Mux (Stichwort: Gated Clock). Das 
mußt du dann zwar gut im Auge behalten, aber machen kann man das schon:
1
   aclk <= gclk when run='1' else '0';

von Anfänger (Gast)


Lesenswert?

Puh, jetzt ist meine Verwirrung komplett :(

Ein Mux war für mich ein Selections-Element, um von mehreren Eingängen 
einen auszuwählen, der dann den Ausgang treibt, bzw. darstellt.

Ein Element mit einem Eingang und einem Ausgang ist auch ein Mux?
Was ist dann bitte schön ein Mux?

... und gated clock - war das nicht etwas, was man vermeiden sollte?

Würdest Du mit halbiertem Takt arbeiten, oder wie würdest Du die 
Aufgabenstellung angehen?

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


Lesenswert?

> Was ist dann bitte schön ein Mux?
Du hast die Antwort vor der Frage gegeben:
> Ein Mux war für mich ein Selections-Element, um von mehreren Eingängen
> einen auszuwählen, der dann den Ausgang treibt, bzw. darstellt.
Also: Ein Mux ist ein Element mit mindestens 2 Eingängen, mindestens 1 
Selektionseingang und genau 1 Ausgang.

> Ein Element mit einem Eingang und einem Ausgang ist auch ein Mux?
In meinem Beispiel wählt der Mux zwischen einem Signal gclk und einer 
'0' aus. Also wie du schon beschrieben hast: es wird aus 2 Signalen 
ausgewählt.
Du kannst jede kombinatorische Funktion mit einem Mux ausführen. Die 
LUTs in einem Spartan 3 FPGA sind nichts anderes als ein 16:1 Mux. Und 
die können jede logische Funktion mit bis zu 4 Eingängen abbilden.

> ... und gated clock - war das nicht etwas, was man vermeiden sollte?
Ja, schon. Schön ist das nicht...
Aber wenns irgendwann mal nicht anders geht  ;-)

> Würdest Du mit halbiertem Takt arbeiten,
Ja.
> oder wie würdest Du die Aufgabenstellung angehen?
Oder den doppelten Takt (via DCM) einspeisen.

von Anfänger (Gast)


Lesenswert?

Hallo Lothar,

danke für Deine Geduld!

Nur um ganz sicher zu gehen, dass ich's auch verstanden habe:
1
aclk <= gclk when run='1' else '0';

Diese Anweisung ist also ein Mux und wird immer dann ausgeführt, wenn 
sich gclk oder run ändert?

von Christian R. (supachris)


Lesenswert?

Anfänger schrieb:
> Hallo Lothar,
>
> danke für Deine Geduld!
>
> Nur um ganz sicher zu gehen, dass ich's auch verstanden habe:
>
1
aclk <= gclk when run='1' else '0';
>
> Diese Anweisung ist also ein Mux und wird immer dann ausgeführt, wenn
> sich gclk oder run ändert?

Das ist reine Kombinatorik, also einfach ein paar Gatter. Sauber kann 
man sowas auch mit einem BUFGMUX machen, oder aber versuchen, zu 
Umschiffen...muss denn der ACLK unbedingt abgeschaltet werden? Bei den 
allermeisten SPI Slaves kann der duchlaufen...

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


Lesenswert?

> Bei den allermeisten SPI Slaves kann der duchlaufen...
Dann muß aber der SS zum richtigen Zeitpunkt kommen.

von Christian R. (supachris)


Lesenswert?

Lothar Miller schrieb:
>> Bei den allermeisten SPI Slaves kann der duchlaufen...
> Dann muß aber der SS zum richtigen Zeitpunkt kommen.

Natürlich. Bei den SPI-ADCs, die ich benutzt hab, startet die steigende 
Flanke des CS die Wandlung, die fallende startet das Auslesen, 
dazwischen ist die Wandlungszeit zu beachten. Lässt sich wunderbar über 
einen durchlaufen Zähler machen...

von Anfänger (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Ihr beiden Supercracks :)

verzeiht, aber ich habe Eure Erfahrung net. Insofern habe ich auch keine 
Ahnung, wie man sonst SPI-ADCs ansteuern würde. Freiwillig würde ich mir 
kein SPI-ADC antun, insbesondere nicht in Zusammenhang mit einem FPGA - 
aber es ist nunmal drauf, dann macht es sicher auch Sinn, es zu 
verwenden ;)

Beim LTC1407 gibt es kein CS und ich kann nur sagen, dass ich das Modul 
anhand des Timing-Diagramms erstellt habe.

Den Takt einfach durchlaufen zu lassen und auch intern zu verwenden habe 
ich genausowenig hinbekommen, wie den Takt über den oder das MUX.
Deshalb hat die jetzige Variante also den Takthalbierer.

Die Synthese läuft durch, aber das Ergebnis ist alles andere als 
berauschend. Gut, ich kann nicht beurteilen, ob und schon garnicht wie 
es besser geht, aber das was rauskommt sieht für meine Begriffe grausig 
aus.
Die Zeiten deuten auch auf eine eher suboptimale Lösung hin, denn max. 
80 MHz würde zwar ausreichen, aber ich hätte mehr erwartet.

Der RTL-Viewer will ne Tapete erzeugen, die zum Tapezieren eines 
Fußballstadions reichen würde ... :(

Deshalb meine Frage:
- So wie es aussieht, werden für die Variablen auch Logikelemente 
erzeugt. Was ist dann der Sinn, eine Variable statt einem Signal zu 
verwenden?
- Wie geht man da vor, um zu sehen, was zu optimieren geht?
- Gibt es dafür Regeln, oder ist das "nur" ein Bauchgefühl der alten 
Hasen?
Ich habe im Moment nur die 11er ISE unter Windows am Laufen.
Was muss ich anstellen, um die Testbench (unter ISim?) simulieren zu 
können?
In der ISE sehe ich nix mehr von wegen Simulation und um das Timing zu 
bestimmen, reicht die Weblizenz nicht aus - das geht wohl nur in den 
kostenpflichtigen Paketen.

Wäre für weitere Tips sehr dankbar.

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


Lesenswert?

> LTC1407
> Den Takt einfach durchlaufen zu lassen
Das liegt bei diesem Baustein auf der Hand, so ist es ja auch im DB 
eingezeichnet :-/

Und dann muß nur noch das conv gesetz werden, und gleichzeitig ein 
langes Schieberegister (34 Bit) gestartet. In dieses Schieberegister 
wird der ganze Datenstrom eingetaktet und anschliessend weitergereicht. 
Das wars dann schon...

von Anfänger (Gast)


Angehängte Dateien:

Lesenswert?

Hach :)

Altera ist etwas großzügiger zu Anfängern. Bei denen kam auf RTL was 
brauchbares zu gucken :)

Meine Fragen dazu:
run ist eine Bit-Variable. Woher kommen die run~0 ... run~4 und was sind 
das für Symbole? Ist das ein 2fach MUX?

addr ist 20Bit breit definiert. Wieso gibt es dann noch addr[41..21] und 
addre[62..42] ??? Was habe ich da wieder nich berücksichtigt?

Sehe gerade eine Überschneidung der Postings ...

> Und dann muß nur noch das conv gesetz werden, und gleichzeitig ein
> langes Schieberegister (34 Bit) gestartet. In dieses Schieberegister
> wird der ganze Datenstrom eingetaktet und anschliessend weitergereicht.

Ein (über-)langes Schieberegister ist also besser, als 2mal ein 
kleineres zu füllen?

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


Lesenswert?

> Ein (über-)langes Schieberegister ist also besser, als 2mal ein
> kleineres zu füllen?
Ja, das was du zur Verwaltung der beiden kleinen SR zusätzlich brauchst, 
kannst du genausogut in das längere SR stecken.

von Christian R. (supachris)


Lesenswert?

Zumal das in VHDL ja so schön geht. Beliebig langes SR und dann zur 
Weiterverarbeitung die ensprechenden Teile des Vektors heraus picken.

Byte_0 <= SR(7 downto 0);
Byte_1 <= SR(15 downto 8);
Byte_2 <= SR(23 downto 16);

usw....

von Anfänger (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

bin inzwischen etwas weiter gekommen. Ich muss sagen, dass mir Quartus 
(bislang?) anfängerfreundlicher vorkommt.

Nur mit getakten Prozessen habe ich eine Variante ausprobiert, die ein 
16Bit Schieberegister 2mal ausliest und eine andere, die ein 32Bit 
Schieberegister nur einmal ausliest.

die erste Variante (16Bit SR):
67 LEs, 45 Combinationsfunktionen, 53 Logikregister und 59 Pins
Als maximale Frequenz gibt Altera 148 MHz an.

die zweite Variante (32Bit SR):
62 LEs, 42 Combinationsfunktionen, 50 Logikregister und 59 Pins
Als maximale Frequenz gibt Altera 170 MHz an.

Könnte von den Gurus mal jemand drüber schauen, ob bei gleicher 
Funktionalität noch Optimierungspotential ist?

Im Voraus schon herzlichen Dank.

Ach ja:
Das Signal 'aconv' wird meines Wissens nur geschrieben. Wenn ich es 
jedoch als 'out' anstatt 'inout' deklariere, brauche ich mehr 
Combinatorik und mehr LEs. Kann mir das vielleicht jemand erklären?
Ich habe gleiches bei den restlichen 'out' Signalen auch probiert, dort 
tritt der Effekt nicht auf - im Gegenteil, es sieht genau andersherum 
aus.

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


Lesenswert?

>   o_clock : ...;   -- clock line to ADC, will be internal clock too
Das ist für ein FPGA sehr unschöne Designpraxis. Du kannst nicht 
(einfach so) irgendwelche Signale als lokalen Takt nehmen...
Falls du es trotzdem tust, mußt du fest mit eigenartigen Problemen 
rechnen. Im FPGA arbeitet man besser mit 1 Takt und 
Clock-Enable-Signalen.


> Wenn ich es jedoch als 'out' anstatt 'inout' deklariere,
> brauche ich mehr Combinatorik und mehr LEs.
Das sagt die Synthese. Lass da mal P&R drüber, dann sieht das 
wahrscheinlich wieder besser aus...

von Anfänger (Gast)


Lesenswert?

Hallo Lothar,

> Das ist für ein FPGA sehr unschöne Designpraxis.

da habe ich Dich ein paar Beiträge früher wohl falsch verstanden.
Als es drum ging, dem Takt noch ein enable zu spendieren, was zu einer 
Frequenzhalbierung führte. Du meintest doch, ich solle mit doppeltem 
Takt reinkommen und diesen dann auf ein FF mit clock-enable führen.

So habe ich es jetzt umgesetzt, nur dass mein clock-enable eben das cs 
des gesamten Modules ist. Sobald das Modul aktiv ist, läuft der Takt 
immer.
Auch das hatte ich von Euch so verstanden.

Wenn es falsch ist, könntest Du mir bitte mal zeigen, wie es besser 
wäre?
Denn die Taktleitung einfach fest mit dem Ausgang zu "verdrahten" hat ja 
auch nicht geklappt.

>> Wenn ich es jedoch als 'out' anstatt 'inout' deklariere,
>> brauche ich mehr Combinatorik und mehr LEs.
> Das sagt die Synthese. Lass da mal P&R drüber, dann sieht das
> wahrscheinlich wieder besser aus...

Was ist bitte schön P&R? - Ich kenne das Kürzel nur als "Park and Ride", 
was ja hier wohl nicht weiter hilft ;)

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


Lesenswert?

> Wenn es falsch ist, könntest Du mir bitte mal zeigen, wie es besser wäre?
Werde ich dir morgen zeigen...  ;-)
Als Tipp: der Takt wird parallel auf das FPGA und auf den AD-Wandler 
gegeben. Dann wird einen Takt lang das conv-Signal aktiviert. Und nach 
dem Einlesen der Daten in das lange SR die Daten wie von Christian 
vorgeschlagen auseinandergepfriemelt...

> Was ist bitte schön P&R?
Place and Route

von D. I. (Gast)


Lesenswert?

Place & Route

von Christian R. (supachris)


Lesenswert?

Lothar Miller schrieb:
>> Wenn es falsch ist, könntest Du mir bitte mal zeigen, wie es besser wäre?
> Werde ich dir morgen zeigen...  ;-)
> Als Tipp: der Takt wird parallel auf das FPGA und auf den AD-Wandler
> gegeben. Dann wird einen Takt lang das conv-Signal aktiviert. Und nach
> dem Einlesen der Daten in das lange SR die Daten wie von Christian
> vorgeschlagen auseinandergepfriemelt...

Genau. Der ADC gibt seine Daten zeitigstens 8ns nach der steigenden 
Flanke des SCLK aus. Das heißt, du kannst die auf jeden Fall sicher mit 
der nächsten steigenden Flanke in das SR im FPGA übernehmen, da das Bit 
dann auf jeden Fall noch stabil anliegt. So wird das üblicherweise 
gemacht. Und wieso sind dir eigentlich 170MHz zu langsam? Der ADC 
verkraftet eh nur 50,4MHz als SCLK. Wenn ich mich recht erinnere, hab 
ich den 1407A glaube sogar schon mal mit einem MachXO angesteuert nach 
dem o.g. Prinzip mit 50MHz. Hat zuverlässig geklappt.

von Anfänger (Gast)


Lesenswert?

> Als Tipp: der Takt wird parallel auf das FPGA und auf den AD-Wandler
> gegeben.

Zum einen will ich das nicht, zum anderen ist die Platine ja fertig, da 
kann ich nix mehr dran ändern.
Ja und wollen will ich es nicht, weil das ADC max. 50 MHz verkraftet, 
der FPGA aber vielleicht, bzw. ganz sicher noch andere Aufgaben bekommt. 
Das ADC ist also nur ein Modul von ("meinem") Professor, das bei Bedarf 
aktiviert wird.
Ich gehe davon aus, dass der externe Takt für den FPGA 125 MHz beträgt. 
Wie ich dann zu einem Takt von 300 MHz komme ist mir noch nicht klar, 
aber das ist mein Ziel. Intern will ich das ADC-Modul dann nur mit 50 
MHz, bzw. jetzt eben mit 100 MHz ansteuern (so mein Plan - ob der 
realisierbar ist, muss sich zeigen).

Der ADC-Takt soll also nur dann den FPGA verlassen, wenn in meinem 
"Softcore" das ADC auch aktiviert wurde - ich will ja nicht unnötigen 
Dreck auf den Leitungen produzieren.

> Das heißt, du kannst die auf jeden Fall sicher mit
> der nächsten steigenden Flanke in das SR im FPGA übernehmen

Hm - ich habe das DB so interpretiert, dass der ADC min. 2 Takte 
braucht, bis die Umwandlung fertig ist. Erst dann beginnt die Ausgabe 
der Daten, also mit dem 3. Takt - und im DB des 1407 steht, dass die 
Daten bei steigendem Clock wechseln, man also bei fallendem Clock das 
Bit ins Latch übernehmen soll.

> Und wieso sind dir eigentlich 170MHz zu langsam?

Kann mich nicht entsinnen, das geschrieben zu haben. Als meine erste 
Variante übersetzt wurde, kamen ca. 80MHz raus - dazu schrieb ich, dass 
es wohl ausreichen würde, den ADC zu treiben, dass ich es aber als 
Wertung für schlechtes Design ansehe.

Ich weiß, dass die Frequenzangabe eh nur eine theoretische Daumenpeilung 
ist. Aber wenn der FPGA locker über 300 MHz verkraftet, sind 170 MHz für 
mich die Aussage, dass mein Entwurf ungefär einer Schulnote 3-4 
entspricht.
Das hat nix damit zu tun, dass es mir zu langsam ist, sondern einfach, 
damit, dass man es (sicher) noch besser machen kann.

von Christian R. (supachris)


Lesenswert?

Anfänger schrieb:

>> Das heißt, du kannst die auf jeden Fall sicher mit
>> der nächsten steigenden Flanke in das SR im FPGA übernehmen
>
> Hm - ich habe das DB so interpretiert, dass der ADC min. 2 Takte
> braucht, bis die Umwandlung fertig ist. Erst dann beginnt die Ausgabe
> der Daten, also mit dem 3. Takt - und im DB des 1407 steht, dass die
> Daten bei steigendem Clock wechseln, man also bei fallendem Clock das
> Bit ins Latch übernehmen soll.

Naja kann man machen, ist aber hier Unsinn. Denn die Ausgabe erfolgt 
garantiert nach der Flanke. In Note 12 auf Seite 4 des Datenblattes 
stehts extra drin, dass du die steigende Flanke zum Einsammeln nehmen 
sollst.

Das einfachste ist ein synchroner Zähler mit synchroner(!) Rücksetzung, 
der immer von 0 bis 33 durchläuft. Dessen Zählausgänge nimmst du dann 
für die kombinatorische Erkennung des Zustandes, ob du das CONV ausgeben 
musst oder Datenwort einlesen musst.

Wenn die HW fertig ist, ist das beste, den Takt einfach so auszugeben. 
Da du ja aus deinen 125MHz die 50 erzegen willst, bist du ja eh hinter 
einem DCM o.ä. da geht das problemlos. Wenn man bei der Ausgabe eines 
Taktes die maximale Performance rausholen will, kann man auch ein 
DDR-FlipFlop dafür einbauen, ist aber meist nicht nötig, und wenn dann 
nur bei DDR-Verbindungen mit hohen Frequenzen.

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


Angehängte Dateien:

Lesenswert?

> dass die Daten bei steigendem Clock wechseln ...
Die Daten wechseln nach dem steigenden Clock (bzw. wegen der 
steigenden Flanke). Also ist genau diese Flanke diejenige, an der die 
Daten vorher sicher stabil anstehen. Und damit sollten sie auch genau 
mit dieser Flanke eingetaktet werden.

Zu deinem Design:
Der Ansatz ist nicht schlecht, aber die Sache mit dem
>       if (cs = '0') then
würde ich doch ein wenig anders machen: erst mal den Zyklus komplett 
fertig, und dann wieder den CS abfragen. Denn was wäre, wenn mitten im 
Wandeln oder Schreiben einfach jemand kurz mal den CS wegnimmt?

Sieh dir mal meinen Ansatz an.
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity LTC1407 is
6
    Port ( clk50   : in  STD_LOGIC; 
7
           cs      : in    STD_LOGIC;   -- chip-select: ADC starts with setting cs high
8
           frc     : in    STD_LOGIC;   -- free running conversion (high) or single shot (low)
9
           sck     : out   STD_LOGIC;
10
           conv    : out   STD_LOGIC;
11
           sdo     : in    STD_LOGIC;
12
           nWE     : out   STD_LOGIC;   -- negated write enable (memory)
13
           oChA    : out   STD_LOGIC_VECTOR (15 downto 0);   -- channel A result data from ADC
14
           oChB    : out   STD_LOGIC_VECTOR (15 downto 0);   -- channel B result data from ADC
15
           oaddr   : out   STD_LOGIC_VECTOR (19 downto 0));  -- self incrementing memory address in free running mode
16
end LTC1407;
17
18
architecture Behavioral of LTC1407 is
19
signal cnt : integer range 0 to 41 := 41;
20
signal sr : std_logic_vector(27 downto 0);
21
signal doADC : STD_LOGIC := '1';
22
SIGNAL acnt : integer range 0 to (2**20)-1;
23
begin
24
   sck <= clk50; -- Takt durchreichen, mit constraints sicherstellen, dass das Timing passt
25
   
26
   process begin
27
      wait until rising_edge(clk50);
28
      -- Wandlung läuft
29
      if (cnt<41) then 
30
         cnt  <= cnt+1;
31
      end if;
32
      -- Daten einfach durchschieben, werden bei Zählerstand 32 gespeichert
33
      sr <= sr(sr'left-1 downto 0) & sdo; 
34
      -- Zustände auswerten
35
      case cnt is
36
         when 0 =>  conv <= '1';
37
         when 1 =>  conv <= '0';
38
         when 32 => oChA <= x"0" & sr (27 downto 16);
39
                    oChB <= x"0" & sr (11 downto 0);
40
                    oaddr <= std_logic_vector(to_unsigned(acnt,20));
41
         when 33 => nWE   <= '0';
42
         when 40 => nWE   <= '1';
43
                    doADC <= frc;
44
                    acnt  <= acnt+1; -- Autoincrement
45
         when 41 => if (cs='1' and doADC='1') then 
46
                       cnt <= 0;
47
                    end if;
48
                    if (cs='0') then
49
                       acnt  <= 0;
50
                       doADC <= '1'; -- nach steigender Flanke CS mindestens 1 Wandlung;
51
                    end if;
52
         when others => NULL;
53
      end case;
54
   end process;
55
end Behavioral;
Möglich, dass die eine oder andere zahl noch angepasst werden muß. Es 
geht mir um den Ansatz...


BTW:
Du könntest dir die Leerlaufzeit (cnt= 33..41) sparen, wenn du das 
Speichern während der Wandlung machen würdest (Gedankenskizze im 
Anhang).

von Anfänger (Gast)


Angehängte Dateien:

Lesenswert?

> In Note 12 auf Seite 4 des Datenblattes
> stehts extra drin, dass du die steigende Flanke zum Einsammeln nehmen
> sollst.

Die ist mir vor Deinem Nasenstubser zwar raus, aber selbst jetzt würde 
ich es nicht unbedingt so interpretieren ;) - aber Du hast ja trotzdem 
recht!

> Wenn man bei der Ausgabe eines
> Taktes die maximale Performance rausholen will, kann man auch ein
> DDR-FlipFlop dafür einbauen, ist aber meist nicht nötig, und wenn dann
> nur bei DDR-Verbindungen mit hohen Frequenzen.

Auch wenn das noch Zukunftsmusik ist, spätestens dann, wenn das Ethernet 
tut, will ich in die Richtung. So wie ich Lothar verstanden habe, hat 
der Spartan DDR-FFs nur an den IO-Ports. Wenn Du mir also einen Tipp 
hättest, wie ich die trotzdem verwenden kann, wäre ich Dir sehr 
verbunden!!!

> Zu deinem Design:
> Der Ansatz ist nicht schlecht, aber die Sache mit dem
>>       if (cs = '0') then
> würde ich doch ein wenig anders machen: erst mal den Zyklus komplett
> fertig, und dann wieder den CS abfragen. Denn was wäre, wenn mitten im
> Wandeln oder Schreiben einfach jemand kurz mal den CS wegnimmt?

Puh - jetzt gibst Du es mir aber!
Danke Dir Lothar, für die viele versteckten Tutorials! - Dein Beispiel 
hat mir mehr gebracht, als stundenlanges Tutorial-Lesen :)
... und nach der Steilvorlage konnte ich mein Modul endlich variabel 
gestalten. Herzlichen Dank für die viele unerwähnten Tips!

Deine Variante der cs-Behandlung war auch schwere Kost. Anfangs dachte 
ich, Deine Variante hat ja garkein Reset und würde immer wandeln. Bis 
dann der Herr Osram ein Einsehen hatte :)

Das war mir dann doch zu schwere Kost und ich dachte, ich versuche mal 
die restlichen Deiner Tips umzusetzen und schau mal, was die Synthese 
ausspuckt.
Vom Ergebnis war ich dann doch heftig überrascht.
Meine Variante braucht 2 FFs mehr, ist aber trotzdem schneller (288 MHz 
zu 330 MHz) - und mit dem Wert, meiner Einschätzung nach, reif für die 
Profiliga :)
Kann es sein, dass das 'wait' nicht so gut umgesetzt wird, wie die 
Abfragen im getakteten 'if'?

> Du könntest dir die Leerlaufzeit (cnt= 33..41) sparen, wenn ...

Den Ansatz hatte ich schon mal verfolgt, aber ich war nicht zufrieden 
mit dem Ergebnis. Genauso wie ich das mit dem Takt durchreichen auch 
schon probiert hatte.
Weiß nicht, warum er es letztens mit "illegal synchronous ..." abgelehnt 
hatte. Jetzt scheint es ja zu funzen.

Bei Altera gehört der P&R-Schritt mit zum Übersetzungsprozess - wird 
also immer ausgeführt. Heute habe ich den in der ISE auch mal angestoßen 
und - oh Schreck, oh Graus! - laut Fehlermeldung wird der 1600er vom 
Spartan3E mit der Webpack-Lizenz nicht abgedeckt, d.h. ich kann den Chip 
also garnicht beschreiben?!?

Das ist ja extrem ätzend! - Gibt es freie Alternativen, oder muss ich 
das Board stornieren?

von Christian R. (supachris)


Lesenswert?

Lies mal im Datenblatt des Spartan zu den IDDR und ODDR, da steht das 
mit dem Takt ausgeben über DDR-FF. Wenn man das macht, hat man den Takt 
garantiert synchron zu den DDR-Daten ausgegeben.

WebPack deckt alle Spartan 3e ab: 
http://www.xilinx.com/publications/matrix/Software_matrix.pdf?KeepThis=true&TB_iframe=true

von Anfänger (Gast)


Lesenswert?

Hallo Chris,

danke für Deine Unterstützung!

> WebPack deckt alle Spartan 3e ab: ...

Sorry, mein Fehler. Habe mir gestern extra noch das Update auf 11.2 
installiert, aber erst heute, als das Board kam und ich die Chipnummer 
verglich, fiel mir auf, dass ich den falschen Spartan ausgewählt hatte.

Die Auswahl ist ja mehrstufig, also erst Spartan 3E - als Familie, dann 
das Modell. Der erste 1600E war leider aus der automotive serie :(
Wenn man's weiß, kann man es auch am 2. Buchstaben erkennen.
Ich hatte den XA3S1600E ausgewählt, dabei ist auf dem Board ein 
XC3S1600E (wenn das 'A' für automotive steht, dann steht 'C' ja wohl für 
cute).

von Neuling (Gast)


Lesenswert?

Hallo, ich beschäftige mich noch nicht sehr lange mit VHDL und wäre 
deshalb froh, wenn mir jemand ein paar syntaktische Sachen erklären 
könnte.

Bsp 1.
1
if x >= '0' and x <= '10' then 
2
...

der <= Operator ist normalerweise eine Zuweisung. Gibt es für "kleiner 
gleich" einen speziellen Operator, oder sind während Bedingungen in VHDL 
keine Zuweisungen erlaubt ?  (in C/java etc. wäre if x=5  immer true und 
x wird 5 zugewiesen)


Bsp 2 von oben:
1
case cnt is
2
         when 0 =>  conv <= '1';
3
         when 1 =>  conv <= '0';
4
    ...
5
end case;

Was bewirken hier die Operatoren =>  und <= ?

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


Lesenswert?

> Gibt es für "kleiner gleich" einen speziellen Operator,
ja, das  <=

> oder sind während Bedingungen in VHDL keine Zuweisungen erlaubt ?
Solche Schmutzprogrammierereien, wie sie in C möglich sind, werden in 
VHDL ausgeschlossen. Wenn eine Bedingung abgefragt wird, kann nicht 
gleichzeitig zugewiesen werden.

>   when 0 =>  conv <= '1';
Das => folgt einfach auf ein when, wenn das when in einem case steht 
;-)
Und das <= ist hier eine Zuweisung.

Es gibt einfach Syntaxvorschriften, die eingehalten werden müssen. Und 
in VHDL werden die besonders rigide abgefragt und überwacht.

BTW:
Nochn Pfeil:
1
  vect <= (others => '0');
auch das
others => '0' ist einfach ein feststehender Begriff, der wie ein
others => '1' fix zusammengehört.

Man könnte in dem obigen Beispiel auch so schreiben:
1
  vect <= (0 => '1', others => '0');
Damit wäre dann das Bit 0 gesetzt, die anderen Bits zurückgesetzt.

von J.H. (Gast)


Lesenswert?

Ich verzweifel gerade an der Ansteuerung einer Hex Anzeige:

1 Nibbel hat geklappt, weshalb ich den Zahlenbereich auf ein ganzen Byte 
ausdehnen wollte - klappt aber nicht.
1
anzeigen : process (clk3k_int) 
2
  variable n : integer range 0 to 1;
3
  begin
4
  
5
  if(rising_edge(clk3k_int)) then
6
      n := n + 1;
7
      --aktuelle Stelle auswählen
8
      case n is
9
        when 0 => an <= "1110";
10
        when 1 => an <= "1101";
11
        when others => an <= "1111";
12
      end case;
13
      --case cnt_int(3 downto 0) is
14
      case cnt_int((4*(n+1)-1) downto (4*n)) is
15
        when "0000" => seg <= "0000001";
16
        when "0001" => seg <= "1001111";
17
        when "0010" => seg <= "0010010"; 
18
        when "0011" => seg <= "0000110";
19
        when "0100" => seg <= "1001100";
20
        when "0101" => seg <= "0100100";
21
        when "0110" => seg <= "0100000";
22
        when "0111" => seg <= "0001101";
23
        when "1000" => seg <= "0000000";
24
        when "1001" => seg <= "0000100";
25
        when "1010" => seg <= "0001000";
26
        when "1011" => seg <= "1100000";
27
        when "1100" => seg <= "0110001";
28
        when "1101" => seg <= "1000010";
29
        when "1110" => seg <= "0110000";
30
        when "1111" => seg <= "0111000";
31
        when others => seg <= "0000000";
32
      end case;  
33
  end if;
34
  end process anzeigen;

ist denke ich der relevante Teil. Der Fehler ensteht in der Zeile mit 
dem dekodier switch einer Stelle: Selector (Slice name of type 
std_logic_vector) is an unconstrained array.


Wie macht man das besser bzw richtiger? Oder denke ich insgesamt zu 
c-mäßig? Bin bis eben ganz zufrieden gewesen mit mir :-( Und wenn ich 
nicht versuche die Nibbel zu den Stellen auszuschneiden, bekomm ich auch 
die 2 gewünschten Stellen - halt dann nur das selbe.

Außerdem die takt geschichte der clk3k_int wird aus einem taktteiler 
genommen. Im anderen Thread wurde explizit davor gewarnt so etwas als 
richtigen Takt zu benutzen. Ist das hier auch so? bei ca 3 kHz oder ist 
das eine Prinzipfrage.

danke und gute Nacht

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


Lesenswert?

Probiers mal so:
1
anzeigen : process (clk3k_int) 
2
  variable n : std_logic := '0'; -- n kann also nur 0 und 1 werden!!!!!!!
3
  variable anzeige : std_logic_vector(3 downto 0);
4
  begin
5
  
6
  if rising_edge(clk3k_int) then
7
      n <= not n; -- es gibt nur '0' und '1' (=nicht '0')
8
      --aktuelle Stelle auswählen
9
      case n is
10
        when '0'    => an <= "1110";   anzeige := cnt_int(3 downto 0);
11
        when others => an <= "1101";   anzeige := cnt_int(7 downto 4);
12
      end case;
13
      case anzeige is
14
        when "0000" => seg <= "0000001";
15
        :
16
        when "1111" => seg <= "0111000";
17
        when others => seg <= "0000000";
18
      end case;  
19
  end if;
20
  end process anzeigen;


> Bin bis eben ganz zufrieden gewesen mit mir
Naja, na gut, na sowas:
1
  variable n : integer range 0 to 1; -- n kann also nur 0 und 1 werden!
2
   :
3
   :
4
      n := n + 1;  -- was passiert, wenn n=1 ist?
5
                   -- der Überlauf ist nicht sauber abgefangen  :-(

BTW:
1
  if rising_edge(clk3k_int) then
Das gibt mir ein wenig zu Denken...
Wieviele Takte hast du denn in deinem FPGA-Design?

> der clk3k_int wird aus einem taktteiler genommen.
> wurde explizit davor gewarnt so etwas als Takt zu benutzen.
> Ist das hier auch so? bei ca 3 kHz oder ist das eine Prinzipfrage.
Ja. Als und für Anfänger gilt die zwingende Regel:
Genau 1 Takt im ganzen Design.

In deinem Fall wäre das besser so gelöst:
1
signal DisplayTakt : std_logic := '0';
2
- 50MHz FPGA-Takt, 3000Hz Display-Takt (warum eigentlich so hoch?)
3
signal DisplayTeiler : integer range 0 to 50000000/3000 := 0;
4
:
5
dispclk: process begin
6
   wait until rising_edge(clk); -- der FPGA-Takt
7
   if (DisplayTeiler < 50000000/3000) then
8
        DisplayTeiler <= DisplayTeiler+1;  
9
        DisplayTakt <= '0';
10
   else 
11
        DisplayTeiler <= 0;
12
        DisplayTakt <= '1';
13
   end if;
14
end process;
15
16
anzeigen : process (clk3k_int) 
17
  variable n : std_logic := '0'; 
18
  variable anzeige : std_logic_vector(3 downto 0);
19
  begin
20
  if rising_edge(clk) then -- der FPGA-Takt
21
      if (DisplayTakt='1') then
22
          n <= not n; 
23
          --aktuelle Stelle auswählen
24
          case n is
25
            when '0'    => an <= "1110";   anzeige := cnt_int(3 downto 0);
26
            when others => an <= "1101";   anzeige := cnt_int(7 downto 4);
27
          end case;
28
          case anzeige is
29
            when "0000" => seg <= "0000001";
30
            :
31
            when "1111" => seg <= "0111000";
32
            when others => seg <= "0000000";
33
          end case;  
34
      end if;
35
  end if;
36
  end process anzeigen;

Warum multiplext du deine 7 Segmente eigentlich mit 3 kHz? Da kommen ja 
kaum die Transistoren hinterher. Hast du nicht irgendwelche Schatten, 
Geistersegmente...?

von J.H. (Gast)


Lesenswert?

Danke erst mal, werde mir alles wie gewohnt in Ruhe zu Gemüte führen.

Ja stimmt - es gibt nur 0 und 1 für die Stellen. Momentan. Ich dachte um 
auf 4-stellig zu erweitern, wäre ein integer ganz gut schon eingeplant 
zu sein. Und daß der Überlauf 'automatisch' korrekt wird, hatte ich auch 
gedacht.

Ich habe in dem Design 3 Takte. Den 50 MHz Bordtakt, einen paar Hz 
zähltakt...naja und einen willkührlichen 3 kHz Multiplextakt. Werde den 
dann wohl auch schleunigst verringern. Danke für den Einwurf.

Warum ich mehrere takte habe und nicht einen fragst du dich. Nun das 
liegt daran, daß ich versucht habe, alle modularisieren. Sprich auf ein 
Display Modul hinzuarbeiten, was einfach einen Eingänge hat, die ich 
nachher als component beliebig verdrahten kann. In anderen Designs.
Ich bin aber überzeugt, daß es besser ist auch die multiplexzeiten 
direkt im Display Modul zu bestimmen. Mit Zähler und Systemtakt.


Ich bin um alle Kritik dankbar - ist ja auch nicht zu vermeiden. Es wird 
ja gerne davon gesprochen, daß man als Anfänger eh durch alle Fallen 
laufen muss und einige Fehlersuche wegstecken muss. Da habe ich halt das 
Problem: kein Prof, keine Kollegen o.ä., die überhaupt erst mal um die 
theoretischen Fehlerquellen und Gegenmaßnahmen wissen...sprich wenig 
externen Input um techniken und potentielle Fehler, da ist das Forum 
hier die einzige Quelle. :-) Naja zudem ist mein Gehirn ja auch nicht 
mehr das jüngste so daß neue Denke..sagen wir mal langsamer 
verinnerlicht wird.

von J.H. (Gast)


Lesenswert?

Ach ja: anhand des Beispiels sehe ich, wie du mit nur einem Takt umgehst 
und ich werde versuchen, das in meine Denkweise zu übernehmen. Wie 
gesagt: ursprünglich dachte ich es wäre weise, jedem Einzelmodul einen 
Takteingang zu verpassen, der dann beliebig einfach zugeführt wird.

Ich sehe das als ersten Lernschritt ;-) Denn Einsicht ist... Obwohl mir 
nciht wirklich bildlich klar ist, was da schiefgeht.
Ich vermute sobald da eine Erleuchtung einsetzt kann man auch sagen, es 
wären mehrere Takte handhabbar.

Besten Dank noch mal!

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


Lesenswert?

> Obwohl mir nciht wirklich bildlich klar ist, was da schiefgeht.
Wenn du diesen Takt mit einem DCM aus dem Haupttakt ableitest, geht das 
gut. Wenn du den allerdings aus einem Zähler ableitest, dann hast du je 
nach Platzierung auf dem FPGA unteschiedliche Laufzeiten der Takte 
(Skew). Und die können sich mit jeder kleinen Änderung des Designs 
mitändern. Das gibt dann so urige Fehlerbilder, dass ganz ein anderes 
Modul von irgendeiner klitzekleinen Änderung betroffen ist   :-o

von J.H. (Gast)


Lesenswert?

Also bei obigem Ansatz handelt es sich ja dann um diese erwähnte clock 
enable Geschichte. Werde das in zukunft erst mal so handhaben.

Aber einmal nachfragen müsst ich noch zum allgemeinen Verständnis der 
fpga. Angenommen ich habe in einem Design dann mehrere Komponenten, die 
einen stark geteilten Takt benötigen: dann wäre es auch angeraten, in 
JEDER Komponente die teilung durchzuführen und den system takt allen 
Komponenten einzuspeisen? Ich sehe da dann im Prinzip unnötig viele 
flipflops die dann benutzt werden. Denn jede Teilung verschlingt ja 
einige. (hatte mir gedacht von Anfang an möglichst viel als Komponenten 
zur Verfügung zu haben um die dann in neuen test Designs einfach 
verschalten zu können) Ist das erst mal egal und das fpga muss sonst 
einfach größer werden? klar das ist erst mal egal, aber ich meine jetzt 
auch mittelfristig und theoretisch gerechnet :-) Hätten so viele Teiler 
FFs auch schlechten Einfluss auf timings bei großen designs, weil alles 
'weiter' auseinander gerät?

Wie gesagt: mehr prinzipiell und auf Zukunft gerechnet, daß ich derzeit 
andere Probleme habe ist ja klar.

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


Lesenswert?

> dann wäre es auch angeraten, in JEDER Komponente die teilung
> durchzuführen und den system takt allen Komponenten einzuspeisen?
Es wird (um den Syntax gleich richtig zu verwenden) kein Takt geteilt, 
sondern ein Enable erzeugt. Dieses Enable-Signal ist immer nur 1 
Taktzyklus lang.

> Ich sehe da dann im Prinzip unnötig viele
> flipflops die dann benutzt werden.
Natürlich könntest du einen Enable-Generator bauen, und die Enables 
jedem Modul zuführen. Aber i.A. hat es sich bei mir bewährt, den Takt 
dort zu verwalten, wo er gebraucht wird.
BTW: Du hast im FPGA so viele Flipflops, dass du niemals alle verwenden 
kannst ;-)

> Hätten so viele Teiler FFs auch schlechten Einfluss auf timings
> bei großen designs, weil alles 'weiter' auseinander gerät?
Solche Laufzeit-Fragen werden über Timing-Constraints geregelt  ;-)
Wenn nötig, werden irgendwelche FFs von der Toolchain verdoppelt,
bzw. wenn möglich zusammengefasst.

von J.H. (Gast)


Lesenswert?

ok noch ein verzweifelter Versuch dann muss ich mir glaub ich 
eingestehen dafür vielleicht einfach nicht tauglich zu sein....
Warum funktinoiert das nicht? Rein synthaktisch schon nicht bei der 
unteren Zuweisung wo ich gern die Richtung anpassen würde gibt es 
irgendwas illegales. Unexpected LE.
1
entity shifter2_vhd is
2
3
  generic(SLOW_CLK : natural := 10);
4
  port(  mclk : in std_logic;
5
      --en : in std_logic;
6
      leds : out std_logic_vector(7 downto 0));
7
      
8
end shifter2_vhd;
9
10
11
architecture Behavioral of shifter2_vhd is
12
signal leds_int : std_logic_vector(7 downto 0) := X"01";
13
signal clk_division : integer range 0 to 50000000/SLOW_CLK := 0;
14
signal shift_clk: std_logic;
15
signal updown : std_logic := '0'; 
16
begin
17
  slow_clock : process 
18
  begin
19
    wait until rising_edge(mclk);
20
    if( clk_division < 50000000/SLOW_CLK) then
21
      clk_division <= clk_division + 1;
22
      shift_clk <= '0';  
23
    else
24
      clk_division <= 0;
25
      shift_clk <= '1';  
26
    end if;
27
  end process slow_clock;
28
29
  shift_leds : process(shift_clk, mclk) 
30
  
31
  begin
32
    if( rising_edge(mclk)) then
33
      if( shift_clk = '1') then
34
        case updown is
35
        when '0' =>
36
            leds_int <= leds_int(6 downto 0) & leds_int(7);        
37
        when others =>
38
            leds_int <= leds_int(0) & leds_int(6 downto 0);
39
        end case;
40
      end if;
41
    end if;
42
  end process shift_leds;
43
  
44
  leds <= leds_int;
45
  
46
  updown <= '1' when leds_int(7) = '1' else
47
        <= '0' when leds_int(0) = '1' else
48
       <= updown;
49
  
50
end Behavioral;

das kann doch an sich nicht so schwer sein dachte ich. OK vielleicht 
unnötig kompliziert, aber nach der Starthilfe hatte ich den Anspruch die 
Schnipsel zu etwas vermeindlich leichtem zusammenfügen zu können :-(

von J.H. (Gast)


Lesenswert?

1
begin
2
    if( rising_edge(mclk)) then
3
      if( shift_clk = '1') then
4
        case updown is
5
        when '0' =>
6
            leds_int <= leds_int(6 downto 0) & leds_int(7);  
7
            if(leds_int(6)='1') then
8
              updown <= '1';
9
            end if;
10
        when others =>
11
            leds_int <= leds_int(0) & leds_int(7 downto 1);
12
            if(leds_int(1)='1') then
13
            updown <= '0';
14
            end if;
15
        end case;
16
      end if;
17
    end if;
18
  end process shift_leds;
19
  
20
  leds <= leds_int;

Ich habe das jetzt so hingedengelt. Es macht was es soll, ich bin 
dennoch recht enttäuscht nicht der Kapitän im Boot zu sein.
Wie erschlage ich das Problem sinnvoll? Woher kam obige Meldung, denn 
die habe ich nicht wegbekommen.
und: ist das normal oder sollte ich doch lieber etwas anderes machen 
statt mich ohne zu müssen mit dieser Materie auseinander zu setzen? 
Wissenshunger kann böse nagen, wenn man ihn nicht stillen kann....

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


Lesenswert?

1
 updown <= '1' when leds_int(7) = '1' else
2
        <= '0' when leds_int(0) = '1' else
3
        <= updown;
Sowas sollte man nicht machen, wenn man nicht genau weiß, was man da 
tut. Das gibt ein Latch!!!
Und hinter einem Latch!!! stehen immer ein paar Ausrufezeichen...

Denn wenn das Steuersignal (leds_int(0 bzw. 7)) eines Latches!!! einen 
Spike enthält, na gut, dann schlägt das Ding zu, oder auch nicht   :-o
Zudem ist das Ding nur zu sich selbst synchron.

Beschreib das deine Richtungsumschaltung getaktet in einem Prozess, das 
ist der richtige Weg (so ähnlich, wie du es gemacht hast):
1
 process (clk) begin
2
    if (rising_edge(mclk)) then
3
       if    (leds_int(7) = '1') then updown <= '1'; 
4
       elsif (leds_int(0) = '1') then updown <= '0'; 
5
       end if;
6
    end if;
7
 end process;
Das wäre die direkte Umsetzung deines originalen Codes.

Aber du hast doch auch eine Lösung gefunden, ist doch gut ;-)
Nur hast du in deinem Code einen ganzen Shift-Clock Latency mit drin:
>   if(leds_int(6)='1') then
>   if(leds_int(1)='1') then

von Verilog-Schüler (Gast)


Lesenswert?

Warum sich mit VHDL abplagen?

1
module led_shifter(
2
  output reg [LED_BITS-1:0]  leds,
3
  input                      clk,
4
  input                      reset);
5
6
  parameter CLK_DIV          = 5;
7
  parameter DIV_BITS         = 3;
8
  parameter LED_BITS         = 8;
9
10
  reg [DIV_BITS-1:0] counter;
11
  reg up_down;
12
  wire [LED_BITS-1:0] next_leds;
13
  wire next_up_down, step;
14
15
  assign step = counter == CLK_DIV - 1;
16
17
  assign next_up_down = leds[0] ? 1 : leds[LED_BITS-1] ? 0 : up_down;
18
  
19
  assign next_leds = next_up_down ? leds << 1 : leds >> 1;
20
  
21
  always @(posedge clk)
22
    if (reset || step)
23
      counter <= 0;
24
    else
25
      counter <= counter + 1;
26
27
  always @(posedge clk)
28
    if (reset) begin
29
      leds <= 1;
30
      up_down <= 1;
31
    end else if (step) begin
32
      leds <= next_leds;
33
      up_down <= next_up_down;
34
    end
35
36
endmodule

Alternativ könnte man es auch so schreiben, wenn man den "funktionalen" 
Ansatz nicht mag:

1
module led_shifter(
2
  output reg [LED_BITS-1:0]  leds,
3
  input                      clk,
4
  input                      reset);
5
6
  parameter CLK_DIV          = 5;
7
  parameter DIV_BITS         = 3;
8
  parameter LED_BITS         = 8;
9
10
  reg [DIV_BITS-1:0] counter;
11
  reg up_down;
12
  reg [LED_BITS-1:0] next_leds;
13
  reg next_up_down, step;
14
15
  always @(*)
16
    if (counter == CLK_DIV)
17
      step = 1;
18
    else
19
      step = 0;
20
21
  always @(*)
22
    if (leds[0])
23
      next_up_down = 1;
24
    else if (leds[LED_BITS-1])
25
      next_up_down = 0;
26
    else
27
      next_up_down = up_down;
28
29
  always @(*)
30
    if (next_up_down)
31
      next_leds = leds << 1;
32
    else
33
      next_leds = leds >> 1;
34
  
35
  always @(posedge clk)
36
    if (reset || step)
37
      counter <= 0;
38
    else
39
      counter <= counter + 1;
40
41
  always @(posedge clk)
42
    if (reset) begin
43
      leds <= 1;
44
      up_down <= 1;
45
    end else if (step) begin
46
      leds <= next_leds;
47
      up_down <= next_up_down;
48
    end
49
50
endmodule

Ich hab mich noch nicht entschieden, was mir besser gefällt. Die erste 
Veriante gerantiert, dass man keine Latches baut. Die zweite Veriante 
scheint weiter verbreitet zu sein, oder?

von berndl (Gast)


Lesenswert?

gemach, gemach...

du kannst die ADA Programmierer hier nicht mit deinem C-Code 
(==portierbarer Assembler) ueberfallen :o)

Die erste Variante ist definitiv besser zu verstehen, auch wenn du bei 
den 'assign' schon in die Trickkiste greifst. Unter VHDL ist das alles 
deutlich langatmiger zu beschreiben, hat aber den Vorteil, dass es auch 
nach Jahren noch sofort verstaendlich wird. Bei Verilog muss man sich 
dann schon gaaaanz genau den Code anschauen. Aber ich mag' Verilog auch, 
hat schon was....

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


Lesenswert?

> Ich hab mich noch nicht entschieden, was mir besser gefällt. Die erste
> Veriante gerantiert, dass man keine Latches baut. Die zweite Veriante
> scheint weiter verbreitet zu sein, oder?
Welche Lösung braucht weniger Ressourcen?

> ...Veri-ante...
Kommt das von Vari-log?
Korrekt wäre: Variante, Verilog  ;-)

von Verilog-Schüler (Gast)


Lesenswert?

> Die erste Variante ist definitiv besser zu verstehen, auch wenn du
> bei den 'assign' schon in die Trickkiste greifst.

Naja, Du meinst, meistens wird einfach

1
wire foobar = ...;

anstatt

1
wire foobar;
2
3
...
4
5
assign foobar = ...;

geschrieben?

Ansonsten finde ich das nicht sonderlich "trickreich". Vielleicht liegt 
es daran, dass ich schon einiges in funktionalen Sprachen geschrieben 
habe und "assign" einfach als "Bindungs-Operator" verstehe. Verilog mach 
ich aber erst seit 3 Wochen.


> Welche Lösung braucht weniger Ressourcen?

Beide Lösungen sind (bis auf einen kleinen Fehler, wer findet ihn?) 
absolut identisch.

von Full W. (realjey)


Lesenswert?

Ich reihe mich mal ein:

Ist es möglich 2 Pins gleichzeitig in einer IF- oder Select-Anweisung 
abzufragen? Habe iwie kein passendes Bsp im Netz gefunden.

habs schonmal mit

if(pin1='1' & pin2='1') then

und

if(pin1='1' and pin2='1') then

probiert, funzt aber nicht....

die Pins sind als "inout" deklariert....

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


Lesenswert?

Jey Soon schrieb:
> Ist es möglich 2 Pins gleichzeitig in einer IF- oder Select-Anweisung
> abzufragen?
Ja.  Dein Problem liegt irgendwo anders.

> if(pin1='1' & pin2='1') then
Das geht nicht, weil das & der Verknüpfungsoperator ist.
So ginge es wieder:
> if(pin1&pin2 = "11") then

> die Pins sind als "inout" deklariert....
Wozu das?
Ist es wirklich ein IO-Port?
Oder bist du nur schreibfaul?

von Full W. (realjey)


Lesenswert?

sry,
es sind natürlich reine IN-Ports, ich möchte sie als Hand-Signal für ein 
Handshake benutzen

von Full W. (realjey)


Lesenswert?

sry,
es sind natürlich reine IN-Ports, ich möchte sie als Hand-Signal für ein 
Handshake benutzen

und: Danke für die Antwort

sry für Doppelpost, mein Browser hat sich wohl verhaspelt

von Clemens M. (panko)


Lesenswert?

Mir fällt rückblickend auf das Beispiel mit dem spi ADC oben auf, daß 
Lothar Miller wieder super geholfen hat.
Ich frage mich nun aber, warum dort nun cs als externes Signal keine 
Eintaktung erfahren muss. Sdo kommt ja in ein Schieberegister rein, das 
leuchtet mir da noch ein, aber weshalb darf cs einfach so abgefragt 
werden?

danke!

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


Lesenswert?

Clemens M. schrieb:
> aber weshalb darf cs einfach so abgefragt werden?
Bezogen auf den Beitrag "Re: Der vhdl-Schnipsel-Anfängerfragen Thread"
Sollte/dürfte eigentlich nicht so sein... :-/
Aber ehrlich gesagt war der Code da so verwurstelt, dass mir das nicht 
aufgefallen ist... ;-)

> aber weshalb darf cs einfach so abgefragt werden?
Nur, wenn es als Takt verwendet wird ;-)
Denn dann muß dort vom Hardware-Design eine brauchbare Signalqualität 
garantiert werden, und dann ist es zu sich selber garantiert synchron... 
;-)

von Torben S. (torben_s)


Lesenswert?

Hallo,

ich hoffe dies ist der richtige Thread um eine Anfängerfrage zu stellen 
:)

Wenn ich in einem VHDL-Modul mit einem niedrigeren Takt arbeiten möchte, 
z.B. um etwas für das Auge sichtbar zu machen, ist es dann korrekt, wenn 
ich so vorgehe?

- Mein Modul erhält als Eingang Clock, also Boardtakt
- Im Modul erzeuge ich mir ein "Clock-Enable", dass die richtige 
Frequenz hat
- Ich gucke im entsprechenden Process, ob:
1
process (Clock)
2
begin
3
 if rising_edge(Clock) then
4
   if Clock_Enable = '1' then
5
     tu was...
6
   end if;
7
 end if;

Wenn ich nun zwei verschiedene langsame Takte brauche, ist es dann ok, 
wenn ich in einem Modul zwei verschiedene Clock_Enable habe?

von Torben S. (torben_s)


Lesenswert?

Hallo,

gleich noch eine zweite Frage in diese Richtung:

Wenn ich zwei VHDL-Module hintereinander habe. Das Erste liest Daten mit 
einer hohen Frequenz ein und stellt sie am Ausgang bereit, z.B. nach 
Mittelwertbildung. Das zweite Modul holt sich die Daten mit niedrigerer 
Frequenz ab und gibt sie z.B. aus.

Wie schaffe ich es, dass die Module synchron sind, obwohl sind mit 
unterschiedlichen Frequenzen arbeiten?

- Kann ich beiden den Systemclock geben und im zweiten füge ich 
Clock_Enable ein, sodass immer noch die steigende Flanke vom Systemclock 
detektiert wird, aber die Ausgabe nur läuft, wenn auch das langsamere 
Clock_Enable ansteht?

Sry für die vielleicht blöden Fragen, aber ich komme eher aus der 
Programmierungsecke...

Danke :)

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


Lesenswert?

Torben S. schrieb:
> odass immer noch die steigende Flanke vom Systemclock detektiert wird
Du hast die falsche Vorstellung davon, wie deine VHDL Beschreibung in 
Hardware umgesetzt wird. Eine Taktflanke wird nicht irgendwie 
"detektiert", sondern der Takt geht an Takteingänge von D-Flipflops.

Du musst dir klar machen, dass es im FPGA zur Umsetzung deiner 
Beschreibung genau 2 Bauteile gibt: LUTs für die Logik und Flipflops als 
Speicherelemente.

Such mal hier im Forum nach meinen Postulaten. Das Wichtigste daran ist, 
dass ein Anfängerdesign nur 1 Takt hat und der Rest wie von dir 
beschrieben mit Clock-Enables gemacht wird.

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.