Forum: FPGA, VHDL & Co. Flanke erkennen, Signal setzen


von Dennis R. (dennis84)


Lesenswert?

Hallo,
ich scheitere gerade an einem vermutlich ganz simplen Problem. Ich habe 
ein VALID-Signal, welches 5000 mal pro Sekunde kurz auf LO geht und 
sonst HI ist. Wenn es auf LO ist, möchte ich das SIGNAL BOXOUT auf 0 
setzen und erst bei einer steigenden Kante auf HI gehen. Hier der Code:


STEIGENDE_FLANKE: process (BOX, VALID, CLK)
        begin
         IF VALID = '0'
         THEN
         BOXOUT <= '0';
        END IF;

         if VALID ='1' AND rising_edge(BOX)
         THEN
         BOXOUT <= '1';
        end if;
    end process STEIGENDE_FLANKE;


Fehlermeldung: statement is not synthesizable since it does not hold its 
value under NOT(clock-edge) condition

Fragen:
1. Wie kann ich den Fehler beseitigen?
2. Ich möchte den Code anschließend erweitern. So soll bei steigender 
Flanke ein Counter starten, der nach einiger Zeit ein anderes Signal auf 
HI setzt. Dazu würde ich Clock-Impulse zählen. Ist das Programm 
dementsprechend überhaupt erweiterbar?

von P. K. (pek)


Lesenswert?

Vielleicht etwas in der Art?
1
STEIGENDE_FLANKE: process (BOX, VALID, CLK)
2
     begin
3
       IF VALID = '0' THEN
4
         BOXOUT <= '0';
5
       elsif rising_edge(BOX) THEN
6
         IF VALID = '1' THEN
7
           BOXOUT <= '1';
8
         end if;
9
       end if;
10
     end process STEIGENDE_FLANKE;

von Cihan K. (lazoboy61)


Lesenswert?

Ich würde es so machen
1
STEIGENDE_FLANKE: process (CLK)
2
begin
3
  IF rising_edge(CLK) THEN -- eine schnelle Clock vorausgesetzt
4
    IF VALID = '0' THEN
5
      BOXOUT <= '0';
6
    ELSIF VALID = '1' AND (BOX = '1' AND BOX_v = '0') THEN -- BOX_v um pos. Flanke zu erkennen!
7
      BOXOUT <= '1';
8
    END IF;
9
    BOX_v <= BOX;
10
  END IF;
11
END PROCESS STEIGENDE_FLANKE;

Cihan

von Cihan K. (lazoboy61)


Lesenswert?

Dennis R. schrieb:
> So soll bei steigender
> Flanke ein Counter starten, der nach einiger Zeit ein anderes Signal auf
> HI setzt. Dazu würde ich Clock-Impulse zählen. Ist das Programm
> dementsprechend überhaupt erweiterbar?

bei steigender Flanke von was, CLK? oder BOX?
Kannst du bitte am besten dein Vorhaben genauer beschreiben?


Cihan

von Cihan K. (lazoboy61)


Lesenswert?

Cihan Kalayci schrieb:
> Ich würde es so machen
>
>
1
> STEIGENDE_FLANKE: process (CLK)
2
> begin
3
>   IF rising_edge(CLK) THEN -- eine schnelle Clock vorausgesetzt
4
>     IF VALID = '0' THEN
5
>       BOXOUT <= '0';
6
>     ELSIF VALID = '1' AND (BOX = '1' AND BOX_v = '0') THEN -- BOX_v um
7
> pos. Flanke zu erkennen!
8
>       BOXOUT <= '1';
9
>     END IF;
10
>     BOX_v <= BOX;
11
>   END IF;
12
> END PROCESS STEIGENDE_FLANKE;
13
>
>
> Cihan

Die Abfrage von VALID = '1' kann man ja auch weglassen.

Also so sollte es auch gehen:
1
STEIGENDE_FLANKE: process (CLK)
2
begin
3
  IF rising_edge(CLK) THEN -- eine schnelle Clock vorausgesetzt
4
    IF VALID = '0' THEN
5
      BOXOUT <= '0';
6
    ELSIF BOX = '1' AND BOX_v = '0' THEN -- BOX_v um pos. Flanke zu erkennen!
7
      BOXOUT <= '1';
8
    END IF;
9
    BOX_v <= BOX;
10
  END IF;
11
END PROCESS STEIGENDE_FLANKE;

Cihan

von Dennis R. (dennis84)


Angehängte Dateien:

Lesenswert?

Hallo,
ah vielen Dank für die Antwort. Also als Abzweigung muss man das machen. 
Leider ist es jetzt so, dass das Signal auch bei der fallenden Kante 
manchmal - wenn auch selten - umschaltet. Ich habe das entsprechende 
Bild mit dem Oszi mal angehängt.

Gelb - Valid
Blau - Box
Lila - Boxout

Mit dem Scope kann ich nicht erkennen, dass die fallende Kante 
"unsauber" ist, sprich noch einmal kurz eine steigende Flanke darin 
enthalten ist. Scheinbar ist dies dennoch der Fall, da die 
Flankenerkennung hier anspringt. Kann man in VHDL eine Art Totzeit 
einrichten? Oder gibt es dafür eine andere Erklärung?

von Cihan K. (lazoboy61)


Lesenswert?

Mit welcher CLK Geschwindigkeit tastet du ab
und wer erzeugt bzw. steuert VALID und BOX?

Cihan

von Schlumpf (Gast)


Lesenswert?

Und welche der vielen Möglichkeiten hast du jetzt umgesetzt?
Bissle mehr Info bitte

von Dennis R. (dennis84)


Lesenswert?

Das Bild ist mit folgendem Code entstanden.

STEIGENDE_FLANKE: process (BOX, VALID, CLK)
     begin
       IF VALID = '0' THEN
         BOXOUT <= '0';
       elsif VALID ='1' AND rising_edge(BOX) THEN
         BOXOUT <= '1';
      QINT2 <= QINT2 + 1;
       end if;
end process STEIGENDE_FLANKE;


VALID ist ein Signal, welches das FPGA selbst in einem anderen Prozess 
erzeugt. BOX ist ein Signal, welches ursprünglich von einem Array stammt 
und aufbereitet wurde. Dieses geht an einen Pin das FPGA. CLK ist ein 
externer Taxt mit 20MHz bzw. 24 MHz, je nach Bestückung.

von Cihan K. (lazoboy61)


Lesenswert?

Hast du nun 2 Clocks (20MHz und 24 MHz) in deinem Design?

Es sieht irgendwie danach aus, als ob du Taktdomäne hättest.

Mit welcher Clock wird VALID und BOX erzeugt?
Dementsprechend mit welcher Clock läuft dein Prozess "STEIGENDE_FLANKE"?

Evtl. musst du deine Signale erst einsynchronisieren und dann erst 
abfragen.

Cihan

von Cihan K. (lazoboy61)


Lesenswert?

Dennis R. schrieb:
> BOX ist ein Signal, welches ursprünglich von einem Array stammt
> und aufbereitet wurde. Dieses geht an einen Pin das FPGA.

Meinst du damit, dass er von außen kommt, also über einen I/O Pin des 
FPGAs?

Cihan

von Dennis R. (dennis84)


Lesenswert?

Das CLK kommt von einem Quarz. Der läuft aktuell mit 20MHz und es gibt 
nur diesen einen im System. Später wollte ich diesen jedoch auslöten und 
stattdessen einen 24MHz auflöten. Also aktuell nur einen CLK Takt mit 20 
MHz im System und für diesen Prozess.

Richtig, BOX kommt von außen über einen I/O.

von Cihan K. (lazoboy61)


Lesenswert?

Dann müsstest du das Signal BOX nochmal einfach im gleichen Prozess 
einsynchronisieren.

Schau dir mal am besten folgendes an:
http://www.lothar-miller.de/s9y/categories/35-Einsynchronisieren

Hat Lothar hier sehr schön erklärt.

