Ich versuche schon seit Stunden, mit diesem Code das Display eines
Spartan 3E 1600 anzusprechen, doch alles was erscheint ist ein Cursor
auf dem Display. Ich verstehe nicht was ich falsch gemacht habe, ich
habe mich genau an die Anweisungen im User Guide gehalten, v.a. auch bei
den Delays. In der Simulation klappt eigentlich alles so wie ich es
will. Jetzt habe ich auch mal auf die Warnungen geschaut und da lese ich
dann folgendes:
FF/Latch <SF_D1_2> has a constant value of 0 in block <LCD>. This
FF/Latch will be trimmed during the optimization process.
WARNING:Xst:1896 - Due to other FF/Latch trimming, FF/Latch <SF_D1_3>
has a constant value of 0 in block <LCD>. This FF/Latch will be trimmed
during the optimization process.
WARNING:Xst:1293 - FF/Latch <SF_D1_2> has a constant value of 0 in block
<LCD>. This FF/Latch will be trimmed during the optimization process.
WARNING:Xst:1896 - Due to other FF/Latch trimming, FF/Latch <SF_D1_3>
has a constant value of 0 in block <LCD>. This FF/Latch will be trimmed
during the optimization process.
WARNING:Xst:1426 - The value init of the FF/Latch AKT_STATUS_FSM_FFd12
hinder the constant cleaning in the block LCD.
You should achieve better results by setting this init to 0.
Für mich heißt das also, dass für die Synthese SF_D1 auf "0000"
optimiert wird, was natürlich eine Katastrophe wäre, da so meine Daten
nicht ans Display weitergeleitet werden. Wie kann ich das umgehen?
Könnte mir da jemand helfen?
Johannes schrieb:> Für mich heißt das also, dass für die Synthese SF_D1 auf "0000"> optimiert wird, was natürlich eine Katastrophe wäre,
Nein, nur Bit 2 und 3. Und dass diese immer 0 sind kann in deinem Code
einfach sehen wenn man nach SF_D1 sucht.
Danke für deine schnelle Antwort. Einerseits bin ich froh, dass somit
das Problem des Latches gelöst ist, aber andererseits weis ich dennoch
nicht, warum das Display nicht so mag wie ich es gerne hätte. Hatte
gehofft, dass Problem würde am Latch liegen. Ich hab echt keine Ahnung
woran es liegen könnte.
Johannes schrieb:> warum das Display nicht so mag wie ich es gerne hätte.
Wie stellst du das fest?
Was sagt denn die Simulation zu deiner Displayansteuerung?
Gerade eine Displayansteuerung lässt sich toll simulieren...
Drei Sachen noch:
1
INIT_MACHINEP:process(CLK,RESET,INIT_START)--power on Initialization sequence
Naja das Display soll "Test" anzeigen, allerdings bleibt das Display bis
auf einen Cursor leer. In der Simulation geschieht eigentlich alles so
wie ich es beabsichtigt habe, bzw wie es der Userguide vorschreibt. Die
Zustände wechseln so wie ich es will, die Daten liegen richtig an, die
Befehle und auch die Zeiten stimmen. Nur wenn ich das auf das Board
bringe ist es mir unerklärlich warum nichts angezeigt wird. Hier muss
noch irgendwo ein Fehler sein, der mich zur Verzweiflung bringt.
Ok der Reset ist unnötig, den werd ich mal rausnehmen bzw als synchronen
reset definieren. Aber das Problem bleibt halt.
Ich bin jetzt noch relativ neu, daher weis ich nicht was ein chip scope
ist. Ich habe die case-Abfragen allerdings bei der Simulation überprüft,
und da funktionierten sie so wie sie sollten.
Johannes schrieb:> allerdings bleibt das Display bis auf einen Cursor leer.
Das bedeutet aber, dass die Initialisierung schon mal funktioniert. Miss
doch einfach mit dem Oszi/LA nach, ob die Ansteuersignale (an FPGA-Pin
ausgeben) für diese ausgefuchsten Multiplexer alle funktionieren. Das
sieht nämlich gehörig fehlerträchtig aus...
Johannes schrieb:> Ich bin jetzt noch relativ neu, daher weis ich nicht was ein chip scope> ist.
Chipscope gehört auch nicht in Anfängerhände. Damit gewöhnt man sich nur
schlechten Designstil an.
Chipscope (Xilinx) und SignalTap (Altera) sind interne
Logikanalysatoren.
> Ich habe die case-Abfragen allerdings bei der Simulation überprüft,> und da funktionierten sie so wie sie sollten.
Zeig uns doch mal einen Screenshot von Deiner Simulation, in welchem die
Signale, die zum Display gehen zu sehen sind.
Im Anhang ein (funktionierendes) Beispiel, wie die Signale in der
Simulation bei mir aussehen.
Duke
Gib deinem Enable-Puls mal eine anständige Dauer. Ich bin mir nicht
sicher, dass das die nötigen 450ns sind...
Mir scheint das Timing auf unterster Ebene unnötig knackig. Man nimmt
nicht die Mindestwerte aus dem Datenblatt, sondern baut da ein wenig
Reserve ein. Denn das Signal muß ja noch den Weg durch den Port und die
Leiterbahn zum Display finden.
Also habe jetzt für die Transport machine die Dauer, für die LCD_E auf
high gehalten wird, von 12 Zyklen (= 240 ns) auf 30 Zyklen (= 600 ns)
erhöht, auch die anderen Zeiten hab ich nach oben korrigiert. Das
Ergebnis ist allerdings immer noch das selbe.
Langsamer heißt: so, dass das Timing garantiert im grünen Bereich liegt.
Zykluszeit, Enablepuls,... Alles so, dass es sicher nicht an zu hoher
Geschwindigkeit liegen kann.
Ich habe den Quellcode nun meinem Prof per e-mail geschickt. Er meinte
auch, dass hier ein Timingproblem vorliegt und gab mir den Tipp, einen
Clock-Teiler einzuführen, wodurch die clock dann um den jeweils
angegebenen Faktor verzögert wird und so das ganze verlangsamt wird.
Meine Ergebnisse sind wie folgt:
1000 Display braucht sehr lange (mehrere Sekunden) dann
erscheinen
4 Doppelstriche, die so nicht im Zeichensatz enthalten
sind,
anstatt der 4 Buchstaben von Test
100,255,400 Ähnlich, nur dass erst der Inhalt des Demoprogramms
stehen
bleibt, bevor nach wenigen Sekunden die vier
Doppelstriche
erscheinen
2,5,10 Ales beim alten, Cursor steht an erster Stelle
Alles insgesamt also sehr eigenartig, va. die Ausgabe der Doppelstriche.
Johannes schrieb:> 1000 Display braucht sehr lange (mehrere Sekunden) dann> erscheinen
Aha: ingenieurmäßiges probieren, bis es vielleicht klappt, obwohl man
nicht weiß warum?!?
Hast Du nach dem Einschalten die Resetzeit abgewartet?
Du verwendest den 4-Bit-Modus. Sind die Daten richtig aufgeteilt
("aufgenibbelt") ?
Ist der 4-Bit-Modus richtig initialisiert?
Duke
Also die Initialisierung scheint noch zu klappen, da das Display die
Anzeige des Demoprogramms verwirft. Hab bei der Initialisierung die
Daten aus dem User Guide verwendet (also die 0x3 bzw zum Schluss 0x2),
ok das mit den Zeiten ist so ne Sache, aber ab einem Faktor 5 sollte das
doch ausreichen.
Beim Datentransport sende ich zuerst die höherwertigeren 4 bits, 1us
Pause, mit Clock Teiler halt dann um das jeweilige mehr, die
niederwertigeren 4 bits, 40us Pause, dann ist die Übertragung
abgeschlossen und es kann sofort mit der nächsten Übertragung begonnen
werden
Johannes schrieb:> Ich habe den Quellcode nun meinem Prof per e-mail geschickt. Er meinte> auch, dass hier ein Timingproblem vorliegt und gab mir den Tipp, einen> Clock-Teiler einzuführen
Wenn das die Sache nur nicht noch schlimmer macht...
Wie hast du diesen Taktteiler realisiert?
So hab ich es gemacht, clk2 ist der Eingangsclock:
ausbremsen: process (clk2)
variable ZAEHLER:integer range 0 to 1000:=0;
begin
if rising_edge (clk2) then
if(ZAEHLER=100 )then
CLK<='1';
ZAEHLER:=0;
else
CLK<='0';
ZAEHLER:=ZAEHLER+1;
end if;
end if;
end process ausbremsen;
Das mit dem Teiler war eh eine unsaubere Lösung, da pass ich lieber mein
Timing richtig an. Hab jetzt meine Zeiten bei der Initialisierung mit
denen von Duke verglichen und da fehlts echt weit bei mir, muss ich
nachbessern. Direkt nach der Initialisierung kommt ja der befehl für das
Setzen des Cursors und dann die Daten. Wie sind denn da deine
Zeitabstände, ich denk mal ich nehm die auch wie bei der Initialisierung
in etwa, also erst höherwertig (15 us) dann Pause (7us) dann
niederwertig (15us) und dann Pause bis zum nächsten Teil (75us). Sollte
hinhauen, muss ich jetzt nur noch meinen Code dementsprechend umbauen.
Funktioniert leider immer noch nicht, hab jetzt die Initialisierung nach
Dukes Angabe gemacht, simuliert, verhält sich genau wie gewünscht. Nur
wenn ich es dann wieder auf den Baustein bringen will kommt wieder nur
der Cursor. Nach der Initialisierung hab ich den Set_Addr Befehl
verwendet. 750 Takte LCD_E high gepulst für höherwertigeren Teil, 350
Takte warten, 750 Takte niederwertiger Teil, 4000 Takte Pause. Und
danach dann gleich mit dem ersten Buchstaben angefangen, gleiches
Vorgehen. Nur es tut sich einfach nichts, ich dreh echt gleich durch.
Aber es muss doch an der Transport_machine liegen, denn der clear
display befehl wird ja noch ausgeführt, sonst würde ja der Text des
Demoprogramms noch dastehen. Im Anhang mal der aktuelle Code.
Weis, dass das warscheinlich ned optimal ist, aber ich hab einfach im
Isim clk auf 20ns clock geforcet. Der Rest ist ja im vhdl-file
deklariert. Und dann läuft das halt so ab, eigentlich genau wie ich
will. Mit Testbench hab ich eigentlich kaum Erfahrung.
Danke, Lothar. Ist halt so, ich studiere technische Informatik und wir
hatten circa 4 Stunden vhdl Crashkurs. In den Übungen haben wir halt
mal nen Volladdierer gebaut, aber nicht mal synthetisiert. Sowas wie
Testbench haben wir da gar nicht behandelt. Jetzt soll ich als
studentische Hilfskraft eben dieses LCD zum laufen kriegen. Den Code
hinzubekommen ging eig noch, nur dieses Fehlersuchen. Werd mir das mit
den Testbenches mal anschauen und hoffe, dass ich dann endlich diesen
Fehler finde. Der Prof hat anscheinend auch keine Ahnung woran es
konkret liegt. Später soll ich mich dann auf das xynergy board stürzen.
Johannes schrieb:> wir hatten circa 4 Stunden vhdl Crashkurs.
Ja, das ist in der Tat wenig...
> Sowas wie Testbench haben wir da gar nicht behandelt.
Das ist ein sträfliches Vergehen, denn VHDL ist vom Ansatz her eine
Systembeschreibungs- und Simulationssprache. Nur ein winziger
Bruchteil von VHDL kann überhaupt synthetisiert werden.
Und dann braucht man die Hardware-Denkweise, die etwa so geht: was
erwarte ich vom Synthesizer (Zähler, Register, Vergleicher,...) und wie
muss ich das dann in VHDL hinschreiben, dass ich das auch bekomme?
Einfach ein "Programm" hinzuprogrammieren geht da nicht. Das kann
tadellos simulieren, aber in der Realität kläglich versagen....
Kennst du das Buch VHDL-Synthese von Reichardt&Schwarz?
Nein, das kenn ich leider nicht, wär aber sicher eine gute Literatur für
mich. Dennoch frage ich mich, wo Fehler im Code liegt. Ich habe mich ja
an den Ablauf und die Zeiten gehalten. Das blöde ist eben, dass man
nicht sieht was intern auf dem Ding passiert. Es funktioniert halt, oder
eben nicht.
Johannes schrieb:> Dennoch frage ich mich, wo Fehler im Code liegt.
Der Fehler ist der: du hast einfach mal angefangen. Und dich dann
verwurstelt...
Ich gebe zu, dass ich die ganzen Seitenwirkungen deiner Multiplexer, die
da zwischen Init und Betrieb hin- und herschalten auch nicht so ohne
weiteres kapiere. Und das heißt schon was...
> Ich habe mich ja an den Ablauf und die Zeiten gehalten.
Aber die Effkte der Umschalter und der Kombinatorik (Glitches,
Spikes,...) nicht beachtet. Hier z.B. wirst du garantiert solche Effekte
beobachten:
1
--multiplexer richtig schalten
2
withAKT_STATUSselect
3
SCHALT<='1'whenINIT,
4
'0'whenothers;
5
6
withSCHALTselect
7
LCD_E<=LCD_E0when'0',--zum übertragen
8
LCD_E1whenothers;--zum Initialisieren
9
10
--gibt Aufschluss darüber, ob Daten oder Befehle übertragen werden
Denn die Umschaltung zwischen den Zuständen geschieht nicht in 0.0ns,
sondern es dauert dank Laufzeiten und Kombinatorik eine kurze Zeit, und
solange ist AKT_STATUS volatil und unbestimmt. Und damit sind deine
Ansteuersignale, die ja direkt an AKT-STATUS hängen, nicht besser
dran... :-o
> Das blöde ist, dass man nicht sieht was intern auf dem Ding passiert.
Dafür gibt es den Simulator. Und das Ergebnis der Simulation ist so gut,
wie die Modelle der beteiligten Komponenten (Umwelt). Natürlich kannst
du z.B. an dein Modul nur einen Takt anschließen und in der Waveform
nachsehen, was herauskommt (diese Vorgehensweise reicht für viele
Anwendungsfälle). Du kannst z.B. aber auch ein Modell deines Displays
schreiben und darfst da alle möglichen VHDL-Sprachkonstrukte verwenden,
weil das ja nicht synthetisiert werden soll. Und dort kannst du dann
Timingverletzungen leicht abfragen und melden. Und wenn du an deinem
Modul etwas änderst, musst du nicht die ganze Waveform nochmal anscheun,
sondern kontrollierst einfach, ob die Testbench Fehler ausgespuckt hat.
Aber: konzeptionelle Fehler (wie diese glitchige Muxerei) findet auch
der Simulator nicht (so ohne weiteres)!
> Es funktioniert halt, oder eben nicht.
Nein, das ist der falsche (reaktive) Ansatz: etwas "hinprogrammieren"
und hoffen, dass es geht. Nur kann man das nicht wie in der Software so
einfach "Schritt-für-Schritt" debuggen.
Mein Motto ist eher aktiv: der Synthesizer hat das, was ich wollte, aus
meiner Beschreibung gemacht oder er hat es eben nicht getan. Und wenn
das herauskommt, was ich vorhatte, dann funktioniert es.
Danke für deine Tipps. Ich seh schon, ich muss noch sehr viel lernen.
Ich werd mich jetzt mal hinhocken und mir ein neues Konzept ausdenken,
eben ohne diese Multiplexer.
So jetzt hab ichs mal ganz anders gelöst, ohne einen einzigen
Multiplexer. Ich hab mir gedacht, dass ist ja immer der selbe Ablauf,
also warten, daten senden, warten usw. Also hab ich die jeweiligen
Delays und Daten einfach in arrays gepackt, die ich dann jeweils
zuweise. Die Frage ist nur ob das so billig (50 Zeilen Code im Vergleich
zu über 600) überhaupt funktionieren kann. In der Simulation schauts gut
aus, die Initialisierung klappt auch, das Display wird gelöscht, der
Cursor erscheint. Nur der Text kommt halt nicht. Ich denke aber, dieser
Ansatz wäre va für eine allgemeine Nutzung des LCDs gut. Einfach
gewünschte Daten für Buchstaben in Ram ändern, und schon gehts. Wenn
dieser Ansatz so möglich ist, wohlgemerkt.
Johannes schrieb:> Wenn dieser Ansatz so möglich ist, wohlgemerkt.
Du hast die Links da oben im
Beitrag "Re: FF/Latch Warnung bei LCD Display" schon gesehen?
> In der Simulation schauts gut aus
Bei mir bleibt die Simulation nach dem Kommando "Home" 0x01 stehen:
1
ERROR: Index 22 out of bound 0 to 21.
2
ERROR: In process main_src.vhd:DISPLAY
Ist ja klar, denn die I1 und I2 würden ja ewig weiterlaufen. Ich würde
also an deiner Stelle doch nochmal die Simulation ansehen. Die muss
fehlerfrei laufen, vorher brauchst du nicht auf die Hardware...
> Nur der Text kommt halt nicht.
1
ifZAEHLER=DELAY(I2)then
2
LCD_E<='1';-- jetzt wird auf high geschaltet
3
ifI1>13then
4
LCD_RS<='1';-- und gleichzetig noch RS geändert
5
else
6
LCD_RS<='0';
7
endif;
Du verletzt immer noch eine Setup-Zeit: die Adress-Setup-Zeit tas.
Das Signal RS muss vor der steigenden Flanke des Enable-Impulses
stabil anliegen.
> variable I1: integer range 0 to 21:= 0;
Na toll....
Wenns dann mal läuft, dann sieh dir den
Beitrag "Variable vs Signal" an. Aber das ist
jetzt nicht das Problem...
So, ich hab jetzt mal alles angepasst,simuliert und auf Hardware
gebracht.
Vielen,vielen Dank für eure Hilfen,Lothar und Duke!!!
Jetzt tut sich im Vergleich zu vorher allerdings etwas. Es wird in jedes
Feld des Displays dieser Doppelstrich gedruckt (||), der eigentlich
nicht im Zeichensatz ist. Weder im Userguide noch bei der Suche im
Internet noch bei der Nachfrage beim Prof bin ich fündig geworden, was
es damit auf sich hat.
Ich habe mir vor ein paar Tagen einen Qellcode für einen Counter auf dem
LCD heruntergeladen. Auch dort tauchten nur diese Doppelstriche auf.
Weiß vll irgendeiner, warum diese erscheinen und wie man das beseitigen
kann.
Johannes schrieb:> Es wird in jedes Feld des Displays dieser Doppelstrich gedruckt (||),> der eigentlich nicht im Zeichensatz ist.
Dann ist es evtl. ein frei definierbares Sonderzeichen, das da
ausgegeben wird...
Oder es hängt noch irgendwas anderes mit am selben Bus...
Oder, oder...
> Ich habe mir vor ein paar Tagen einen Qellcode für einen Counter auf dem> LCD heruntergeladen. Auch dort tauchten nur diese Doppelstriche auf.
Das ist eigenartig. Du brauchst jetzt unbedingt einen Logikanalyzer oder
mindestens ein Oszi...
Johannes schrieb:> Ok, dann werd ich wohl mal die Hochschule aufsuchen, mich mit dem Prof> treffen und dann mal nachmessen was da los ist.
Ich würde als erstes mal gucken, ob sich alle Leitungen am Display
richtig verhalten. Ich hab mir in solchen Fällen ein Blinky (~1Hz)
gemacht und jedes Pin einzeln wackeln lassen.
Bei der niedrigen Frequenz kann man sogar mit dem Multimeter debuggen.
Duke
P.S.: Vielleicht hast Du auch nur die Reihenfolge der Datenleitungen
vertauscht.
So, jetzt bin ich an der Hochschule und habe das ganze mit dem Intronix
LogicPort analysiert. Zwei Dinge sind mir dabei sofort aufgefallen.
Erstens ist das Signal LCD_RS immer auf high, was aber für die
Initialisierung und die ersten Befehle falsch ist. Zweitens scheint die
Datenleitung D(3) verrücktzuspielen. Im obigen Beispiel sollen die
Befehle x"28" und x"0C" übertragen werden. Allerdings passt das Signal
D(3) ganz und gar nicht und das zieht sich durch die komplette Analyse.
Dabei wird doch das Datum als kompletter Nibble übergeben, gemeinsam mit
D (0) bis D(2) und die stimmen ja.Vielleicht handelt es sich aber auch
um einen Fehler im Analysator, was ich allerdings nicht glaube, da ich
die Messung paar mal wiederholt habe. Data0 ist übrigens ein
unverbundener Anschluss und auch dieser zeigt was an, so dass der
Laborleiter meinte, hier könnte ein Fehler liegen. Könnte das vll auch
auf D(3) zutreffen?
War ich wohl etwas vorschnell, habe das Kabel ausgetauscht und jetzt
funktioniert es. Allerdings bleibt RS immer auf 1 und was mir außerdem
noch aufgefallen ist, ist dass einmal x"3" für die Initialisierung nicht
übertragen wird, sondern nur zweimal.