Hallo Leute
Wie der Beitragsnahme schon verrät möchte ich einen ADC mit einem FPGA
auslesen und die Daten des ADC im BRAM speichern.
Die Daten des ADC liegen bei der steigenden Flanke des sys_CLK's am
Eingang des FPGA bereit. Gesteuert soll der FPGA von einem XMega werden.
Der Start der Aufzeichnung der ADC-Daten soll durch eine steigende
Flanke von "RUN" erfolgen. Die Aufzeichnugsgeschwindigkeit richtet sich
nach dem variabelen Clock "var_CLK".
In einer State Maschine sollen die zum Schreiben der Daten in den BRAM
erforderlichen Control-Signale wie die Schreib-Adresse, Write-EN und der
Write-CLK erzeugt werden.
Ich hab das in eine FSM gepackt, weil ich die Daten nicht einfach
nacheinander in das BRAM schreiben will wie man es bei einem FIFO macht.
Deswegen hab ich auch eine PreTrigger-Adresse. Soll heißen: Bis zur
PreTrigger-Adresse sollen die Daten wie in einem Ringspeicher
aufgezeichnet werden und wenn das Trigger-Signal kommt wird die
momentane (also die letzte Adresse im Ringspeicher vor dem
Trigger-Signal) in "s_trig_addr" kopiert.
Siehe:
1
elsifNEXT_STATE_WR=STS_ADR_RDthen
2
s_wr_clk<='1';
3
s_wr_en<='1';
4
s_trig_addr<=s_wr_addr;
5
s_wr_addr<=to_integer(unsigned(PRE_TRIGGER))+1;
6
s_trigger<='1';
Ab da sollen die neuen Daten des Triggerzeitpunktes ab der
PreTrigger-Adresse bis zur End-Adresse ("trace_length") in den BRAM
gespeichert werden.
1
elsifNEXT_STATE_WR=WR_ADR_POSTthen
2
3
ifs_wr_addr=trace_lengththen
4
s_wr_rdy<='1';
5
s_trig_en<='0';
6
else
7
s_wr_addr<=s_wr_addr+1;
8
s_wr_clk<='1';
9
s_wr_en<='1';
10
endif;
11
endif;
Kann man das so wie ich das hier versucht habe zu lösen machen, oder
gibt es da elegantere Lösungen?
Ich frage desshalb, da es nicht richtig stabil läuft..
Wäre nett, wenn mal jemand über den VHDL Code schauen könnte.
Grüße
Steffen
Hm, das macht man nicht so. Leg den Takt (konstant und mit wenig Jitter
direkt vom Quarzoszillator) an den ADC und an einen CLK Eingang des
FPGA. Dann intern den CLK dauerhaft an den BRAM. Gesteuert wird das
ganze dann mit dem WE Signal und einem Adresszähler. Und variable
Abtastrate macht man, indem man nicht alle Samples in den RAM schreibt,
sondern jedes 2. jedes 4. usw. denn schnelle ADCs mögen es nicht, wenn
sie (viel) langsamer als ausgelegt getaktet werden. Und ein variabler
Takt für einen ADC bringt immer Jitter mit sich, was sich in digitalem
Rauschen auswirkt. Übrigens kann man einen Pretrigger auch ganz einfach
mit einem FIFO machen. Einfach reinschreiben, und wenn Pretrigger-Anzahl
erreicht, mit jedem Schreiben ein Wort auslesen, dann hast du immer die
letzten x Samples drin. Wenn ein Trigger kommt, das Auslesen abstellen.
Aber so wie du es machen willst, gehts auch.
Hallo Christian
Also der ADC läuft kontinuierlich mit 50Mhz. Der bekommt keinen variblen
Takt ab.
Ich habe nur einen 25Mhz Oszillator am FPGA. Mit der PLL takte ich im
FPGA den Takt auf 50Mhz und gebe den auch über einen Pin des FPGA an den
ADC aus.
Der variable Takt ist ja von dem internen systemTakt abgeleitet. Dieser
soll ja die Speichergeschwindigkeit bestimmen. Also generier ich in
Abhängigkeit dieses variablen Taktes die Adresse sowie den WrClockEN des
BRAM's.
Wie man im Timing des BRAM's sehen kann man doch mit WrClockEN das
schreiben steuern, oder täusch ich mich da? An den WrClock des BRAM's
geht ja der SystemClock dran und das sind ja 50Mhz.
Was mir jetzt gerade auffällt ist der "WE" !
Warum ist der im BlockSchaltBild und nicht im Timingdiagramm wieder zu
finden? Ich dachte ja eigentlich auch dass man damit lesen/schreiben
steuert. Aber ich hab ja jeweils einen WrClockEN und einen RdClockEN.
???
Jetzt bin ich schon etwas durcheinander.
Wozu soll der "WE" denn sein?
Grüße Steffen
Steffen H. schrieb:> Also der ADC läuft kontinuierlich mit 50Mhz. Der bekommt keinen variblen> Takt ab.> Ich habe nur einen 25Mhz Oszillator am FPGA
Damit hast Du zwei Taktquellen und zwei verschiedene Taktdomänen.
Stichwort: Clock Domain Crossing
Selbst wenn Du aus den 25 MHz im FPGA 50 MHz machst, sind die anders
(Frequenz, Phasenlage) als die 50 MHz des ADCs.
Für ein synchrones Design würde ich den Takt, den der ADC bekommt auch
im FPGA verwenden (einfache Lösung). Andernfalls muß da ein asynchrones
FIFO dazwischen und Du mußt damit rechen, daß der ADC seine Daten
vielleicht mit 50,00001 MHz liefert, die der FPGA nur mit 49,99995 MHz
ausliest und damit der FIFO irgendwann voll ist (komplexere Lösung).
Duke
Duke Scarring schrieb:> Damit hast Du zwei Taktquellen und zwei verschiedene Taktdomänen.> Stichwort: Clock Domain Crossing>> Selbst wenn Du aus den 25 MHz im FPGA 50 MHz machst, sind die anders> (Frequenz, Phasenlage) als die 50 MHz des ADCs.
Wenn die 50MHz aus den 25MHz via DCM erzeugt werden, kann das recht gut
unter Kontrolle gehalten und definiert werden, weil das FPGA seinen
Taktmanager ja persönlich kennt. Da kann das Taktdomänenproblem
eigentlich nicht auftreten.
Aber auch ich würde hier eher das gesamte Design auf 50MHz laufen
lassen. Niemals wird ein Takt für eine Komponente (BRAM) aus der
Kombinatorik erzeugt:
>>> s_wr_clk <= '1'; <<<
Der Takt liegt einfach dauernd an, das ClockEnable am DPRAM dient
eigentlich nur dem Stromsparen und bleibt auch dauernd an. Das Schreiben
wird nur durch das WE gesteuert.
> Du mußt damit rechen, daß der ADC seine Daten vielleicht mit> 50,00001 MHz liefert, die der FPGA nur mit 49,99995 MHz ausliest
Sicher?
Da würde die DLL aber sehr schlecht einrasten...
Lothar Miller schrieb:>> 50,00001 MHz liefert, die der FPGA nur mit 49,99995 MHz ausliest> Sicher?> Da würde die DLL aber sehr schlecht einrasten...
Das war ein Bespiel. Je näher die beiden Takte aneinanderliegen, desto
seltener treten ja die Probleme auf. Und umso schwerer sind sie zu
detektieren und zu debuggen... (BTDT)
Duke
Duke Scarring schrieb:> Je näher die beiden Takte aneinanderliegen, desto> seltener treten ja die Probleme auf.
Hast du da einen DCM zum verdoppeln verwendet?
Mit 2 beliebigen Takten taucht der Fehler natürlich immer 1 Tag vor der
Auslieferung auf... :-/
(BZW: der Fehler ist natürlich schon vorher aufgetaucht, wurde aber
ignoriert...)
Hallo Duke
>> Also der ADC läuft kontinuierlich mit 50Mhz. Der bekommt keinen variblen>> Takt ab.>> Ich habe nur einen 25Mhz Oszillator am FPGA>Damit hast Du zwei Taktquellen und zwei verschiedene Taktdomänen.>Stichwort: Clock Domain Crossing
Warum hab ich da zwei Taktquellen? Wie Lothar es richtig erkannt hat
wird der Haupttakt = sys_CLK nur aus den externen 25MHz gewonnen und per
PLL im FPGA verdoppelt. Dies ist doch eigentlich mein Hauptakt im
gesamten FPGA, also mein System-Takt.
>Für ein synchrones Design würde ich den Takt, den der ADC bekommt auch>im FPGA verwenden (einfache Lösung).
Der ADC bekommt doch den selben Takt ab wie er im FPGA verwendet wird.
Also folgendes:
ext.25MHz->in_FPGA->FPGA_PLL->50MHz(sys_CLK)->Systen-Clock in gesamten
Design
->50MHz(sys_CLK)->FPGA_out->ADC_CLK
>Selbst wenn Du aus den 25 MHz im FPGA 50 MHz machst, sind die anders>(Frequenz, Phasenlage) als die 50 MHz des ADCs.
Warum ist das so? Hat der interne Takt(sys_CLK) wenn ich den über einen
Port nach aussen führe eine Verzögerung?
Grüße Steffen
Lothar Miller schrieb:
>Aber auch ich würde hier eher das gesamte Design auf 50MHz laufen>lassen. Niemals wird ein Takt für eine Komponente (BRAM) aus der>Kombinatorik erzeugt:>>> s_wr_clk <= '1'; <<<>Der Takt liegt einfach dauernd an, das ClockEnable am DPRAM dient>eigentlich nur dem Stromsparen und bleibt auch dauernd an. Das Schreiben>wird nur durch das WE gesteuert.
Also sollte ich lieber den BRAM folgendermaßen mit der Logic verbinden?
>>(LOGIC) sysCLK -> WrClock (BRAM)>>(LOGIC) '1' -> WrClockEN (BRAM)>>(LOGIC) WR_en -> WE (BRAM)
Das muss ich doch unbedingt mal ausprobieren.
Hallo
Hab jetzt mal 3 Varianten ausprobiert.
Variante 1: (ursprüngliche Version)
>>(LOGIC) sysCLK -> WrClock (BRAM)>>(LOGIC) wr_clk -> WrClockEN (BRAM)>>(LOGIC) WR_en -> WE (BRAM)>>> sysCLK: permanent 50Mhz>>> wr_clk: WR-Impuls von einer Periode der 50Mhz zur Datenübernahme,
Pausendauer zwischen den Impulsen variert je nach Auf-
zeichnungsgeschwindigkeit
>>> WR_en: geht am Beginn der Aufzeichnung auf '1' und erst am Ende der
Aufzeichnung wieder auf '0'
Ergebnis:
>> Daten landen nicht immer richtig im BRAM
Variante 2: (WE permanent auf 'High')
>>(LOGIC) sysCLK -> WrClock (BRAM)>>(LOGIC) wr_clk -> WrClockEN (BRAM)>>(LOGIC) '1' -> WE (BRAM)>>> sysCLK: permanent 50Mhz>>> wr_clk: WR-Impuls von einer Periode der 50Mhz zur Datenübernahme,
Pausendauer zwischen den Impulsen variert je nach Auf-
zeichnungsgeschwindigkeit
>>> WE: permanent auf 'High' Pegel
Ergebnis:
>> Daten landen richtig im BRAM
Variante 2: (WrClockEN permanent auf 'High')
>>(LOGIC) sysCLK -> WrClock (BRAM)>>(LOGIC) '1' -> WrClockEN (BRAM)>>(LOGIC) WR_en -> WE (BRAM)>>> sysCLK: permanent 50Mhz>>> wr_clk: permanent auf 'High' Pegel>>> WR_en: WR-Impuls von einer Periode der 50Mhz zur Datenübernahme,
Pausendauer zwischen den Impulsen variert je nach Auf-
zeichnungsgeschwindigkeit
Ergebnis:
>> Daten landen richtig im BRAM (gleiches Ergebnis wie Variante2)
Jetzt frag ich mich wirklich ernsthaft wozu "WE" am generierten
pseudo-DP-RAM gut ist!?
Wie schon gesagt, ich habe getrennte WrClockEN und RdClockEN :/
Ich häng nochmal das Timing und das Blockbild dran.
Steffen
Hallo Duke
Ich hab es live mit dem Board probiert. Und nach mehrmaligen
durchprobieren der einzelnen Versionen gab es nur eine leichte
Verbesserung der Version2 und Version3 zur Version1. Es sind aber immer
noch aussetzer drin! Woher die auch immer kommen :/
1
s_trig_addr<=s_wr_addr;
2
s_wr_addr<=to_integer(unsigned(PRE_TRIGGER))+1;
Kann man die Schreib-Adresse, so wie ich es gemacht habe, einfach in
"s_trig_addr" zwischenspeichern und dann die selbige neu initialisieren?
Oder gibt es da eventuell Probleme?
Doch wie gesagt, ich versteh den Sinn von WE am pseudo-Dual-Port-RAM
nicht! Der WE ist ja auch im Timing-Diagramm gar nicht mit aufgenommen.
Allerdings muss WE zum schreiben einen "High"-Pegel haben. Das hab ich
getestet.
Hab mir auch mal die Variante von Christin durch den Kopf gehen lassen
mit dem FIFO.
>>Christian schrieb:>Übrigens kann man einen Pretrigger auch ganz einfach>mit einem FIFO machen. Einfach reinschreiben, und wenn Pretrigger-Anzahl>erreicht, mit jedem Schreiben ein Wort auslesen, dann hast du immer die>letzten x Samples drin. Wenn ein Trigger kommt, das Auslesen abstellen.
Ich denke mir mal, das ab einer bestimmten Adresse(X) durch das
gleichzeitige Lesen des FIFO's ja nicht alle Adressen automatisch
nachrutschen. Oder wie soll das dann ablaufen?
Steffen
Klar geht das. Du schreibst meinetwegen 2000 Worte rein, ohne
auszulesen. Ab da liest du bei jedem Schreiben auch ein Wort aus. Dann
wird das beim 2001. Wort das 1. unten rausgeworfen und das 2001. rutscht
auf die Stelle des 2000. usw. der ganze FIFO kreiselt dann, und hält
immer die letzten 2000 Worte. Natürlich gibts da unzähliche andere Wege,
bei 2^n Worten Pretrigger gehts immer sehr gut mit Bitmasken auf dem
Adresszähler usw.
Ich hab gerne die FIFO Lösung genommen, die hat nur den Nachteil, dass
man während dem Pretrigger den Lesetakt mit einem BUFGMUX beispielsweise
umschalten muss. Was natürlich auch geht: Die einstellbaren FIFO-Flags
benutzen. Dann sparst du dir das synchronisieren. Du stellst die
FIFO-Flasg-Schwelle auf die Pretrigger größe, und wenn die Überschritten
wird, öffnest du RE und der FIFO kreiselt genauso. Da muss man dann nur
aufpassen, die FLags haben durch die Gray-Zähler +-1 Takt Latenz. Oder
aber du machst das selber mit dem Ausgangsvektor, der den Füllstand auf
der Leseseite anzeigt....
Danke für deine Hilfe Christian.
Dann werd ich das demnächst mal ausprobieren.
Noch ein paar Fragen dazu:
>während dem Pretrigger den Lesetakt mit einem BUFGMUX umschalten
Was macht man mit dem BUFGMUX? Weil ich arbeite mit eimnem Lattice.
Meinst du damit zufällig das man den Lesetakt dann zwischen zwei
verschiedenen Takten umschalten muss?
>Die einstellbaren FIFO-Flags benutzen. Du stellst die FIFO-Flasg-Schwelle>auf die Pretrigger-Größe
Das wäre optimal wenn das so einfach gehen sollte. Zweifel dabei hab ich
allerdings dass dies funktioniert wenn ich einen
variabelen/einstellbaren PreTrigger habe. Denn die Flag-Schwellen werden
doch im IP-Core-Generator vorher bestimmt. Die Dokumentation ist leider
sehr schlecht bei Lattice. Leider..
Grüße Steffen
Ahso, ich arbeite mit Xilinx, da braucht man zum Takte schalten einen
BUFGMUX. Sowas gibts bei Lattice bestimmt auch. Ist halt dann eine
herstellerspezifische Primitive. Bei den Xilinx FIFO Cores kann man
einstellen, dass man die Schwellen während der Laufzeit einfach ändern
kann, da it ja nur ein Komparator drin. Ebenso erlauben die FIFOs
Füllstandsanzeigen, sogar für die Write und die Read Domain getrennt.
Sowas geht sicher bei Lattice auch, kann mir nicht vorstellen, dass die
da in viel nachstehen.
Okay,
BUFGMUX = DCS bei Lattice. Sowas gibt´s da also auch. Aber ob ich die
Schwellen des FIFO's zur Laufzeit ändern kann, muss ich noch versuchen
rauszubekommen. Auf alle Fälle haben die FIFO's "empty",
"allmost_empty", full" und "allmost_full" Flags.
Steffen H. schrieb:> Ich hab es live mit dem Board probiert. Und nach mehrmaligen> durchprobieren der einzelnen Versionen gab es nur eine leichte> Verbesserung der Version2 und Version3 zur Version1. Es sind aber immer> noch aussetzer drin! Woher die auch immer kommen :/
Ah. Unqualifiziertes rumprobieren. Ich nutze für sowas einen Simulator
und eine Testbench. Da kann ich mehr sehen, als nur geht/geht nicht...
Duke
Hallo
Duke schrieb:
>Ah. Unqualifiziertes rumprobieren. Ich nutze für sowas einen Simulator>und eine Testbench. Da kann ich mehr sehen, als nur geht/geht nicht...
Da hast du schon irgendwie Recht Duke. Dann werd ich mal am WE eine
Testbench bauen. Der nachteil einer Testbench ist nur die, dass die
Verzögerungen/Delays nicht mit einbezogen werden. Die müsste man dann
alle manuell im code setzen.
Wie Beispielsweise:
>>> s_wr_clk <= '1' after 6 ns; <<<
Aber was solls, wenn man den Fehler nicht mehr so einfach im Code selber
finden kann dann bleibt mir ja garnix anderes mehr übrig.
@Christian
Mit dem FIFO komm ich gerade auch nicht weiter. Was ich schon
rausbekommen hab ist: Es gibt bei Lattice ebenfalls die Möglichkeit die
Adressen für die Flags "dynamisch" im laufenden Desingn zu setzen. Heut
Nachmittag hörte sich das alles noch so einfach an. Und nun seh ich
schon wieder den Wald vor lauter Bäumen nicht.. Naja, eins nach dem
anderen.
Ich kann mir übrigens auch beim FIFO die Addressen nach außen führen
lassen. Mal sehen, ob das auch noch eine Option für mich ist.
Also danke schonmal für Euere Hilfe bis hierhin.
Steffen
In der Testbench musst du sinnvollerweise die Delays der externen
Komponenten setzen, beispielsweise dein ADC. Die internen Delays weiß
die Lattice Toolchain nach dem Routen. Und dann kannst du wenn gar nix
hilft, eine Timing-Simulation machen. Grundlage sind dann die VHD
Beschreibung der fertig gerouteten Netzliste und die SDF Delay Daten.
Modelsim kann das dann mit dem echten Timing im FPGA simulieren und
spueckt auch Fehler aus, wenn Setup- und/oder Hold-zeiten der internen
Komponenten verletzt werden. Natürlich nur, wenn Lattice das gescheit
einprogrammiert hat. Bei Xilinx klappt das jedenfalls, bei Lattice ganz
sicher auch.
So eine Timing-Simulation ist aber nur das letzte Mittel, zunächst mal
muss man natürlich eine Verhaltenssimulation machen. Wenn man ohne Simu
FPGA Designs entwirft, tappt man ziemlich oft im Dunkeln und muss nur
raten, wo der Fehler liegen könnte.
Na dann ist der erste Schritt jetzt eine gescheite Testbench zu
erstellen. Und dann die Simulation anwerfen und schauen, was passiert.
Sonst kommst du eh kaum weiter. Ohne Simulation kann man vielleicht ein
kleines CPLD Design machen, aber ein komplexes FPGA? Naja...
In einer Testbench hast du ja die Simulationszeit now. Und diese
Simulationszeit kannst du durch eine andere Zeit teilen und dann als
Argument an die sin() Funktion übergeben:
Hehe, so gehts natürlich auch. Ich mach es immer über den Text-Dateien
Weg, weil ich fast immer reale Signale einspeise um die Funktion meiner
Signalverarbeitungskette zu simulieren. Für rein mathematische Signale
ist Lothars Weg natürlich etwas einfacher.
Danke euch beiden.
@Christian
Das mit der textio muss ich mir erst mal noch genauer durchlesen. Gibt's
ja hier genug Beiträge im Forum.
Die Methode von Lothar klingt auch sehr gut.
@Lothar
>In einer Testbench hast du ja die Simulationszeit now.
Wie groß ist den die Simulationszeit? Die konnte man doch irgendwo
einstellen, bzw. in irgendeiner Datei hab ich das schon mal gesehen. Ist
die so um die 1ps?
Ich hab jetzt erst mal so auf die Schnelle versucht ein Rechteck-Signal
mit Rise-und Falltime zu generieren.
Ich glaub ich hab schon den ersten Fehler gefunden. Zumindest die
Simulation mag es gar nicht mit uninitialisierten Signalen zu arbeiten.
Hier mal noch ein Auszug aus meinem Trigger:
Ich versuch es mal kurz zu beschreiben wie sich "s_trig_hold" verhalten
sollte:
"s_trigger=1" soll "s_trig_hold" setzen, aber nur falls "s_trig_hold=0"
ist. Ist "s_trig_hold=1" dann tut "s_trigger" nix. Allerdings sollte
dann der "var_CLK" "s_trig_hold" wieder zurücksetzten.
"s_trig_hold" ist doch als "std_logic" deklariert. Das heißt ja er kann
13 verschiedene Zustände haben. Und so versteht es auch die Simulation.
Denn "s_trig_hold" kommt aus dem Zustand "U" gar nicht erst raus.
Würde es gehen, wenn ich es so löse?
Ich denke mir dabei: s_trig_hold ist ja ein Signal und keine Variable.
Dann müsste doch wenn s_trig_hold als letzten Zustand eine '1' hatte
doch auch die Abfragen (if) noch auf den letzten Zustand greifen und
nicht auf den neu gesetzten vor den if-Abfragen? Oder hab ich da einen
Denkfehler?
Steffen
Steffen H. schrieb:> Zumindest die> Simulation mag es gar nicht mit uninitialisierten Signalen zu arbeiten.
Doch: sie arbeitet mit 'U'. Und irgendwas irgendwie mit 'U' verknüpft,
gibt 'U'...
> Dann müsste doch wenn s_trig_hold als letzten Zustand eine '1' hatte> doch auch die Abfragen (if) noch auf den letzten Zustand greifen und> nicht auf den neu gesetzten vor den if-Abfragen?
Das schon, aber:
> Oder hab ich da einen Denkfehler?
Ja. Du denkst in Signalen und Variablen und deren Verhalten. Das ist
Unsinn. Denn letztlich muß deine Beschreibung in FFs und LUTs abgebildet
werden. Und du mußt es eben so beschreiben, dass das geht...
> Denn "s_trig_hold" kommt aus dem Zustand "U" gar nicht erst raus.
Such dir Stelle, wo das signal definiert wird und schreib da einen
Initwert hin:
signal s_trig_hold : std_logic := '0';
Steffen H. schrieb:>>In einer Testbench hast du ja die Simulationszeit now.> Wie groß ist den die Simulationszeit? Die konnte man doch irgendwo> einstellen,
Da brauchst du nicht einstellen: die Simulationszeit ist das, was du
in der Waveform oben in der Zeitskala siehst.
> bzw. in irgendeiner Datei hab ich das schon mal gesehen.> Ist die so um die 1ps?
Das ist die kleinste zeitliche Auflösung der Simulation.
>>>Und Modelsim bringt mir spontan eine "nette" Fehlermeldung!
# Model Technology ModelSim PE Student Edition vcom 6.6d Compiler
2010.11 Nov 2 2010
# -- Loading package standard
# -- Loading package std_logic_1164
# -- Loading package numeric_std
# -- Loading package math_real
# -- Compiling entity testbench
# -- Compiling architecture behavior of testbench
# ** Error:
I:/FPGA/Versuche/DSO_CORE_8bit/TEST_TRIGGER_RAM/tb_sampler.vhd(79): No
feasible entries for infix operator "*".
# ** Error:
I:/FPGA/Versuche/DSO_CORE_8bit/TEST_TRIGGER_RAM/tb_sampler.vhd(79):
Cannot resolve expression type of infix expression.
# ** Error:
I:/FPGA/Versuche/DSO_CORE_8bit/TEST_TRIGGER_RAM/tb_sampler.vhd(79):
Illegal type conversion to std.standard.integer (operand type is not
known).
# ** Error:
I:/FPGA/Versuche/DSO_CORE_8bit/TEST_TRIGGER_RAM/tb_sampler.vhd(129): No
feasible entries for infix operator "*".
# ** Error:
I:/FPGA/Versuche/DSO_CORE_8bit/TEST_TRIGGER_RAM/tb_sampler.vhd(129): Bad
expression in left operand of infix expression "/".
# ** Error:
I:/FPGA/Versuche/DSO_CORE_8bit/TEST_TRIGGER_RAM/tb_sampler.vhd(129): No
feasible entries for subprogram "sin".
# ** Error:
I:/FPGA/Versuche/DSO_CORE_8bit/TEST_TRIGGER_RAM/tb_sampler.vhd(129):
Cannot resolve expression type of infix expression.
# ** Error:
I:/FPGA/Versuche/DSO_CORE_8bit/TEST_TRIGGER_RAM/tb_sampler.vhd(129):
Illegal type conversion to std.standard.integer (operand type is not
known).
# ** Error:
I:/FPGA/Versuche/DSO_CORE_8bit/TEST_TRIGGER_RAM/tb_sampler.vhd(129):
Type conversion (to std_logic_vector) can not have aggregate operand.
# ** Error:
I:/FPGA/Versuche/DSO_CORE_8bit/TEST_TRIGGER_RAM/tb_sampler.vhd(200):
VHDL Compiler exiting
>>Das versteh ich jetzt mal gar nicht. Zumal Modelsim ja das Package >>"math_real"
geladen hat!
Jemand eine Idee?
Steffen
So, hier mal die Waves der Verhaltens-Simulation. Hier sieht alles
perfekt aus. Hab den Ausschnitt extrem verkleinert gewählt, damit man
die Aufzeichnung des PreTriggers besser erkennen kann.
Wenn der Fehler nur ab und zu auftritt, ist es ein Timing-Problem. Hast
du denn die Timing Constraints richtig gesetzt? Also den/die Clocks erst
mal und dann noch mindestens die Eingänge für die ADC Daten?
Ganz ehrlich? Ich kenn mich mit den Timing-Constraints noch gar nicht
aus. Wo schreibt man die eigentlich rein? Ich hab ein paar in der "lpf"
und "prf" Datei drin. Ich häng sie mal mit dran.
Ich müsst wahrscheinlich mal noch die Beziehung zwischen den externen
Signalen zu dem internen Clock setzten. Aber wie das geht hab ich mir
noch noch nicht erarbeitet.
Bei der Synthese bekomme ich auch noch eine Warnung:
>>> A user-defined clock should be declared on object "p:sysCLK" <<<
Und da hab ich auch immer noch nicht raus bekommen wo und wie ich da
sysCLK deklariere.
Jetzt hab ich gerade in einer Projektdatei gesehen:
>> # mapper_options>> set_option -frequency 50>>> set_option -auto_constrain_io 1 <<<>> set_option -write_verilog 0>> set_option -write_vhdl 0
Ich sollte mir also eine Constraint Datei basteln.
Bitte habt ein wenig Nachsicht mit mir. Hab mir VHDL selber bei gebracht
und noch am lernen.Hab erst vor 4 Monaten damit angefangen.
Grüße Steffen
Und Modelsim bringt mir spontan eine "nette" Fehlermeldung!
>># Model Technology ModelSim PE Student Edition vcom 6.6d Compiler>>2010.11 Nov 2 2010>># -- Loading package standard>># -- Loading package std_logic_1164>># -- Loading package numeric_std>># -- Loading package math_real>># -- Compiling entity testbench>># -- Compiling architecture behavior of testbench>>># ** Error:>>I:/FPGA/tb_sampler.vhd(79): No feasible entries for infix operator "*".>>># ** Error:>>I:/FPGA/tb_sampler.vhd(79): Cannot resolve expression type of infix expression.>>># ** Error:>>I:/FPGA/tb_sampler.vhd(79): Illegal type conversion to std.standard.integer>>(operand type is not known).>>># ** Error:>>I:/FPGA/tb_sampler.vhd(129): No feasible entries for infix operator "*".>>># ** Error:>>I:/FPGA/tb_sampler.vhd(129): Bad expression in left operand of infix expression
"/".
>>># ** Error:>>I:/FPGA/tb_sampler.vhd(129): No feasible entries for subprogram "sin".>>># ** Error:>>I:/FPGA/tb_sampler.vhd(129): Cannot resolve expression type of infix expression.>>># ** Error:>>I:/FPGA/tb_sampler.vhd(129): Illegal type conversion to std.standard.integer>>(operand type is not known).>>># ** Error:>>I:/FPGA/tb_sampler.vhd(129): Type conversion (to std_logic_vector) can not>>have aggregate operand.>>># ** Error:>>I:/FPGA/tb_sampler.vhd(200): VHDL Compiler exiting
Das versteh ich jetzt mal gar nicht. Zumal Modelsim ja das Package
"math_real" geladen hat! Was mache ich da falsch?
Hat dazu jemand eine Idee?
Steffen
Danke Lothar,
Wird sofort nach Feierabend ausprobiert. Ich hatte dank der Testbench
noch ein paar Fehler in meinem Design (siehe Anhänge ganz oben) gefunden
und schon erfolgreich beseitigt.
Tolles Forum hier! Muss ich jetzt ernsthaft mal anmerken.
Grüße Steffen
Hallo Lothar
Ich hab es hin bekommen! Danke nochmal. Im Anhang mal noch ein paar
Waves von der Testbench. In "Real", also in der Hardware scheint es auch
alles so zu klappen. Habe jetzt keine Aussetzer und krummen Werte die
mir das Design bringt.
Der ADC wird momentan allerdings nur mit 50Mhz getaktet. Deswegen ja
auch nur max. 5Mhz als Eingangssignal.
Werde dann mal später, wenn mal alles soweit auf einer Platine ist
versuchen hier und da noch zu optimieren um noch ein wenig mehr Speed
aus dem FPGA zu holen. (Pipelining)
Momentan lässt das Design laut Timing-Report nur max 69.1Mhz zu. Zum
Optimieren muss ich mich wohl oder übel in die Timing-Constraints
einarbeiten müssen. Da ist dann bestimmt nochmal EURE HILFE gefragt.
Bis dahin
Gruß Steffen
Steffen H. schrieb:> Momentan lässt das Design laut Timing-Report nur max 69.1Mhz zu. Zum> Optimieren muss ich mich wohl oder übel in die Timing-Constraints> einarbeiten müssen. Da ist dann bestimmt nochmal EURE HILFE gefragt.
Naja, der Wert stammt doch bestimmt aus der Synthese, oder? Das kann
dann nach dem P&R noch einiges mehr oder auch weniger werden.
Und die Timing Constraints optimieren nix, die sagen erst mal nur, wo
was nicht ausreicht.
Ja, genau das meinte ich. Wenn die Constraints richtig gesetzt sind,
dann meckert doch bestimmt die Synthese (Synplify) rum. Das schlechteste
Timing Ergebnis kommt im Modul RAM_CONTROL vor. Und da werd ich dann
nochmal ansetzen.
Steffen
Diese Meldung finde ich schon komisch:
>>>Found inferred clock PLL_MODUL_50Mhz_1|CLKOS_inferred_clock with period >>>10.00ns. A user-defined clock should be declared on object >>>"n:System_Clock.CLKOS"
Vor allem da sie in der PLL vorkommt und da ja eigentlich die CLK NETs
drin stehen. ???
Wie und wo ich die auch immer deklarieren (on object) soll!! Das gilt es
noch zu erforschen :)
Steffen
Timing Constraints werden im Normalfall erst nach der Synthese beachtet.
Es gibt zwar auch Synthese Constraint Files, aber die haben wenig mit
Timing zu tun.
Was die Warnung bedeutet, weiß ich nicht, arbeite nahezu ausschließlich
mit Xilinx.
Hallo
Um euch mal auf dem Laufenden zu halten: Heute mal die ersten Bilder
meines Projektes. Scheint alles ganz gut zu funktionieren. DSO in
TEK-Optik: 2 Kanäle mit einer analogen Bandbreite von min. 20Mhz.
Samplingrate allerdings est einmal (bloß) bei 50 Mhz. Jetzt geht es
erstmal an die Funktionen im Display.
LG Steffen
Und hier mal noch ein Bild zum Versuchsaufbau.
1x ATmega8: 4x Encoderauswertung + Aufbereitung
1x XMega128A1: 3x Encoderauswertung + Datenaufbereitung Display über
SDRAM
1x ATmega8515: Displaycontroller
1x LatticeXP: Datenspeicher + Trigger ADC Daten
Bis jetzt erst 1 analog-Kanal aufgebaut zum Testen!
Alles recht ESD conform.. ;-)