Das Bild im vorherigen Beitrag auf dem Oszilloskopen zeigt dir an der 
neg. Flanke von BOX(blau) an, dass evtl. Spikes sich eingefangen haben. 
Dementsprechend müsstest du ihn nur einsynchronisieren und es sollte 
dann auch laufen.

Cihan

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


Lesenswert?

Dennis R. schrieb:
> 1. Wie kann ich den Fehler beseitigen?
Es ist kein Fehler, es ist die falsche Denkweise!

> welches 5000 mal pro Sekunde kurz auf LO geht und
> sonst HI ist. Wenn es auf LO ist, möchte ich das SIGNAL BOXOUT auf 0
> setzen und erst bei einer steigenden Kante auf HI gehen. Hier der Code:
Ich würde mal erst den 20MHz Takt auf 80-100MHz aufblasen und dann 
synchron arbeiten. Dann wird die Flankenerkennung ein Kinderspiel mit 
einem Schieberegister:
http://www.lothar-miller.de/s9y/categories/18-Flankenerkennung

> Kann man in VHDL eine Art Totzeit einrichten?
Zeiten werden in FPGAs idR. über Zähler oder Schieberegister erledigt.

von Schlumpf (Gast)


Lesenswert?

Dein Problem ist vermutlich, dass VALID und BOX keinen zeitlichen Bezug 
zueinanderen haben. Daher kann es passieren, dass VALID gerade seinen 
Zustand ändert, wenn das mit BOX getaktete Register seine Flanke erhält. 
Dadurch bekommst du eine Setupzeit-Verletzung am Register und bum...

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


Lesenswert?

Schlumpf schrieb:
> Dadurch bekommst du eine Setupzeit-Verletzung am Register und bum...
Das ist in 99,9% aller Fälle noch nicht mal das eigentliche Problem. 
Viel schlimmer ist es, wenn dieses externe Signal an 2 Flipflops im FPGA 
geht. Und die bei einem Pegelwechsel wegen unterschiedlicher 
Signallaufzeiten unterschiedliche Pegel sehen, und so beim passenden 
Taktimpuls die FSM in die Wüste fährt...

Dort wurde das schon angesprochen:
Cihan Kalayci schrieb:
> Schau dir mal am besten folgendes an

von Schlumpf (Gast)


Lesenswert?

Lothar Miller schrieb:
> Viel schlimmer ist es, wenn dieses externe Signal an 2 Flipflops im FPGA
> geht. Und die bei einem Pegelwechsel wegen unterschiedlicher
> Signallaufzeiten unterschiedliche Pegel sehen, und so beim passenden
> Taktimpuls die FSM in die Wüste fährt...

stimmt.. vorallem ist es noch deutlich wahrscheinlicher, dass dieser 
Zustand auftritt..

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


Lesenswert?

Schlumpf schrieb:
> vorallem ist es noch deutlich wahrscheinlicher, dass dieser
> Zustand auftritt..
Und vor allem wird dieser Effekt auch bei beliebig niedrigen 
Taktfrequenzen auf. Da reicht sogar ein einziger Taktimpuls...

von Schlumpf (Gast)


Lesenswert?

... und vorallemallemallem bekommt man ne Setupzeitverletzung aber auch 
bei beliebig niedrigen Taktfrequenzen hin... :-) Also das Argument lass 
ich nicht gelten gg

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


Lesenswert?

Schlumpf schrieb:
> ... und vorallemallemallem bekommt man ne Setupzeitverletzung aber auch
> bei beliebig niedrigen Taktfrequenzen hin... :-)
> Also das Argument lass ich nicht gelten gg
Diese Setup-Verletzung juckt aber schon gar überhaupt niemanden, wenn 
das nur 1 einziges Flipflop betrifft. Weil sich das FF nämlich gleich 
nach der Timingverletzung (und einem evtl. folgenden kurzen metastabilen 
Zustand) recht schnell entscheidet, ob es den Pegelwechsel jetzt 
mitbekommen hat oder nicht.
Und beim (potentiellen) nächsten Takt wird dann das Flipflop schon den 
richtigen Pegel abbekommen...

von Schlumpf (Gast)


Lesenswert?

Lothar Miller schrieb:
> Diese Setup-Verletzung juckt aber schon gar überhaupt niemanden, wenn
> das nur 1 einziges Flipflop betrifft.

stimmt, aber genauso wenig würde es bei nur einem FF interessieren, wenn 
die Laufzeiten zwischen den beiden (einem) FF unterschiedlich ist und 
somit zu undefinierten Zuständen in einer FSM führen :-)

Zusammenfassen würde ich es so:
Wir denken beide gerade an das gleiche Problem, welches durch 
unterschiedliche Ursachen hervorgerufen werden kann.

Problem:
Mehrere FFs die aufgrund etwas "schwammiger" Zustände zum Zeitpunkt der 
Taktflanke einen zueinander inkonsistenten Zustand einnehmen, der 
unerwünscht oder nicht definiert ist und zu Fehlverhalten im System 
führen kann.

Ursachen:
- Nicht synchronisierter Eingang, der durch unterschiedliche 
Arrival-Times relativ zum Takt an den FF zu diesem Effekt führen kann.

- Setupzeit-Verletzungen bei dem einen oder anderen FF, aufgrund eines 
Flankenwechsels des Eingangs, der bei dem einen FF die eine und bei dem 
anderen FF ne andere Auswirkung hat und somit zu den Inkonsistenzen 
führt.

Letztendlich meinen wir den gleichen Effekt, hervorgerufen durch 
unterschiedliche Mechanismen.
Aber in beiden Fällen ist es mit nur EINEM Flip-Flop das zu nichts 
anderem im System konsistent sein muss, kein Problem. Bei mehreren FF, 
die zueinander konsistent sein müssen, ist es aber in beiden Fällen ein 
Problem..

oder lieg ich jetzt komplett daneben?

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


Lesenswert?

Schlumpf schrieb:
> - Setupzeit-Verletzungen bei dem einen oder anderen FF, aufgrund eines
> Flankenwechsels des Eingangs, der bei dem einen FF die eine und bei dem
> anderen FF ne andere Auswirkung hat
Aber diese zeitlichen Unterschiede zwischen und in 2 Flipflops sind 
bestenfalls noch dem Routing zuzurechnen, sodass letztlich wieder nur 1 
Effekt übrigbleibt.
Und diesem Effekt kann man dann auch gleich noch Fertigungstoleranzen in 
die Schuhe schieben, wenn z.B. ein FF etwas mehr Energie zum Umschalten 
braucht (und demzufolge eine größere Setupzeit hat)...

Schlumpf schrieb:
> Aber in beiden Fällen ist es mit nur EINEM Flip-Flop das zu nichts
> anderem im System konsistent sein muss, kein Problem. Bei mehreren FF,
> die zueinander konsistent sein müssen, ist es aber in beiden Fällen ein
> Problem..
>
> oder lieg ich jetzt komplett daneben?
Ja, es gibt keine 2 Fälle...  ;-)
Es ist der gleiche Effekt, denn auch in dem von mir skizzierten Fall 
geht es darum, dass auf irgendeine Art (marginal unterschiedliche 
Laufzeit und in der Folge höchstwahrscheinlich eine Zeitverletzung 
mindestens bei einem der Flipflops) ein Flipflop noch den "alten" Pegel 
übernimmt, das Andere aber schon den "neuen" Pegel.

Und die Ausnutzung des Umstands, dass dieser Effekt bei EINEM Flipflop 
gar nicht auftreten kann, nennt man "Eintakten" oder 
"Einsynchronisieren"...

von Schlumpf (Gast)


Lesenswert?

Lothar Miller schrieb:
> Es ist der gleiche Effekt,


Richtig ;-)
Denn letztendlich ist es egal, wo sich die Signale rumgetrieben haben, 
bis sie am Register angekommen sind.. Blöd ist nur, wenn sie nicht alle 
pünktlich zur Flanke erscheinen und dann Blödsinn in den Registern 
steht..

von Josef G. (bome) Benutzerseite


Lesenswert?

