Hallo liebe Gemeinde
Seid mir bitte nicht böse, aber ich bin noch blutiger Anfänger in sachen
FPGA und VHDL.
Aufgabe ist es für eine Triggereinrichtung zwei 8bit Werte mit einander
zu vergleichen. Also Wert_A mit Wert_B. Allerdings muss ein Vergleich
immer genau einen Takt zuvor geschehen und dieses Ergebnis im
2.Taktzyklus beim zweiten Vergleich vorliegen.
Die Gleichung dazu:
Y = (A >= B) & (A' < B')
Hinweis: A' und B' sollen hier die Vergleichswerte einen Taktzyklus
vorher darstellen.
Ich weiß gar nicht erst wie ich da anfangen soll. Wer kann helfen und
mir einen Tip geben und mich auf die richtige Fährte führen?
Ich danke schon mal für die Hilfe
Steffen
Kuck dir das hier mal an:
http://www.doulos.com/knowhow/vhdl_designers_guide/an_example_design_entity/
Dann noch als Hinweis: Wenn du den alten Zustand brauchst, dann musst du
einen getakteten Process ´ala:
process(clk)
begin
if clk'event and clk='1' then
...
end if;
end process;
bauen, sonst kannst du keine Werte speichern (Schaltwerk vs Schaltnetz).
Grüße,
Markus
Hallo Markus
Danke dir schonmal. Allerdings hilft der link mir da auch nicht weiter.
Ich hab mir jetzt schon mal einen Comparator gebastelt der greater,
equal und less ausgibt.
Das ich hier mit Taktflanken arbeiten muss war mir schon klar. Ich hab
auch schon etwas Logik auf dem Papier gezeichnet, wie es eigentlich
funktionieren müsste. Allerdings möchte ich es in VHDL abbilden und kein
Schematic nehmen.
Weitere Vorschläge?
Grüße Steffen
Hallo
Nun ein wenig bin ich jetzt schon weiter. Die funktionelle Simulation
funktioniert. Doch wird das Design in einer timig simulation noch
funktionieren?
Wer kann mal über diesen (Anfänger-) Code schauen?
Ich habe noch ein asyncronen Reset über "Stop" und "RESET" mit
eingefügt. Außerdem gibt es einen Trigger-Enable Anschluss und einen zur
Auswahl des Triggermodus, steigende oder fallende Flanke.
Ich kann mit Kritik umgehen. Also, ran an die Tasten, was könnt ich da
noch besser machen???
Grüße
Steffen
> Ich habe noch ein asyncronen Reset über "Stop" und "RESET" mit> eingefügt.
Ja, böse, böse...
Wenn schon ein asynchroner Reset, dann auf jeden Fall keinen
kombinatorischen asynchronen Reset.
> Nun ein wenig bin ich jetzt schon weiter. Die funktionelle Simulation> funktioniert. Doch wird das Design in einer timig simulation noch> funktionieren?
Ja. Das wird sogar sehr gut auch in einer Timing-Simulation
funktionieren. Aber in der Realität wird das Desing herumzicken!!!
Warum? Weil du asynchrone Eingänge vergleichst:
1
if(DATA_IN<TRIG_LEVEL)then
2
less<='1';
3
equal<='0';
4
greater<='0';
Und dann die kombinatorisch ermittelten Werte (less..greater) ohne
weitere Synchronisation direkt weiterverwendest:
1
iffalling_edge(CLK)then
2
q_dff_3<=(greaterorequalorout_trig_hi);
3
endif;
Das muß und wird irgendwann schief gehen.
Was, wenn kurz vor der nächsten fallenden Flanke ein neues DATA_IN
kommt. Sind dann für diese Abfragen die 3 Komparatorausgänge garantiert
alle richtig und stabil?
Nein. Du kannst das nicht garantieren, solange DATA_In zum Takt keinen
Bezug hat. Das Stichwort und die Problematik dahinter heißt
"Einsynchronisieren":
http://www.lothar-miller.de/s9y/categories/35-Einsynchronisieren
BTW:
> comperator: process(DATA_IN,TRIG_LEVEL)
Das sollte eher comparator heißen. Komperatoren gibt es nicht.
Hallo Lothar
Danke für die Hinweise. Genau sowas hab ich auch befürchtet. Aber bitte
nicht vergessen, das ist mein erster Versuch und ich bin blutiger
Anfänger in Sachen VHDL und FPGA.
>Ja. Das wird sogar sehr gut auch in einer Timing-Simulation>funktionieren. Aber in der Realität wird das Desing herumzicken!!!>Warum? Weil du asynchrone Eingänge vergleichst:
1
if(DATA_IN<TRIG_LEVEL)then
2
less<='1';
3
equal<='0';
4
greater<='0';
Wie kann ich den denn einsynchronisieren? Zum Beispiel mit einer
fallenden Flanke von CLK?
Wie kann ich das mit dem RESET lösen?
Also "RESET" soll der interne Reset sein. Und STOP kommt von außerhalb (
aber immer noch innerhalb der FPGA von einem anderen Component.
Grüße
Steffen
Steffen H. schrieb:> Also "RESET" soll der interne Reset sein.
Dann ist der also taktsynchron...
> Und STOP kommt von außerhalb> aber immer noch innerhalb der FPGA von einem anderen Component.
... und der auch?
Dann sollte das keine Probleme geben.
Aber: wenn der Reset und der Stop taktsynchron sind, warum nimmst du sie
dann nicht in den getakteten Teil des Prozesses?
So etwa:
1
process(CLK)begin
2
iffalling_edge(CLK)then
3
if(stop='1'orRESET='0')then
4
q_dff_1<='0';
5
else
6
q_dff_1<=less;
7
endif;
8
endif;
9
endprocess;
Dann ist das wesentlich klarer, dass alles vom Takt abhängt.
> Wie kann ich das mit dem RESET lösen?
Stell dir die Frage: "Wofür brauche ich einen Reset?"
Wenn die Antwort ist: "Für den Reset-Knopf!"
Dann lass den Reset weg.
Welche Zielplattform (welches FPGA) verwendest du? Wenn es Xilinx ist,
dann lies zum Thema asynchroner Reset mal den
Beitrag "Xilinx und die Resets"
Und die Links, die darin auftauchen.
Hallo Steffen,
Lothar ist hier im Forum einer der Großen. Was der schreibt, hat immer
Hand und Fuß. Oder fast immer, manchmal gibt es auch abweichende
Meinungen. So auch hier. Lothar Miller schrieb:
> Ja. Das wird sogar sehr gut auch in einer Timing-Simulation> funktionieren. Aber in der Realität wird das Desing herumzicken!!!> Warum? Weil du asynchrone Eingänge vergleichst:> if (DATA_IN < TRIG_LEVEL) then> less <= '1';> equal <= '0';> greater <= '0';> Und dann die kombinatorisch ermittelten Werte (less..greater) ohne> weitere Synchronisation direkt weiterverwendest:> if falling_edge (CLK) then> q_dff_3 <= (greater or equal or out_trig_hi);> end if;> Das muß und wird irgendwann schief gehen
Hier muss ich Lothar leider punktuell widersprechen. Er hat sicher
Recht, wenn er schreibt, dass Signale, die in das FPGA von außen
eingegeben werden, entweder als taktsynchron bekannt sein oder
einsynchronisiert werden müssen. Aber es ist durchaus erlaubt, aus diese
Signalen kombinatorische Verknüpfungen zu bilden und die Ergebnisse
daraus weiter kombinatorisch zu verarbeiten, bevor das finale Signal in
ein Flipflop übernommen wird.
Harald
Harald Flügel schrieb:> Aber es ist durchaus erlaubt, aus diese Signalen kombinatorische> Verknüpfungen zu bilden und die Ergebnisse daraus weiter kombinatorisch> zu verarbeiten, bevor das finale Signal in ein Flipflop übernommen wird.
Du hast mit der allgemeinen Betrachtung natürlich recht, aber ich hatte
(in Unkenntniss des hoffentlich synchronen Umfelds) angemäkelt, dass
Signale ohne weitere Synchronisation taktsynchron weiterverarbeitet
wurden:
>> Warum? Weil du asynchrone Eingänge vergleichst:>> if (DATA_IN < TRIG_LEVEL) then>> less <= '1';>> equal <= '0';>> greater <= '0';>> Und dann die kombinatorisch ermittelten Werte (less..greater) ohne>> weitere Synchronisation direkt weiterverwendest:>> if falling_edge (CLK) then>> q_dff_3 <= (greater or equal or out_trig_hi);>> end if;
Da unten könnte gleichwertig auch stehen:
1
iffalling_edge(CLK)then
2
q_dff_3<=(DATA_IN>TRIG_LEVELorout_trig_hi);
3
endif;
Und wenn dann DATA_IN oder TRIG_LEVEL asynchron wären... :-o
Fazit: wie Harald sagt dürfen natürlich alle Signale auch schon vor dem
Einsynchronisieren logisch verknüpft werden. Nur braucht dann auch
dieses kombinierte Signal irgendeine Validierung, bevor es taktsynchron
verwendet werden darf.
Hallo
Danke für eure Antworten und Tips. Hab gestern sehr lange Lothar seine
Seite besucht und gelesen und gelesen.. Sehr, sehr interressant!
Nun nochmal zu meiner Teilkomponente "Trigger".
DATA_IN kommt von einem ADC, der mit CLK getaktet wird. Ich weiß nicht,
ob man da sagen kann, die Daten kommen Taktsyncron. Denn laut Datasheet
des ADC stehen die Daten "typischer Weise" nach 5.9ns nach der L->H
Flanke des Taktes bereit. Dies kann allerdings auch schon mal 12ns
dauern. Der CLK für den ADC ist der selbe wie für den Trigger
(Comparator).
Das Stop-Signal soll später mal von dem Adresszähler ( den ich noch
nicht einmal angefangen hab zu schreiben) erzeugt werden, und zwar dann,
wenn ein bestimmter Zählerstand erreicht ist, und nichts mehr in den
internen BRAM gespeichert werden soll. Zähler soll sozusagen Stop
ausgeben und seinen Zählerstand auf "0000000000" zurücksetzen. Bis
irgendwann der Trigger wieder frei gegeben wird. Dies soll von außerhalb
des FPGA´s durch irgendeine MCU via serielle Schnittstelle zum FPGA
geschehen. Soweit eigentlich mein Vorhaben.
Als internen Reset bezeichne ich leider doch den RESET der von außerhalb
über einen RESET Taster erzeugt wird. Ist auf meinen Board halt so
vorgegeben und ich weiß nicht, ob ein FPGA bei seiner Initialisierung
einen Internen Reset in irgend einer Weise durchführt.
Ich verwende übrigens einen LATTICE FPGA vom Typ XP3 (LFXP3C) Speedgrad
-3. War letztens auf der Electronica in München und da wurde mir LATTICE
empfohlen für mein Vorhaben.
Hatte eigentlich vorgehabt mit Xillix Spartan3 zu arbeiten, aber da gab
es dieses unwiederstehliche Angebot einer Platine mit dem LFXP3C als
FPGA im Internet unter: http://www.hardware-design.de/ das HWD-LFXP3C
Eval_board für unschlagbare 24€. Da hab ich natürlich zugeschlagen!
Wo ich jetzt gerade hänge ist die Verwendung der internen Block-RAMs als
Speicher, die Generierung des Adresszählers für die Speicherung und die
Clock-Generierung für den ADC (bis 80Mhz) aus dem auf dem Board zur
Verfühgung stehenden 25Mhz Oszilators (werd ihn wohl eher auf 40Mhz
umrüsten).
Die serielle Schnittstelle, ähnlich SPI hab ich schon fertig. Die
liefert mir übrigens auch den Vergleichswert TRIG_LEVEL für den
Comparator. Die Übernahme eines neuen TRI_LEVEL Wertes geschieht jetz
noch über einen Impuls (Länge: mindestens 60ns) von LOAD_Data von der
seriellen Schnittstelle von außen.
Sollte ich den auch einsyncronisieren über den CLK des ADC?
Grüße
Steffen
Ach ja, über Block-RAM Impementierung hab ich inzwischen schon viel
gefunden im WWW. Aber wie ich den Adresszähler gestalte leider noch
nicht. Ist wahrscheinlich nur ein ganz einfacher Zähler/Counter der noch
den BRAM_ENable und BRAM_WR generiert.
Ist das so einfach???
Doch dieser sollte doch irgendwie gesteuert werden, oder?
Gerade wenn man nur Daten aufzeichnen will, wenn ein "JetztZähle"-Signal
anliegt. Und dann selbstständigt stoppt wenn die maximale
Speicheradresse erreicht ist und sich selbstädigt wieder rücksetzt.
Da seh ich gerade den Wald vor Bäumen nicht.
Muss mich noch ein wenig belesen und auf eure Hilfe, Tips, Denkanstöße
warten..
Steffen
Wie wäre es mit einem Blockram FIFO? Oder brauchst du nach der Aufnahme
wahlfreien Zugriff auf die Samples? Den FIFO könntest du einfach so
lange beschrieben, bis er voll ist. Daszu gibts das Full Flag. Ist
natürlich die einfachste Lösung, aber wenn die Aufnahmlänge erst mal fix
ist...wieso nicht?
Hallo Christian
Ich würde lieber einen normalen RAM bauen, damit eventuell noch mit
einem PRE-Trigger arbeiten kann
.
Mir reicht es jetzt allerdings erst einmal aus, wenn bei ausgelöstem
Trigger (TRIG_OUT) der BRAM mit den Daten gefüllt wird bis er voll ist.
Ich denk mal es werden eher 2-3 verschaltete BRAM´s werden.
Ist der BRAM also voll, wird der Trigger gestoppt (TRIG_EN =0 und
TRIG_OUT =0) und ein weiteres Signal (SAMPLE_READY) generiert um dem MC
anzuzeigen, dass er die DATEN nun auslesen kann.
Ist der MC mit der Aufbereitung der Daten fertig, gibt er den Trigger
wieder frei. (TRIG_EN =1)
Grüße
Steffen