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?
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
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?
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.
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
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
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.
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
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.
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...
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
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..
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...
... und vorallemallemallem bekommt man ne Setupzeitverletzung aber auch
bei beliebig niedrigen Taktfrequenzen hin... :-) Also das Argument lass
ich nicht gelten gg
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...
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?
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"...
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..
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?
> 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.
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;
Eigentlich hätte ich das mit der Einsynchronisation folgendermaßen
gemacht:
1
SIGNALR1_BOX,R2_BOX,i_BOX,BOX_v:STD_LOGIC;
2
3
STEIGENDE_FLANKE:process(CLK)
4
begin
5
IFrising_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
IFVALID='0'THEN
10
BOXOUT<='0';
11
ELSIFi_BOX='1'ANDBOX_v='0'THEN-- BOX_v um pos. Flanke zu erkennen!
12
BOXOUT<='1';
13
ENDIF;
14
BOX_v<=i_BOX;
15
ENDIF;
16
ENDPROCESSSTEIGENDE_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
ifrising_edge(rise)THEN
4
ifVALID='1'THEN
5
ZAEHLWERT_STEIGENDE_FLANKE<=QINT;
6
endif;
7
endif;
8
endprocessSTEIGENDE_FLANKE_SPEICHERN;
Benutze mal bitte am besten die [vhdl] MAKROS, um deinen Quellcode
besser darzustellen.
Cihan
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.
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
ifNE555='0'THEN
5
QINT<="0000000000000";
6
VALID<='0';
7
START<='0';
8
elsifCLK='1'ANDCLK'eventTHEN
9
QINT<=QINT+1;
10
START<='1';
11
12
ifQINT>"0000010101100"THEN
13
VALID<='1';
14
15
ifQINT>"1000010101100"THEN
16
VALID<='0';
17
START<='0';
18
endif;
19
endif;
20
endif;
21
22
endprocessCTR;
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?
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!
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
SIGNALR1_NE555,R2_NE555,i_NE555:STD_LOGIC;
2
SYNC:PROCESS(CLK)
3
BEGIN
4
IFCLK='1'ANDCLK'EVENTTHEN
5
R1_NE555<=NE555;-- NE555 asynchron
6
R2_NE555<=R1_NE555;
7
i_NE555<=R2_NE555;-- i_NE555 nun synchron
8
ENDIF;
9
ENDPROCESS;
10
11
CTR:process(CLK,i_NE555)
12
begin
13
14
ifi_NE555='0'THEN
15
QINT<="0000000000000";
16
VALID<='0';
17
START<='0';
18
elsifCLK='1'ANDCLK'eventTHEN
19
QINT<=QINT+1;
20
START<='1';
21
22
ifQINT>"0000010101100"THEN
23
VALID<='1';
24
25
ifQINT>"1000010101100"THEN
26
VALID<='0';
27
START<='0';
28
endif;
29
endif;
30
endif;
31
32
endprocessCTR;
Ich persönlich würde es aber so machen mit dem Reset:
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
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
NETQ2<0>LOC="P5"|IOSTANDARD=LVCMOS33;
13
NETQ2<1>LOC="P6"|IOSTANDARD=LVCMOS33;
14
NETQ2<2>LOC="P7"|IOSTANDARD=LVCMOS33;
15
NETQ2<3>LOC="P8"|IOSTANDARD=LVCMOS33;
16
NETQ2<4>LOC="P9"|IOSTANDARD=LVCMOS33;
17
NETQ2<5>LOC="P10"|IOSTANDARD=LVCMOS33;
18
NETQ2<6>LOC="P14"|IOSTANDARD=LVCMOS33;
19
NETQ2<7>LOC="P15"|IOSTANDARD=LVCMOS33;
20
NETQ2<8>LOC="P16"|IOSTANDARD=LVCMOS33;
21
NETQ2<9>LOC="P17"|IOSTANDARD=LVCMOS33;
22
NETQ2<10>LOC="P21"|IOSTANDARD=LVCMOS33;
23
NETQ2<11>LOC="P23"|IOSTANDARD=LVCMOS33;
24
NETQ2<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:
-------------------------
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.
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
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:OUTSTD_LOGIC;
3
...
4
SIGNALi_VALID:STD_LOGIC;
5
...
6
VALID<=i_VALID;-- außerhalb eines Prozesses, i_VALID kann innerhalb eines Prozesses benutzt werden
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:
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
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.
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
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.
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
@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
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.
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.
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
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
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.
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
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:
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.
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
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.
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... :-/
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.