Lothar Miller schrieb:
> Viel schlimmer ist es, wenn dieses externe Signal an 2 Flipflops im FPGA
> geht. Und die bei einem Pegelwechsel wegen unterschiedlicher
> Signallaufzeiten unterschiedliche Pegel sehen, und so beim passenden
> Taktimpuls die FSM in die Wüste fährt...

Bei Flipflops mit hoher Ausgangsbelastung kommt es vor, dass die
Synthese-Software die Flipflops eigenmächtig mehrfach anlegt.
Wenn das einzusynchronisierende Signal von aussen kommt, wird das
vermutlich dadurch verhindert, dass ein Eingangs-FF im IO-Block
verwendet wird. Wie sieht das aus bei zwei Takt-Domänen
innerhalb des FPGA? Kann man die FF-Verdopplung gezielt
für ein bestimmtes FF verbieten, oder geht das nur global?

von P. K. (pek)


Lesenswert?

> Kann man die FF-Verdopplung gezielt
> für ein bestimmtes FF verbieten, oder geht das nur global?

Würde etwas in dieser Art versuchen:

set_instance_assignment -name physical_synthesis_register_duplication 
-to <to> -entity
 <entity name> <value>

Oder, noch besser, zwei FF's in Reihe benutzen, das erste synchronisiert 
den Clockübergang und hat fan-out 1, das zweite hat dann den grossen 
Fan-Out und wird (möglicherweise) dupliziert, was aber nicht weiter 
tragisch ist.

von Dennis R. (dennis84)


Angehängte Dateien:

Lesenswert?

Ich würde mal erst den 20MHz Takt auf 80-100MHz aufblasen
> Werde ich machen.


http://www.lothar-miller.de/s9y/categories/18-Flankenerkennung
> Da Box bei mir das nicht-synchrone Signal ist, habe ich daraus folgendes 
gemacht:

FLANKE_ERKENNEN: process
variable sr : std_logic_vector (3 downto 0) := "0000";
    begin
      wait until rising_edge(clk);
      rise <= not sr(3) and sr(2) ;
      fall <= not sr(2) and sr(3);
      sr := sr(2 downto 0) & BOX;
end process FLANKE_ERKENNEN;


Ich verstehe das nur zum Teil: Also ich warte bis ich eine steigende 
Flanke beim Clock-Signal habe. Dann sehe ich mir die "Bitübergänge" in 
dem Array an und sehe dadurch, ob ein 0->1 oder 1->0 Wechsel vorliegt. 
Bei sr := sr(2 downto 0) & BOX; habe ich eine Bitweise verundung mit dem 
asynchronen Signal. Nur warum funktioniert das mit der letzten Zeile 
(bzw. wie?)?

Um keine Probleme mit unsauberen Flanken beim Box-Signal zu bekommen, 
habe ich eine kleine Hysterese in meiner Elektronik eingeführt. Ich sehe 
auf dem Oszi (Bild beigefügt) nun keine Falschimpulse mehr. Zur 
Sicherheit müsste ich vielleicht aber später noch eine Totzeit einfügen.

Habe ich also ein Signal von außen, muss ich eine Synchronisation 
vorschalten? Arbeite ich jedoch dann intern weiter, ist dies nicht mehr 
nötig (wie zum Beispiel bei der folgenden Weiterverarbeitung, wo bei der 
Flanke ein Zähler abgefragt und der Wert abgespeichert werden soll)?

STEIGENDE_FLANKE_SPEICHERN: process(rise)
    begin
     if rising_edge(rise) AND VALID ='1' THEN
    ZAEHLWERT_STEIGENDE_FLANKE <= QINT;
    end if;
end process STEIGENDE_FLANKE_SPEICHERN;

von Cihan K. (lazoboy61)


Lesenswert?

Eigentlich hätte ich das mit der Einsynchronisation folgendermaßen 
gemacht:
1
SIGNAL R1_BOX, R2_BOX, i_BOX, BOX_v: STD_LOGIC;
2
3
STEIGENDE_FLANKE: process (CLK)
4
begin
5
  IF rising_edge(CLK) THEN -- eine schnelle Clock vorausgesetzt
6
    R1_BOX <= BOX; -- hier asynchron
7
    R2_BOX <= R1_BOX;
8
    i_BOX  <= R2_BOX; -- hier synchron, i_BOX kann verwendet werden
9
    IF VALID = '0' THEN
10
      BOXOUT <= '0';
11
    ELSIF i_BOX = '1' AND BOX_v = '0' THEN -- BOX_v um pos. Flanke zu erkennen!
12
      BOXOUT <= '1';
13
    END IF;
14
    BOX_v <= i_BOX;
15
  END IF;
16
END PROCESS STEIGENDE_FLANKE;

Dennis R. schrieb:
> STEIGENDE_FLANKE_SPEICHERN: process(rise)
>     begin
>      if rising_edge(rise) AND VALID ='1' THEN
>     ZAEHLWERT_STEIGENDE_FLANKE <= QINT;
>     end if;
> end process STEIGENDE_FLANKE_SPEICHERN;

Und sowas immer so:
1
STEIGENDE_FLANKE_SPEICHERN: process(rise)
2
    begin
3
     if rising_edge(rise) THEN
4
       if VALID ='1' THEN
5
         ZAEHLWERT_STEIGENDE_FLANKE <= QINT;
6
       end if;
7
    end if;
8
end process STEIGENDE_FLANKE_SPEICHERN;

Benutze mal bitte am besten die [vhdl] MAKROS, um deinen Quellcode 
besser darzustellen.

Cihan

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


Angehängte Dateien:

Lesenswert?

Cihan Kalayci schrieb:
> Benutze mal bitte am besten die [vhdl] MAKROS, um deinen Quellcode
> besser darzustellen.
Richtig. Die Tokens werden etwa so wie im Screenshot angewendet (nur 
eben [vhdl] statt [c]).

> Eigentlich hätte ich das mit der Einsynchronisation folgendermaßen
> gemacht:
Das ergibt das gleiche wie die Schieberegistergeschichte. Es ist nur auf 
wesentlich mehr Zeilen verteilt...

Dennis R. schrieb:
> Ich verstehe das nur zum Teil: Also ich warte bis ich eine steigende
> Flanke beim Clock-Signal habe.
Falsche Denkweise!
Du "wartest" nicht auf eine Taktflanke, sondern wegen einer Taktflanke 
wird irgendwas im FPGA passieren.

> Bei sr := sr(2 downto 0) & BOX; habe ich eine Bitweise verundung mit dem
> asynchronen Signal.
Nein. Das & ist in VHDL eine Aneinanderhängung (Concatenation). Eine 
Verundung erreichst du mit AND.
Mit  sr := sr(2 downto 0) & BOX
wird also aus sr(2), sr(1), sr(0) und BOX ein neuer 4-Bit Vektor 
gemacht, und der dann an sr zugewiesen.

von Dennis R. (dennis84)


Lesenswert?

Ich versuche in Zukunft immer die Makros zu verwenden. Den Code habe ich 
auf das umgestellt, was Cihan Kalayci (lazoboy61) im unteren Teils 
seines Posts geschrieben hat.

Du "wartest" nicht auf eine Taktflanke, sondern wegen einer Taktflanke
wird irgendwas im FPGA passieren.
> OK.

Nein. Das & ist in VHDL eine Aneinanderhängung (Concatenation). Eine
Verundung erreichst du mit AND.
Mit  sr := sr(2 downto 0) & BOX
wird also aus sr(2), sr(1), sr(0) und BOX ein neuer 4-Bit Vektor
gemacht, und der dann an sr zugewiesen.
> Ah. Sonst würde ja auch kein 4-Bit-Vector entstehen.


Ich habe einmal die Zählstände kontrolliert, welches mein Programm 
vorher erzeugt. Leider scheine ich hier auch in unerwünschte Zustände 
reinzulaufen. Ich hatte hier mit Empfindlichkeitsliste gearbeitet 
anstatt einer wait-Anweisung und bin eigentlich davon ausgegangen, dass 
jedes Mal, wenn CLK oder NE555 sich ändern auch der Prozess startet und 
auswertet. Der Code:
1
 CTR:  process (CLK, NE555)
2
        begin
