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
Ups, Sorry! Das war die Testbench. Hier jetzt der richtige Code. Vieleicht kann man da noch was in Components machen? 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 | if falling_edge (CLK) then |
2 | q_dff_3 <= (greater or equal or out_trig_hi); |
3 | end if; |
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 | if falling_edge (CLK) then |
3 | if (stop ='1' or RESET ='0') then |
4 | q_dff_1 <= '0'; |
5 | else
|
6 | q_dff_1 <= less; |
7 | end if; |
8 | end if; |
9 | end process; |
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 | if falling_edge (CLK) then |
2 | q_dff_3 <= (DATA_IN > TRIG_LEVEL or out_trig_hi); |
3 | end if; |
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.