Hallo zusammen
Ich habe in meinem Projekt ein Quartus Block RAM erstellt und dieses mit
einem mif File initialisiert. In der Simulation verhält sich das RAM
genau so, wie ich es gerne hätte. In der Praxis, sieht es jedoch etwas
merkwürdig aus.
Ich bekomme von meinem LCD Modul die x und y position, wo gerade
gezeichnet wird. Dann kann ich die Farben bzw. RGB Werte mittels
REDstate, BLUEstate und GREENstate anpassen.
Wenn ich dies wie beim Kommentar "Rechteck anzeigen" mache, dann klappt
dies einwandfrei. Wenn ich jedoch den BLUEstate aufgrund des memData
Inhaltes anpasse, so wie etwas weiter oben im Code, dann zeigt mir das
Display manchmal kurz ein bisschen Blau an, und dann bleicht es aus. Ein
rotes Rechteck ist nicht mehr sichbar. Ohne die Zeile
SeriousSam schrieb:> Ev. muss BLUEstate ausserhalb des sichtbaren Bereichs 0 sein, es> wird aber nie zurückgesetzt.
Interessante Theorie.
Könnte tatsächlich sein. Wobei ich nicht verstehe, warum ich dann das
rote rechteck nicht sehen kann. Wenn ich BLUEState verwende, sehe ich
nur etwas blaues dass dann ausbleicht
Hat tatsächlich etwas gebracht. Jedoch das selbe problem, wenn ich die
nächste Farbe hinzufüge.
Ich glaube das Problem kommt von den Clocks.
Ich müsste glaube ich den RAM Clock um 180 Grad Phasenverschieben, damit
ich auch gültige Daten auslesen kann.
Was meint ihr?
Holger K. schrieb:> Ich müsste glaube ich
Was sagt denn die Simulation?
> Ich glaube das Problem kommt von den Clocks.
Worauf gründet dieser Glaube?
> den RAM Clock um 180 Grad Phasenverschieben, damit ich auch gültige> Daten auslesen kann.> Was meint ihr?
Das Problem liegt woanders. Sicher. Denn wenn es sowas wäre, dann
hättest du bestenfalls irgendeine Verschiebung...
Holger K. schrieb:> dann zeigt mir das Display manchmal kurz ein bisschen Blau an, und dann> bleicht es aus.
Und was passiert an den Ports? Kommen die Sync-Signale noch richtig?
Mich wundertübrigens, dass dein Display 481 Pixel hoch und 801 Pixel
breit ist:
Lothar M. schrieb:> Mich wundertübrigens, dass dein Display 481 Pixel hoch und 801 Pixel> breit ist: signal xPos : integer range 0 to 800;> signal yPos : integer range 0 to 480;
Das ist in der Tat ein Fehler.
Lothar M. schrieb:>> Ich glaube das Problem kommt von den Clocks.> Worauf gründet dieser Glaube?
Da es mit einem verschobenen Clok plötzlich besser wurde.
Ich habe nun folgendes gemacht:
Ist sowas in Ordnung oder eher ein Hack?
1
mem:entitywork.ram
2
portmap(
3
address=>address,
4
clock=>notclkpll,--180Grad Phasenschieben
5
data=>data,
6
wren=>wren,
7
q=>memData
8
);
Lothar M. schrieb:>> den RAM Clock um 180 Grad Phasenverschieben, damit ich auch gültige>> Daten auslesen kann.>> Was meint ihr?> Das Problem liegt woanders. Sicher. Denn wenn es sowas wäre, dann> hättest du bestenfalls irgendeine Verschiebung...
Ich hab mir das so vorgestellt, dass das RAM seine Daten mit der
steigenden Flanke an seinen Ausgang legt. Auf die steigende Flanke lese
ich jedoch auch den Ausgang des RAMs ein und gebe die Daten ans Display.
Nun dachte ich, dass es hierbei zu zufälligen treffern kommt. manchmal
hab ich die daten erwischt, manchmal nicht.
Nachdem ich nun den Code wie folgt angepasst habe:
Und den Memoryclock mit dem not invertiert habe, sieht das LCD wie im
angehängten Bild aus.
Das "rote" Rechteck ist auch sichtbar.
Scheint tatsächlich ein Clock problem gewesen zu sein.
Oder sollte ich noch etwas weiter suchen?
So nebenbei, was würde man bei einem solchen Projekt für Timing
Constraints definieren?
Falls jemand jemals über diesen Thread stolpert und gerne auch solch
eine Grafik hätte... Ich habe lediglich eine Zeile im RAM gespeichert.
das mif file ist im anhang. zum konvertieren von Bildern nutze ich
srecord bzw. srec_cat.exe mit folgenden befehlen:
Holger K. schrieb:> Oder sollte ich noch etwas weiter suchen?
Ja, denn du hast jetzt zwar irgendwas irgendwie hingebastelt, aber
dieses simple Design muss auch mit 1 Takt laufen.
Warum bleibt eigentlich das Sync-Timing stehen? Wird das auch über das
RAM gesteuert? Oder doch nur über 2 Zähler, wie üblich...
Holger K. schrieb:> ein Quartus Block RAM erstellt
Was sagt die Doku dieses RAM zu diesem Verhalten?
Lothar M. schrieb:> Warum bleibt eigentlich das Sync-Timing stehen? Wird das auch über das> RAM gesteuert? Oder doch nur über 2 Zähler, wie üblich...
Das Sync-Timing wird über Zähler gemacht.
Lothar M. schrieb:> Holger K. schrieb:>> ein Quartus Block RAM erstellt> Was sagt die Doku dieses RAM zu diesem Verhalten?
Das ist eine gute Frage.
Siehe das Bild im Anhang.
Sehr merkwürdig ist, dass das Datenwort welches an Adresse 01 liegt,
erst nach zwei memclk Takten kommt. alle weiteren kommen dann nach einem
Takt.
Das macht mir das leben gerade ziemlich schwer. Denn ich habe ein xPos
und yPos counter bzw. Integer.
Nun möchte ich ja rechtzeitig die Daten an den Datenbus legen, nämlich
VOR der posFlanke des LCD Pixel Clocks.
Grundsätzlich hätte ich dies geschafft, nämlich durch die erzeugung des
"framePulse" wie man im Diagramm sieht.
Dadurch dass aber aus irgendeinem Grund die Ausgabe des Worts von
Adresse 01 um einen weiteren Clock verzögert wird, funktioniert dies so
wieder nicht. Sehr ärgerlich.
So, ich musste folgende Einstellung entfernen:
Im Quartus MegaFunction Wizard die Registrierung des Ausganges q mit dem
Clock. Dann war mein erster zusätzlicher Clock weg.
Die aktuelle VHDL Datei habe ich mal angehängt.
Ich bin neu im Gebiet VHDL und würde mich sehr über Kommentare zum Code
freuen. Was man besser machen kann oder anders machen kann und was
vielleicht auch ok ist.
Danke
Holger K. schrieb:> Ich hab mir das so vorgestellt, dass das RAM seine Daten mit der> steigenden Flanke an seinen Ausgang legt. Auf die steigende Flanke lese> ich jedoch auch den Ausgang des RAMs ein und gebe die Daten ans Display.
Da offenbarst Du m.E. ein Verständnisdefizit ;).
Das RAM liest Du in einem getakteten Prozeß ein (eine Signalzuweisung,
die in einem Prozeß geschieht, der ein "rising_edge(...)" enthält,
erzeugt ein Register). Die Signalzuweisung in dem Prozeß macht im
selben Takt erst mal gar nichts, sondern sorgt lediglich dafür, daß
der entsprechende Wert rechtzeitig zur nächsten steigenden Taktflanke
im Register bereitsteht.
Im selben Takt wird entsprechend der vorherige Registerwert
verarbeitet.
Die Gedanken oben brauchst Du dir also nicht zu machen, das macht deine
Synthese für dich.
Ein solches Verhalten erzeugt natürlich - wenn (noch) nicht verstanden -
eine zunächst unvermutete Latenz: das Ergebnis kommt später an als
vermutet. Ich habe mir deinen Code nicht genau angeschaut, aber die
Symptome sprechen dafür, daß Du gerade genau dieses Problem hast...
Markus F. schrieb:
> Die Gedanken oben brauchst Du dir also nicht zu machen, das macht deine> Synthese für dich.
Bist du dir ganz sicher?
Immerhin geht es hierbei um das Einlesen von Signalen.
Soweit ich weiss, müssen diese eine gewisse Zeit vor und nach der
Clockflanke stabil bleiben.
Wenn ich mir die Simulation ohne invertierten Memoryclock ansehe, dann
kann ich nicht beurteilen, welchen Wert nun gesamplet wird, da genau
beim wechsel eingelesen wird. Ich dachte immer, sowas sollte man auf
keinen Fall machen.
Siehe das Bild im Anhang.
memData sind die Daten die AUS dem RAM rauskommen und in das Register
eingelesen werden sollen. Aber genau dann beim Einlesen ändern diese
ja....
Mit invertiertem Memoryclock sieht dies m.M.n besser aus.
Aber wie gesagt, bin ich noch kein Experte...
Holger K. schrieb:> Mit invertiertem Memoryclock sieht dies m.M.n besser aus.
Durch das Verwenden des invertierten Taktes verdoppelst du quasi den
Systemtakt. Deshalb bemerkst du dann eine Latency nicht, oder sie wirkt
sich anders aus.
Holger K. schrieb:> Wenn ich mir die Simulation ohne invertierten Memoryclock ansehe, dann> kann ich nicht beurteilen, welchen Wert nun gesamplet wird, da genau> beim wechsel eingelesen wird. Ich dachte immer, sowas sollte man auf> keinen Fall machen.
Schau' dir dasselbe Signal in TimeQuest an.
Dann wirst Du feststellen, daß - vorausgesetzt, das Design schafft die
Taktfrequenz - die Synthese dafür sorgt, daß der im Takt vorher
zugewiesene Wert gerade rechtzeitig zur steigenden Flanke bereitgestellt
wird, ohne die Hold-Time des vorigen Takts oder die Setup-Time des
aktuellen zu verletzen.
Das Invertieren des Taktes sorgt nur dafür, daß dein Design praktisch
mit doppelter Taktfrequenz läuft und damit maximal nur einen halb so
schnellen Takt schafft, wie es eigentlich könnte.
Markus F. schrieb:> Dann wirst Du feststellen, daß - vorausgesetzt, das Design schafft die> Taktfrequenz - die Synthese dafür sorgt, daß der im Takt vorher> zugewiesene Wert gerade rechtzeitig zur steigenden Flanke bereitgestellt> wird, ohne die Hold-Time des vorigen Takts oder die Setup-Time des> aktuellen zu verletzen.
Vielen Dank.
Dies werde ich versuchen.
Ist es dazu notwendig, Constraints im SDC File anzulegen? Oder kann er
dies ohnehin syntethisieren?
Danke.
Holger K. schrieb:> Ist es dazu notwendig, Constraints im SDC File anzulegen? Oder kann er> dies ohnehin syntethisieren?
Wenn Quartus weiß, mit welchem Takt dein Design laufen soll (das
sollte natürlich mindestens im .sdc-File stehen) und Du keine
"Extra-Würste" (wie Taktdomänenübergänge, asynchrone Signale oder
Multicycles) drin hast, geht der Rest innerhalb des FPGAs
üblicherweise von alleine und braucht keine weiteren Angaben.
Entweder geht dann das Timing auf oder Du hast noch zu lange
sequentielle Ketten drin und bekommst timing violations, die Du durch
einfügen von Registern oder Multicycles "aufbrechen" mußt.
Markus F. schrieb:> Wenn Quartus weiß, mit welchem Takt dein Design laufen soll (das> sollte natürlich mindestens im .sdc-File stehen)
Bedeutet dies, dass sowas genügt als komplettes SDC File?
Holger K. schrieb:> Sehr merkwürdig ist, dass das Datenwort welches an Adresse 01 liegt,> erst nach zwei memclk Takten kommt. alle weiteren kommen dann nach einem> Takt.
Das ist bei Altera BlockRAMs so - es hat ein nicht deaktivierbares
Ausgangsregister. (Immerhin kann man Eingangs-Register deaktivieren).
Bei Xilinx kann man es weg-konfigurieren und braucht dann einen
Taktzyklus weniger.
Das mit "alle weiteren kommen dann nach einem Takt" scheint nur so, weil
es quasi wie eine Pipeline ist.
Mampf F. schrieb:> Das ist bei Altera BlockRAMs so - es hat ein nicht deaktivierbares> Ausgangsregister. (Immerhin kann man Eingangs-Register deaktivieren).
Andersrum (zumindest bei meinen Cyclone III M9Ks).
Man kann das Ausgangs-"Q"-Register deaktivieren. Das Eingangs
"Address"-Register nicht (genauso das data- und wren-Register).
Quartus kann aber ein Address-Register, das man sowieso schon
hingeschrieben hat, in das M9K "reinschieben", so daß keine weitere
Latenz dazukommt.
Wenn ich das richtig verstehe, hat der TO an "beiden Enden" Register
dran, ist also zumindest für einen Takt Latenz selbst verantwortlich.
Markus F. schrieb:> Mampf F. schrieb:>> Das ist bei Altera BlockRAMs so - es hat ein nicht deaktivierbares>> Ausgangsregister. (Immerhin kann man Eingangs-Register deaktivieren).>> Andersrum (zumindest bei meinen Cyclone III M9Ks).>> Man kann das Ausgangs-"Q"-Register deaktivieren. Das Eingangs> "Address"-Register nicht (genauso das data- und wren-Register).> Quartus kann aber ein Address-Register, das man sowieso schon> hingeschrieben hat, in das M9K "reinschieben", so daß keine weitere> Latenz dazukommt.
Jau richtig, sorry! Gerade nochmal im Quartus nachgeschaut - du hast
recht!