3
           
4
          if NE555 ='0' THEN                        
5
              QINT <= "0000000000000";            
6
              VALID <= '0';       
7
              START <= '0';      
8
          elsif CLK='1' AND CLK'event THEN        
9
             QINT <= QINT +1;         
10
             START <= '1';                   
11
           
12
             if QINT > "0000010101100" THEN    
13
              VALID <= '1';
14
           
15
             if QINT > "1000010101100" THEN   
16
              VALID <= '0';
17
              START <= '0';
18
            end if;
19
          end if;
20
       end if; 
21
      
22
     end process CTR;

Versuche ich jedoch zum Beispiel das CLK-Signal einzusynchronisieren und 
dann weiterzuarbeiten, bekomme ich immer Probleme mit "connected to 
following multiple drivers".

Wie man sehen kann, blicke ich nicht so gut durch wie nötig. Gibt es 
irgendwelche Kurse, die auf VHDL-Hardware-Programmierung spezialisiert 
sind (und nicht Simulation), damit ich das mal ordentlich lernen kann?

von Klaus (Gast)


Lesenswert?

Dennis R. schrieb:
> Du "wartest" nicht auf eine Taktflanke, sondern wegen einer Taktflanke
> wird irgendwas im FPGA passieren.
>> OK.

Warum vertauscht du hier konsequent, das Zitierte mit deinen Antworten? 
Das macht die Sache sehr unübersichtlich!

von Cihan K. (lazoboy61)


Lesenswert?

Dennis R. schrieb:
> CTR:  process (CLK, NE555)
>         begin
>
>           if NE555 ='0' THEN
>               QINT <= "0000000000000";
>               VALID <= '0';
>               START <= '0';
>           elsif CLK='1' AND CLK'event THEN
>              QINT <= QINT +1;
>              START <= '1';
>
>              if QINT > "0000010101100" THEN
>               VALID <= '1';
>
>              if QINT > "1000010101100" THEN
>               VALID <= '0';
>               START <= '0';
>             end if;
>           end if;
>        end if;
>
>      end process CTR;

Versuche mal bitte asynchrone Signale kommplett zu vermeiden. Der 
"NE555" ist nämlich asynchron zu CLOCK ("CLK") und somit könnten wieder 
Spikes auftreten. Wenn du unbedingt "NE555" als RESET haben willst, 
solltest du ihn vorher auch nochmal synchronisieren. z.B. so:
1
 SIGNAL R1_NE555, R2_NE555, i_NE555: STD_LOGIC;
2
 SYNC: PROCESS (CLK)
3
        BEGIN
4
        IF CLK = '1' AND CLK'EVENT THEN
5
          R1_NE555 <= NE555;    -- NE555 asynchron
6
          R2_NE555 <= R1_NE555;
7
          i_NE555  <= R2_NE555; -- i_NE555 nun synchron
8
        END IF;
9
       END PROCESS;
10
11
 CTR:  process (CLK, i_NE555)
12
        begin
13
           
14
          if i_NE555 ='0' THEN                        
15
              QINT <= "0000000000000";            
16
              VALID <= '0';       
17
              START <= '0';      
18
          elsif CLK='1' AND CLK'event THEN        
19
             QINT <= QINT +1;         
20
             START <= '1';                   
21
           
22
             if QINT > "0000010101100" THEN    
23
              VALID <= '1';
24
           
25
             if QINT > "1000010101100" THEN   
26
              VALID <= '0';
27
              START <= '0';
28
            end if;
29
          end if;
30
       end if; 
31
      
32
     end process CTR;

Ich persönlich würde es aber so machen mit dem Reset:
1
 SIGNAL R1_NE555, R2_NE555, i_NE555: STD_LOGIC;
2
 SYNC: PROCESS (CLK)
3
        BEGIN
4
        IF CLK = '1' AND CLK'EVENT THEN
5
          R1_NE555 <= NE555;    -- NE555 asynchron
6
          R2_NE555 <= R1_NE555;
7
          i_NE555  <= R2_NE555; -- i_NE555 nun synchron
8
        END IF;
9
       END PROCESS;
10
11
 CTR:  process (CLK)
12
        begin     
13
          if CLK='1' AND CLK'event THEN  
14
            if i_NE555 ='0' THEN                        
15
              QINT <= "0000000000000";            
16
              VALID <= '0';       
17
              START <= '0';  
18
            else    
19
              QINT <= QINT +1;         
20
              START <= '1';                   
21
22
              if QINT > "0000010101100" THEN    
23
                VALID <= '1';
24
              elsif QINT > "1000010101100" THEN   
25
                VALID <= '0';
26
                START <= '0';
27
              end if;
28
            end if;
29
          end if;
30
     end process CTR;

Dann hättest du nämlich einen syn. Reset.

Cihan

von Cihan K. (lazoboy61)


Lesenswert?

Wie ist denn der Timerbaustein NE555 konfiguriert? Was gibt er als INPUT 
zum FPGA rein? Wahrscheinlich ist es ein HIGH / LOW-Wechsel mit einer 
bestimmten Frequenz und Pulsbreite für den HIGH und LOW-Anteil.

Wenn der NE555 in der LOW-Phase ist, quasi das FPGA als INPUT einen LOW 
sieht, wird dein Programm, was du oben beschrieben hast, den Zähler 
solange Rücksetzen bis der NE555 wieder in die HIGH-Phase geht, quasi 
ist der Reset in der LOW-Phase des NE555 die ganze Zeit aktiv. 
(Bewusst?)

Mit welcher CLK arbeitest du aktuell und welche Frequenz und Pulsbreite 
besitzt der NE555?

Cihan

von Dennis R. (dennis84)


Angehängte Dateien:

Lesenswert?

Erst einmal vielen Dank für die Hilfe.

Der untere Code im Beitrag vom  04.02.2013 10:21 funktioniert bei mir 
nicht (System läuft nicht), mit dem oberen läuft das System. Da hier im 
Thread immer mal wieder einzelne Codefragmente stehen, hier mal alles im 
Zusammenhang.


Aktueller Stand:

pins.ucf:
---------
1
#NET "CLK" CLOCK_DEDICATED_ROUTE = FALSE;                
2
#NET "NE555" CLOCK_DEDICATED_ROUTE = FALSE;              
3
#NET "BOX" CLOCK_DEDICATED_ROUTE = FALSE;                
4
5
NET "CLK"        LOC = "P51"   | IOSTANDARD = LVCMOS33;    
6
NET "VALID"      LOC = "P33"    | IOSTANDARD = LVCMOS33;   
7
NET "CLK_HALBE"  LOC = "P74"   | IOSTANDARD = LVCMOS33;    
8
NET "START"      LOC = "P75"   | IOSTANDARD = LVCMOS33;    
9
NET "NE555"      LOC = "P83"   | IOSTANDARD = LVCMOS33;    
10
NET "BOX"        LOC = "P118"  | IOSTANDARD = LVCMOS33;   
11
12
NET Q2<0>         LOC = "P5"    | IOSTANDARD = LVCMOS33;     
13
NET Q2<1>         LOC = "P6"    | IOSTANDARD = LVCMOS33;
14
NET Q2<2>         LOC = "P7"    | IOSTANDARD = LVCMOS33;
15
NET Q2<3>         LOC = "P8"    | IOSTANDARD = LVCMOS33;
16
NET Q2<4>         LOC = "P9"    | IOSTANDARD = LVCMOS33;
17
NET Q2<5>         LOC = "P10"   | IOSTANDARD = LVCMOS33;
18
NET Q2<6>         LOC = "P14"   | IOSTANDARD = LVCMOS33;
19
NET Q2<7>         LOC = "P15"   | IOSTANDARD = LVCMOS33;
20
NET Q2<8>         LOC = "P16"   | IOSTANDARD = LVCMOS33;
21
NET Q2<9>         LOC = "P17"   | IOSTANDARD = LVCMOS33;
22
NET Q2<10>        LOC = "P21"   | IOSTANDARD = LVCMOS33;
23
NET Q2<11>        LOC = "P23"   | IOSTANDARD = LVCMOS33;
24
NET Q2<12>        LOC = "P24"   | IOSTANDARD = LVCMOS33;
25
26
  
27
28
#NET "RISE_BOX"   LOC = "P26"   | IOSTANDARD = LVCMOS33;   
29
#NET "FALL_BOX"   LOC = "P24"   | IOSTANDARD = LVCMOS33;



Und der eigentliche Code:
-------------------------
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.std_logic_unsigned.all;
4
5
entity ARRAY_ANSTEUERUNG is
6
  port (   CLK: in  std_logic; 
7
         NE555: in  std_logic;  
8
           BOX: in  std_logic;      
9
         VALID: inout bit;
10
        BOXOUT: inout bit;
11
 alter_zustand: inout std_logic;
12
      RISE_BOX: inout std_logic;
13
      FALL_BOX: inout std_logic;
14
         START: out bit;
15
     CLK_HALBE: out std_logic;
16
             Q: out std_logic_vector (12 downto 0);
17
            Q2: out std_logic_vector (12 downto 0));
18
end ARRAY_ANSTEUERUNG;
19
20
21
22
architecture VERHALTEN of ARRAY_ANSTEUERUNG is
23
signal QINT:  std_logic_vector (12 downto 0);
24
signal ZAEHLWERT_STEIGENDE_FLANKE: std_logic_vector (12 downto 0);
25
SIGNAL R1_NE555, R2_NE555, i_NE555: STD_LOGIC;
26
27
begin
28
29
SYNC: PROCESS (CLK)
30
        BEGIN
31
        IF CLK = '1' AND CLK'EVENT THEN
32
          R1_NE555 <= NE555;    -- NE555 asynchron
33
          R2_NE555 <= R1_NE555;
34
          i_NE555  <= R2_NE555; -- i_NE555 nun synchron
35
        END IF;
36
       END PROCESS;
37
38
39
40
 CTR:  process (CLK, i_NE555)
41
        begin
42
           
43
          if i_NE555 ='0' THEN                        
44
              QINT <= "0000000000000";            
45
              VALID <= '0';       
46
              START <= '0';      
47
          elsif CLK='1' AND CLK'event THEN        
48
             QINT <= QINT +1;         
49
             START <= '1';                   
50
           
51
             if QINT > "0000010101100" THEN    
52
              VALID <= '1';
53
           
54
             if QINT > "1000010101100" THEN   
55
              VALID <= '0';
56
              START <= '0';
57
            end if;
58
          end if;
59
       end if; 
60
      
61
     end process CTR;
62
  
63
     
64
     
65
     
66
FLANKE_ERKENNEN: process 
67
variable sr : std_logic_vector (3 downto 0) := "0000";
68
    begin
69
      wait until rising_edge(clk);
70
        RISE_BOX <= not sr(3) and sr(2) ;
71
        FALL_BOX <= not sr(2) and sr(3); 
72
        sr := sr(2 downto 0) & BOX;
73
    end process FLANKE_ERKENNEN;    
74
     
75
76
77
STEIGENDE_FLANKE_SPEICHERN: process(RISE_BOX)
78
variable slow_down: std_logic_vector (9 downto 0) := "0000000000";
79
    begin
80
   
81
     if rising_edge(RISE_BOX) THEN
82
     slow_down := slow_down + 1;
83
        if VALID ='1' THEN
84
        ZAEHLWERT_STEIGENDE_FLANKE <= QINT - 174;
85
      end if;
86
    end if;
87
end process STEIGENDE_FLANKE_SPEICHERN;   
88
89
 
90
     
91
    Q <= QINT;                            
92
    Q2 <= ZAEHLWERT_STEIGENDE_FLANKE; 
93
    CLK_HALBE <= NOT QINT(0);            
94
     
95
end VERHALTEN;


Das Bild vom Oszi zeigt in gelb Valid, in blau BOX und in lila den 
NE555. Im Code wird genau mit dem kurzen "Bips" des NE555 gearbeitet. 
Ich habe versucht das für das Bild im Anhang gut aufzunehmen. Je nachdem 
wo nun die steigende Flanke bei Box ist, soll sich nun der Wert am 
Ausgang entsprechend einstellen. Das zweite Bild im Anhang zeigt bei 
Port 0 die niederwertigen Bits und bei Port 1 die höherwertigen. Aber 
selbst wenn ich mein Objekt nicht bewege (BOX unverändert) springt der 
Zählwert am Ausgang wild hin und her (leider auf dem Bild nicht gut zu 
erkennen).

Ich verstehe meinen Code so, dass mein Zähler loslaufen sollte - laut 
Code und Überlegung - wenn der NE555 wieder HI ist. Aktuell ist mein CLK 
noch 20 MHz, da der neue Quartz noch nicht geliefert wurde. Der Impuls 
vom NE555 ist etwa 1,5 µs lang und kommt etwa alle 230 µs.

von Cihan K. (lazoboy61)


Lesenswert?

Bin gerade noch am Prüfen deines Codes, aber das was mir schon gleich 
auffält ist folgendes:
Du hast ein Signal QINT im Format STD_LOGIC_VECTOR. Dass du dem immer 
eine dazuaddierst und abfragst ist ja in Ordnung, aber dass du ihm 174 
aufeinmal subrahierst geht definitiv nicht!
Dazu weiteres hier:
http://www.mikrocontroller.net/articles/Rechnen_in_VHDL

Du müsstest auf jedenfall die Library USE IEEE.NUMERIC_STD.ALL 
einbinden, entweder QINT auf Integer oder Unsigned casten, oder du 
änderst QINT direkt auf Unsigned, was sich empfielt, da du dann in IF 
Abfragen direkt mit Zahlen abfragen kannst, anstatt die Bits anzugeben!

Cihan

von Cihan K. (lazoboy61)


Lesenswert?

Und lass das mal mit den inout´s. Brauchst du wahrscheinlich in deinem 
Beispiel garnicht. Willst du das was du über RISE_BOX extern einliest 
wieder zurück über den gleichen PIN ausgeben? Nein oder. Sonst müsstest 
du ja auch die Leitung programmtechnisch hochohmig setzen etc.

Benutze am besten anstatt inout interne Signale, die du dann an Outputs 
verknüpfts. Z.B. für VALID:
1
...
2
VALID: OUT STD_LOGIC;
3
...
4
SIGNAL i_VALID: STD_LOGIC;
5
...
6
VALID <= i_VALID; -- außerhalb eines Prozesses, i_VALID kann innerhalb eines Prozesses benutzt werden
7
...

Cihan

von Cihan K. (lazoboy61)


Lesenswert?

So hier mal paar Kommentare und Vorschläge in deinem Code:
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 ARRAY_ANSTEUERUNG is
7
  port (   CLK: in  std_logic; 
8
         NE555: in  std_logic;  
9
           BOX: in  std_logic;      
10
         VALID: out STD_LOGIC; -- nicht bit!
11
--        BOXOUT: inout bit; -- wird nicht verwendet
12
-- alter_zustand: inout std_logic; -- wird nicht verwendet
13
      RISE_BOX: out std_logic;
14
      FALL_BOX: out std_logic;
15
         START: out STD_LOGIC; -- nicht bit!
16
     CLK_HALBE: out std_logic;
17
             Q: out std_logic_vector (12 downto 0);
18
            Q2: out std_logic_vector (12 downto 0));
19
end ARRAY_ANSTEUERUNG;
20
21
architecture VERHALTEN of ARRAY_ANSTEUERUNG is
22
signal QINT:  std_logic_vector (12 downto 0);
23
signal ZAEHLWERT_STEIGENDE_FLANKE: std_logic_vector (12 downto 0);
24
SIGNAL R1_NE555, R2_NE555, i_NE555: STD_LOGIC;
25
26
SIGNAL i_VALID, i_RISE_BOX: STD_LOGIC;
27
28
begin
29
30
SYNC: PROCESS (CLK)
31
        BEGIN
32
        IF CLK = '1' AND CLK'EVENT THEN
33
          R1_NE555 <= NE555;    -- NE555 asynchron
34
          R2_NE555 <= R1_NE555;
35
          i_NE555  <= R2_NE555; -- i_NE555 nun synchron
36
        END IF;
37
       END PROCESS;
38
39
 CTR:  process (CLK, i_NE555)
40
        begin
41
           
42
          if i_NE555 ='0' THEN                        
43
              QINT <= "0000000000000";            
44
              i_VALID <= '0';       
45
              START <= '0';      
46
          elsif CLK='1' AND CLK'event THEN        
47
             QINT <= QINT +1;         
48
             START <= '1';                   
49
           
50
             if QINT > "0000010101100" THEN    
51
              i_VALID <= '1';
52
           
53
             if QINT > "1000010101100" THEN   
54
              i_VALID <= '0';
55
              START <= '0';
56
            end if;
57
          end if;
58
       end if; 
59
      
60
     end process CTR;
61
     
62
FLANKE_ERKENNEN: process 
63
variable sr : std_logic_vector (3 downto 0) := "0000";
64
    begin
65
      wait until rising_edge(clk);
66
        i_RISE_BOX <= not sr(3) and sr(2) ;
67
        FALL_BOX <= not sr(2) and sr(3); 
68
        sr := sr(2 downto 0) & BOX;
69
    end process FLANKE_ERKENNEN;    
70
     
71
STEIGENDE_FLANKE_SPEICHERN: process(i_RISE_BOX)
72
--variable slow_down: std_logic_vector (9 downto 0) := "0000000000"; -- wird nicht verwendet
73
    begin
74
   
75
     if rising_edge(i_RISE_BOX) THEN
76
--     slow_down := slow_down + 1; -- wird nicht verwendet
77
        if i_VALID ='1' THEN -- Solange i_VALID = '1' ist und pos. i_RISE_BOX, wird die IF Schleife aufgerufen! (bewusst?)
78
        ZAEHLWERT_STEIGENDE_FLANKE <= STD_LOGIC_VECTOR((UNSIGNED(QINT)) - 174); -- QINT nach UNSIGNED casten, 174 abziehen und Ergebnis für 
79
                                                      -- ZAEHLWERT_STEIGENDE_FLANKE nach std_logic_vector casten!
80
      end if;
81
    end if;
82
end process STEIGENDE_FLANKE_SPEICHERN;   
83
84
   VALID <= i_VALID;
85
    RISE_BOX <= i_RISE_BOX;
86
    Q <= QINT;                            
87
    Q2 <= ZAEHLWERT_STEIGENDE_FLANKE; 
88
    CLK_HALBE <= NOT QINT(0);            
89
     
90
end VERHALTEN;

Schau dir mal dein VALID an, ist dir klar dass wenn immer die pos. 
RISE_BOX und VALID = 1 ist, dass die Subtraktion stattfindet.

Cihan

von Dennis R. (dennis84)


Lesenswert?

Ich lese mich gerade in Rechnen mit VHDL, Variablentypen und 
Umwandlungen ein.

Den Code habe ich 1:1 einmal ausprobiert. Leider flackern damit nach wie 
vor die die untersten 5-7 Bits, je nachdem welche Position ich habe.

Ich habe Testweise aus
ZAEHLWERT_STEIGENDE_FLANKE <= STD_LOGIC_VECTOR((UNSIGNED(QINT)) - 174);
einfach mal
ZAEHLWERT_STEIGENDE_FLANKE <= STD_LOGIC_VECTOR((UNSIGNED(QINT)) - 0);
gemacht. Flackert dennoch.

Ich wollte das eigentlich so machen, dass immer wenn eine steigende 
Flanke zu sehen ist, der Zählerwert abzüglich eines Offsets von 174 
festgehalten werden soll in ZAEHLWERT_STEIGENDE_FLANKE. Das ist dann 
meine Position.

Ich hatte das slow_down verwendet um die Darstellung am Monitor 
langsamer zu machen. Der ursprüngliche Code war dieser hier:
1
if rising_edge(RISE_BOX) THEN
2
     slow_down := slow_down + 1;
3
             if VALID ='1' THEN
4
               if slow_down = "0000000000" THEN
5
                  ZAEHLWERT_STEIGENDE_FLANKE <= QINT - 174;
6
       end if;
7
      end if;
8
    end if;
9
end process STEIGENDE_FLANKE_SPEICHERN;

von Cihan K. (lazoboy61)


Lesenswert?

Kannst du mal dei Vorhaben am besten detailliert erklären, bzw. auch mit 
Bilder und Zeichnungen darstellen. Was soll das Box, Valid, NE555 
bewirken. Warum willst du einen Zähler bzw. wozu. Es fehlen noch viele 
Hintergründe, sodass der Fehler vllt sogar in dem Ansatz liegt als in 
deinem Codeausschnitt. Versuche mal die Details rüberzubringen.

Cihan

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


Lesenswert?

Cihan Kalayci schrieb:
> use ieee.std_logic_unsigned.all;
> USE IEEE.NUMERIC_STD.ALL;
Na toll. Immer her mit den Libs...
Kurz: NIEMALS std_logic_unsigned (std_logic_arith) und numeric_std 
zusammen. Doppelte Typdefinitionen straft der Synthesizer mit seltsamem 
Verhalten. Dazu der Beitrag "IEEE.STD_LOGIC_ARITH.ALL obsolete"

> signal QINT:  std_logic_vector (12 downto 0);
Ein Integer ist genau das Richtige für einen Zähler. Dann kann man 
sowas richtig schön dezimal lesen:
> if QINT > "0000010101100" THEN

> Und lass das mal mit den inout´s.
Richtig. Nur aus Schreibfaulheit ("dann brauche ich keine keine lokalen 
Signale!") machst du da mit inout bewusst eine falsche Beschreibung 
deines Systems. Denn das sind keine bidirektionalen Leitungen.

> Schau dir mal dein VALID an, ist dir klar dass wenn immer die pos.
> RISE_BOX und VALID = 1 ist, dass die Subtraktion stattfindet.
Das sieht man mit einer Testbench sehr schön.
@ Dennis: hast du eine Testbench für deine Beschreibung?
Und häng einfach das VHDL-File hier an, dann weiß man um was es geht. Es 
ist überaus mühselig, sich anhand von Codeschnipseln ein klares Bild zu 
machen.

von Cihan K. (lazoboy61)


Lesenswert?

Nehme ich die Library ieee.std_logic_unsigned.all raus und alle anderen 
drin tretet folgender Fehler auf:
Line 51. + can not have such operands in this context

Nehme ich die Library IEEE.NUMERIC_STD.ALL raus und alle anderen drin 
tretet folgender Fehler auf:
Line 87. Undefined symbol 'UNSIGNED'

Bei dem oberen meckert er wegen der Zeile
QINT <= QINT + 1;

und bei dem unteren Fehler wegen dem casting
ZAEHLWERT_STEIGENDE_FLANKE <= STD_LOGIC_VECTOR((UNSIGNED(QINT)) - 174);

Ich brauche ja beide Library um überhaupt synthesieren zu können, oder?
Irgendwie bin ich jetzt ein bisschen durcheinander.

Ich habe immer gelesen dass man numeric_std und std_logic_arith 
vermeiden soll.

Cihan

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


Lesenswert?

Cihan Kalayci schrieb:
> Ich brauche ja beide Library um überhaupt synthesieren zu können, oder?
Nein. Es reicht die numeric_std.
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std

> Ich habe immer gelesen dass man numeric_std und std_logic_arith
> vermeiden soll.
Die std_logic_arith und die std_logic_signed/std_logic_unsigned gehören 
zusammen.

von Cihan K. (lazoboy61)


Lesenswert?

Wenn ich die std_logic_unsigned rausnehme, dann müsste man doch die 
Zeile von oben ändern:
QINT <= QINT + 1;

Entweder wird QINT gleich als integer definiert oder man muss QINT nach 
unsigned casten, dann addieren und zurück nach std_logic_vector casten. 
Richtig?

Cihan

von Cihan K. (lazoboy61)


Lesenswert?

@Lothar:
Manchmal gibt es bei mir Fälle, wo ich IP Cores von Xilinx benutze 
(FIFOs, FFT, DDR2, UART) bei denen nicht die Library numeric_std benutzt 
wird, sonder mehr die std_logic_arith. Kann dies zu problemen führen, 
wenn ich in meinen eigenen vhd-Dateien ausschließlich numeric_std 
benutze und die verwendeten IP Cores mit den von std_logic_arith laufen? 
Würde mich stark interessieren.

Danke dir.

Cihan

von Dennis R. (dennis84)


Angehängte Dateien:

Lesenswert?

Damit überhaupt klar ist, was ich machen will.
Ich sehe mir mit einem Sensor einen ausgeleuchteten Bereich an. Ist 
alles hell, dann ist mein Videosignal überall HI. Dunkle ich einen 
Bereich ab, dann ist das Videosignal für den abgedunkelten Bereich LO. 
Um einen scharfen Übergang zu erzeugen, lege ich einen Triggerpegel 
fest. Überschreitet oder unterschreitet mein Videosignal eine gewisse 
Spannung, dann sehe ich das als meinen Übergang hell-dunkel bzw. 
dunkel-hell an. Das ist mein BOX (BOX HI ist hell, BOX LO ist dunkel). 
In der Mitte des Messbereich ist es beim Bild im Anhang also dunkel.


Aufgabe des FPGA Spartan 6: Das FPGA erhält drei Eingangssignale. Einen 
NE555-Takt (230 µs HI, 20 µs LO), einen Quartz- CLK mit 20 MHz und ein 
BOX-Signal mit Flanken. Mit dem NE555-Signal startet mein Messzyklus und 
ich zähle dann die CLKs. Liegt ein Flankenwechsel beim BOX vor, wird der 
Zählerstand gespeichert. Dann weiß ich, dass hier mein Übergang 
dunkel-hell bzw. hell-dunkel ist. Da ich die ersten Pixel des Sensors 
nicht auswerten darf (Dummies) erzeuge ich mir ein VALID-Signal. Nur 
wenn dieses HI ist, darf ich einen Flankenwechsel beachten.

Bild im Anhang: Gelb ist Valid, blau ist BOX und lila ist der NE555.

Einen Testbench in dem Sinne habe ich nicht. Alles was ich habe an VHDL 
ist oben angegeben. Auf dem Monitor sehe ich mir dann den gespeicherten 
Wert über die Pixels an. Das ist mein Test bislang.

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


Lesenswert?

Cihan Kalayci schrieb:
> Kann dies zu problemen führen,
> wenn ich in meinen eigenen vhd-Dateien ausschließlich numeric_std
> benutze und die verwendeten IP Cores mit den von std_logic_arith laufen?
Nein, weil jedes Modul für sich compiliert wird. Viele Xilinx-Cores sind 
eh' in Verilog geschrieben.

von Cihan K. (lazoboy61)


Lesenswert?

Dennis R. schrieb:
> Einen Testbench in dem Sinne habe ich nicht. Alles was ich habe an VHDL
> ist oben angegeben. Auf dem Monitor sehe ich mir dann den gespeicherten
> Wert über die Pixels an. Das ist mein Test bislang.

Mit einer Testbench meinte Lothar die Simulation dafür. Hast du es schon 
mal simuliert?

Lothar Miller schrieb:
> Cihan Kalayci schrieb:
>> Kann dies zu problemen führen,
>> wenn ich in meinen eigenen vhd-Dateien ausschließlich numeric_std
>> benutze und die verwendeten IP Cores mit den von std_logic_arith laufen?
> Nein, weil jedes Modul für sich compiliert wird. Viele Xilinx-Cores sind
> eh' in Verilog geschrieben.

Danke dir Lothar. War dann wohl die ganze Zeit auf einem falschem Pfad. 
Dachte nur std_logic_arith und numeric_std sind verboten zusammen zu 
benutzen. Wusste aber nicht, dass ..._unsigned eine Ableitung vom 
..._arith ist, man lernt nie aus.

Cihan

von Cihan K. (lazoboy61)


Angehängte Dateien:

Lesenswert?

Hier hast du mal ein Simulation-Screenshot.
So wie es aussieht flackert hier nichts.
Versuche mal am besten das Design unter Chipscope zu beobachten, also 
mit dem Logic Analyzer von Xilinx.
Da wirst du dann sehen was wirklich auf der Hardware passiert, vor allem 
warum es flackert!

Cihan

von Dennis R. (dennis84)


Lesenswert?

Mich machen an meinem Entwurf gerade ein paar Sachen stutzig. Das werde 
ich jetzt mal nachprüfen. Auch zur Verwendung von Variablen und 
Simulationen muss ich mir mal einiges ansehen. Danke für die Hilfe. Wenn 
ihr Interesse habt, schreibe ich das Ergebnis hier rein.

von Cihan K. (lazoboy61)


Lesenswert?

Ich würde dir empfehlen grundsätzlich deine Designs vorerst zu 
simulieren, so wie oben. Aber manchmal sieht die Simulation in Ordnung 
aus, aber auf der Hardware gibt es Probleme. Hier ist Chipscope ein 
mächtiges Werkzeug, mit dem du dein Design in Real-Time beobachten 
könntest. Da kannst du auch dann 100 % sehen warum dein Wert flackert.

Mein Tipp an dich, versuche am besten dich auch in Chipscope 
einzuarbeiten.
Viel Erfolg. Das Ergebnis zu posten ist immer für die Leser sinnvoll.

Cihan

von Dennis R. (dennis84)


Lesenswert?

Es scheint zu laufen :)

Also ich habe basierend auf dem was ich von euch erfahren habe den Code 
einmal stark geändert. Jetzt sehe ich keine Probleme mehr mit 
"bitwacklern". Folgendes habe ich gemacht:

1. Nur zwei Signale von außen ans FPGA geführt (CLK und BOX). Der NE555 
ist rausgefolgen, ich erzeuge so viel möglich intern. Das Box-Signal 
habe ich mit dem Schieberegister synchronisiert.
2. Ich verwende Variablen für interne Berechnungen anstatt inouts beim 
Port.
3. Demnach gibt es im Port-Bereich nur noch in oder out, aber kein inout 
mehr.
4. Ich habe kleine Prozesse geschrieben, welche ich einzeln und separat 
mit meiner Hardware testen konnte.
5. Ich habe versucht noch passender Variablennamen zu vergeben.

Ob der Code einem VDHL-Experten gefällt bezweifle ich dennoch. Ich 
vermute, dass die shared Variablen sauer aufstoßen. Aber damit konnte 
ich Variablen in verschiedenen Prozessen nutzen. Vielleicht stören auch 
andere Eigenschaften

Mit Chipscope muss ich mich wirklich mal befassen. Ansonsten merke ich 
leider immer wieder, dass ich hier blutiger Anfänger bin. Ich vermute 
das beste wird sein, mal nach VHDL-Kursen in Hessen oder Umgebung von 
Hessen zu suchen.

Vielen Dank für eure Hilfe.


Hier noch mein Code:
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 ARRAY_ANSTEUERUNG is
7
  port (   CLK_INPUT:             in  std_logic;
8
           BOX_INPUT:             in  std_logic;     
9
           CLK_HALBE_OUTPUT:      out std_logic;
10
        VALID_OUTPUT:          out std_logic;
11
        BOX_FALL_OUTPUT:       out std_logic;
12
        START_ARRAY_OUTPUT:    out std_logic;
13
        STEIGENDE_FLANKE_WERT: out std_logic_vector (12 downto 0);
14
        FALLENDE_FLANKE_WERT:  out std_logic_vector (12 downto 0)
15
         );
16
end ARRAY_ANSTEUERUNG;
17
18
19
20
21
architecture VERHALTEN of ARRAY_ANSTEUERUNG is
22
shared variable CLK_HALBE_INTERN: STD_LOGIC;
23
shared variable CLK_ZAEHLER_INTERN: STD_LOGIC_VECTOR (12 downto 0) := "0000000000000";
24
shared variable START_ARRAY_INTERN: STD_LOGIC;
25
shared variable BOX_INTERN_RISE: STD_LOGIC;
26
shared variable BOX_INTERN_FALL: STD_LOGIC;
27
shared variable VALID_INTERN: STD_LOGIC;
28
29
begin
30
31
 CLK_HALBE: PROCESS(CLK_INPUT)                       
32
     begin
33
        if CLK_INPUT='1' AND CLK_INPUT'EVENT THEN
34
         CLK_HALBE_INTERN := NOT CLK_HALBE_INTERN;
35
        end if;
36
   end process CLK_HALBE;
37
38
39
    CLK_ZAEHLEN_INTERN: PROCESS                        
40
      begin
41
      wait until rising_edge(CLK_INPUT);
42
     CLK_ZAEHLER_INTERN := CLK_ZAEHLER_INTERN + 1;
43
       if CLK_ZAEHLER_INTERN > "1000010111000" THEN
44
        CLK_ZAEHLER_INTERN := "0000000000000";
45
      end if;
46
     end process CLK_ZAEHLEN_INTERN;
47
48
49
50
    STARTSIGNAL_ARRAY: PROCESS
51
      begin
52
        wait until rising_edge(CLK_INPUT);
53
           if CLK_ZAEHLER_INTERN > "1000000000000" THEN
54
         START_ARRAY_INTERN := '0';
55
         else
56
           START_ARRAY_INTERN := '1';
57
          end if;
58
      end process STARTSIGNAL_ARRAY;    
59
60
  
61
       VALID_ERZEUGEN: PROCESS
62
         begin
63
         wait until rising_edge(CLK_INPUT);
64
        if CLK_ZAEHLER_INTERN < "0111111101111" THEN
65
             if CLK_ZAEHLER_INTERN > "0000010110010" THEN
66
            VALID_INTERN := '1';
67
          end if;  
68
         else
69
           VALID_INTERN := '0';
70
          end if;
71
       end process VALID_ERZEUGEN;    
72
73
74
75
     BOX_AUSWERTEN: process 
76
      variable sr : std_logic_vector (3 downto 0) := "0000";
77
        begin
78
        wait until rising_edge(clk_input);
79
        if VALID_INTERN ='1' THEN
80
             BOX_INTERN_RISE := not sr(3) and sr(2);
81
             BOX_INTERN_FALL := not sr(2) and sr(3);
82
             sr := sr(2 downto 0) & BOX_INPUT;
83
        end if;
84
     end process BOX_AUSWERTEN;    
85
86
87
88
89
    STEIGENDE_FLANKE_SPEICHERN: process
90
   variable slow_down: std_logic_vector (1 downto 0) := "00";
91
    begin
92
      wait until  rising_edge(clk_input);
93
     slow_down := slow_down + 1;
94
      if BOX_INTERN_RISE = '1' THEN
95
         if slow_down = "00"  THEN
96
          STEIGENDE_FLANKE_WERT <= CLK_ZAEHLER_INTERN;
97
        end if;
98
      end if;     
99
   end process STEIGENDE_FLANKE_SPEICHERN;
100
  
101
102
103
   FALLENDE_FLANKE_SPEICHERN: process
104
   variable slow_down2: std_logic_vector (1 downto 0) := "00";
105
    begin
106
      wait until  rising_edge(clk_input);
107
     slow_down2 := slow_down2 + 1;
108
      if BOX_INTERN_FALL = '1' THEN
109
         if slow_down2 = "00"  THEN
110
          FALLENDE_FLANKE_WERT <= CLK_ZAEHLER_INTERN;
111
        end if;
112
      end if;
113
   end process FALLENDE_FLANKE_SPEICHERN;  
114
  
115
116
117
CLK_HALBE_OUTPUT <= CLK_HALBE_INTERN;         
118
START_ARRAY_OUTPUT <= START_ARRAY_INTERN;     
119
VALID_OUTPUT <= VALID_INTERN;                 
120
BOX_FALL_OUTPUT <= BOX_INTERN_RISE;           
121
122
     
123
end VERHALTEN;

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


Lesenswert?

Dennis R. schrieb:
> shared variable
Jetzt geht los...   :-o
Du kommst aus der Softwareecke, oder?

Zum Thema "Variablen und ihre Grenzen" empfehle ich den 
Beitrag "Variable vs Signal"

von Dennis R. (dennis84)


Lesenswert?

Ich habe Mechatronik studiert. Und im Studium C/C++ gemacht. Von VHDL 
habe ich bis vor kurzem noch nie etwas gehört.

Hmm 100% verstanden habe ich es noch nicht. Also das heißt ich sollte 
überall anstatt Variablen Signale einsetzen? Wenn überhaupt nur für 
Kombinatorik-Aufgaben auf Variablen setzen.

Ich verstehe jedoch in meinem oben genannten Programm nicht ganz, was 
dann anders herauskommen soll? Denn ich habe über wait until oder 
sensivity list eigentlich immer genau bedacht, wann der Prozess anlaufen 
soll. Und dann läuft er einfach komplett durch. Setze ich auf Signale, 
muss ich ja noch jeweils einen Prozesszyklus extra warten, bis der Wert 
des Signals dann aktualisiert wurde.

von Duke Scarring (Gast)


Lesenswert?

Dennis R. schrieb:
> Also das heißt ich sollte
> überall anstatt Variablen Signale einsetzen? Wenn überhaupt nur für
> Kombinatorik-Aufgaben auf Variablen setzen.
Ja.

> Ich verstehe jedoch in meinem oben genannten Programm nicht ganz, was
Du hast kein Programm, sondern die Beschreibung einer digitalen 
Schaltung.

> dann anders herauskommen soll? Denn ich habe über wait until oder
> sensivity list eigentlich immer genau bedacht, wann der Prozess anlaufen
> soll. Und dann läuft er einfach komplett durch. Setze ich auf Signale,
> muss ich ja noch jeweils einen Prozesszyklus extra warten, bis der Wert
> des Signals dann aktualisiert wurde.
Das nennt man Latency.
Sieh es mal so: Immer wenn die Taktflanke kommt, wird an einem Register 
der Wert vom Eingang gespeichert und der Ausgang aktualisiert. Dann hat 
das kombinatorische Netzwerk Zeit bis zur nächsten Taktflanke um neue 
Werte zu 'berechnen'.

VHDL auf einem FPGA ist nicht wie ein C-Programm in einem µC, sondern 
eher die Beschreibung von vielen 74xx auf einem großen Steckbrett.

Duke

von Dennis R. (dennis84)


Lesenswert?

Ok, verstehe ich soweit.

Also ich habe aus den shared variables nun bis auf eine Ausnahme signals 
gemacht. Denn wenn ich CLK_ZAEHLER_INTERN auf signal umstelle, dann ist 
mein LSB bei BOX_FALL_OUTPUT stets 1. Wobei das hier eigentlich nach 
meinem Verständnis keine Einfluss haben sollte.

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


Lesenswert?

Dennis R. schrieb:
> Denn wenn ich CLK_ZAEHLER_INTERN auf signal umstelle, dann ist
> mein LSB bei BOX_FALL_OUTPUT stets 1.
Ich würde mich an deiner Stelle fragen: Warum?

>>     BOX_FALL_OUTPUT:       out std_logic;
>  mein LSB bei BOX_FALL_OUTPUT
Das ist doch sowieso nur 1 Bit breit...  :-/

von Dennis R. (dennis84)


Lesenswert?

Ach sorry. Verpeilt vorhin. Ich meinte, dass wenn ich signal 
CLK_ZAEHLER_INTERN nun einsetze, dass STEIGENDE_FLANKE_WERT<0> - also 
das LSB des Speicherwerts - immer 1 ist. Mit Veränderung des 
slow_down-Wertes kann ich jedoch im LSB auch stets eine 0 erzeugen. Von 
daher sieht es für mich so aus, als läge dies nicht am Zählen oder 
Auswerten der vorhergehenden Prozesse, sondern einfach am ausgeben der 
Werte von STEIGENDE_FLANKE_SPEICHERN Prozess.

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.