Hallo,
ich versuche gerade, ein XC9572XL-VQ64 als Treiber für ein dummes
320x240er LCD einzusetzen. Das CPLD ist dabei wie ein SRAM mit
integriertem Adress-Latch als XMEM an einen ATMega8515 angebunden. Auf
der anderen Seite ist das eigentliche SRAM angeschlossen sowie das
Display.
Ich habe ob der begrenzten Ressourcen des Chips keine Wunder erwartet,
aber in Prinzip funktioniert es schon weit besser als befürchtet. Das
verwendete Speicherlayout orientiert sich lose an der Implentierung aus
Grafikfähiger LCD Controller für 320x240 LCD mit 8 Graustufen, weil
es erstens praktisch für AVRs mit XMEM ist und zweitens ohne viel
Rechnerei Platz für 3 Bit pro Pixel bietet. Im Gegensatz zum dort
beschriebenen Controller hat bei dieser Variante allerdings der µC alle
Rechenzeit der Welt zum Erstellen des Bildes und das halbe IC-Grab
entfällt.
Dass das verwendete Display mies ist und es Dinger mit Controller
nachgeschmissen gibt, ist bekannt. Doch der Weg ist das Ziel und dieses
Teil hat hohen emotionalen Wert, weil sein zufälliges
mir-in-die-Hände-Fallen letztlich der Auslöser war, dass ich mich
überhaupt wieder mit Elektronik beschäftige. Insofern bitte ich, auf
Empfehlungen in Richtung anderes Display verwenden zu verzichten :)
Sehr gerne lese ich jedoch jeden Tipp zum Code; das ist das erste, was
ich nach LEDs leuchten/blinken/von Taster steuern lassen in einer
Hardwarebeschreibung mache und vermute daher viele Anfängerfehler.
Aber genug zum Projekt, jetzt zum Problem. Genauer habe ich genau zwei
(sichtbare) Probleme:
Erstens bleibt die FSM manchmal regelrecht stehen. Ob und wann das
passiert, scheint vom CPLD-Takt, µC-Takt und vor allem von der Mondphase
abzuhängen. Manchmal läuft es mit 16 MHz am CPLD eine Weile stabil,
manchmal ist schon bei 8 MHz nach <1 Sekunde Ende. Symptome: Display
bleibt stehen, alle vom Prozess main abhängigen Ausgänge stehen still.
Dieses Verhalten konnte ich bis auf in etwa das hier reduziert
beobachten:
Entscheidend ist die mit !!! markierte Zeile. Ohne dieses wait ist alles
gut. Mit friert der Prozess nach eigenem Gutdünkein ein. Das kann kurz
nach dem Start oder nach einer halben Minute passieren, meistens
innerhalb der ersten zehn Sekunden.
Dabei macht es keinen Unterschied, ob die FSM mit wait until oder mit if
rising_edge(clk) und case formuliert ist. d_flm ist dabei ein Beispiel
als Debug-Ausgang, andere Pins verhalten sich genauso. Kombinatorisches
funktioniert dabei unbeeindruckt weiter, andere Prozesse auch.
Einzige Voraussetzung ist, dass der Bus c_da auch an den µC
angeschlossen ist. Also vermutete ich zunächst Contention an dieser
Stelle. Kann ich jedoch ausschließen. Selbst wenn das XMEM-Interface
deaktiviert und PORTA als Eingang konfiguriert ist, führt ein Wackeln an
c_oe zum Hänger.
Daraufhin habe ich mit zusätzlichen Kondensatoren experimentiert, ohne
Erfolg. Nun habe ich die bidirektionalen Busse c_da und m_d mit jeweils
1k gegen GND terminiert und seitdem läuft es erheblich stabiler, wenn
auch noch nicht zuverlässig. Immerhin gehen jetzt 12 MHz so
einigermaßen. Bei 16 wäre aber erst das Flimmern bei den Grautönen weg.
Das zweite Problem waren Schreibfehler, also dass bevorzugt beim
Schreiben von 0x00 oder 0xff ins SRAM stattdessen das Kompliment davon
geschrieben wird, was sich in entsprechenden Bildfehlern und beim
Zurücklesen der Werte äußert. Bei Lesezugriffen kommt es zu keinerlei
Fehlern. Dieses Problem wird auch mit niedrigerem Takt nicht besser. Und
selbst, wenn ich den Schreibzyklus um ein Vielfaches verlängere, kommt
das Problem vor. Auch hier haben die Pulldowns jedoch sehr geholfen.
Der Aufbau ist wie im Bild zu sehen eine Katastrophe für die
Signalqualität. Mein Oszi ist leider ein paar Jahrzehnte zu alt, um
sowas auch nur annähernd originalgetreu abzubilden. Also die Frage: kann
ich davon ausgehen, dass beide Probleme alleine dem Steckbrettaufbau und
damit verbundenem EMV-Ärger geschuldet ist? Oder ist das CPLD-Design zu
grottig? Oder gar der Chip kaputt? Fürchte die Platine würde einen
Austauch nicht überleben, also bevor ich das versuche oder ein zweites
Exemplar baue wüsst ich gerne, ob das überhaupt wahrscheinlich genug
ist.
Probleme mit dem µC-seitigen Timing der Speicherzugriffe würde ich
eigentlich ausschließen. Außer dass der derzeit nur mit 1 MHz läuft und
mit maximalen Wait States auf das XMEM zugreift, habe ich auch mit
manueller Ansteuerung der Ports und Pausen im ms-Bereich experimentiert,
ohne dass sich an den beiden Problemen etwas geändert hätte.
Das Aufbaufoto eben zur Einschätzung, ob es am Ende nur daran liegt. Das
CPLD ist auf der Unterseite der zentralen Platine, auf dem rechten
Steckbrett der AVR, auf dem linken der Speicher und ein Tiny2313 als
reiner Taktgeber. Die wunderschöne Skizze zum schnellen Überblick. Der
Code mit Bitte um Einschätzung, ob es doch da hakt.
Lautet das Urteil, dass nur die vielen bunten Strippen schuld sind,
würde ich mal ein Layout dazu machen, sonst muss ich wohl erst nochmal
abwägen.
Danke!
@ Malte S. (maltest)
>Erstens bleibt die FSM manchmal regelrecht stehen. Ob und wann das>passiert, scheint vom CPLD-Takt, µC-Takt und vor allem von der Mondphase>abzuhängen. Manchmal läuft es mit 16 MHz am CPLD eine Weile stabil,>manchmal ist schon bei 8 MHz nach <1 Sekunde Ende. Symptome:
Klingt nach nicht synchronisierten Eingangssignalen.
>begin> c_da <= (others => '0') when c_we = '1' and c_oe = '0' else (others >=> 'Z');
Das it OK.
> process begin> wait until rising_edge(clk); -- !!!> wait until rising_edge(clk);> d_flm <= '1';> wait until rising_edge(clk);> d_flm <= '0';> end process;>end;
AHHH! Das NICHT! Was soll denn das? Das ist KEINE BEschreibung
synthetisierbarer Hardware.
>Der Aufbau ist wie im Bild zu sehen eine Katastrophe für die>Signalqualität.
Ich würde in so eine Steckbrettkatastrophe keine Sekunde investieren!
Das lachen sich ja Wackelkontakte krank vor Lachen!
>ich davon ausgehen, dass beide Probleme alleine dem Steckbrettaufbau und>damit verbundenem EMV-Ärger geschuldet ist?
Nein. Siehe oben. Kriegen der AVR und dein CPLD den GLEICHEN Takt? Oder
verschiedene?
> Oder ist das CPLD-Design zu>grottig?
Woher sollen wird das wissen, ohne den Quellcode zu sehen?
>Oder gar der Chip kaputt?
Wahrscheinlich eher nicht.
>manueller Ansteuerung der Ports und Pausen im ms-Bereich experimentiert,>ohne dass sich an den beiden Problemen etwas geändert hätte.
Klingt nach Wackelkontakten oder asynchronen Eingangssignalen.
>Lautet das Urteil, dass nur die vielen bunten Strippen schuld sind,>würde ich mal ein Layout dazu machen,
Tu das.
> AHHH! Das NICHT! Was soll denn das? Das ist KEINE BEschreibung> synthetisierbarerHardware.
Es "geht" evtl. schon, aber es ist, naja, äusserst ungewöhnlich...
Siehe http://www.lothar-miller.de/s9y/archives/47-wait-im-Prozess.html> stattdessen das Kompliment davon
Du meinst sicher das Kompl-E-ment...
Falk Brunner schrieb:> Klingt nach nicht synchronisierten Eingangssignalen.
Was mit den vorhandenen FFs schwierig werden könnte. Hatte allerdings
gehofft, mit der jetzigen Lösung davon eher verschont zu bleiben.
Falk Brunner schrieb:> AHHH! Das NICHT! Was soll denn das? Das ist KEINE BEschreibung> synthetisierbarer Hardware.
Ließ sich aber so synthetisieren? Ergibt eine FSM mit anonymen States,
die der Reihe nach durchlaufen werden.
Hatte das als funktional äquivalent zu dem hier verstanden und beides
führt auch zum gleichen Ausgangssignal:
1
process(clk)
2
begin
3
ifrising_edge(clk)then
4
casestateis
5
when"00"=>
6
state<="01";
7
when"01"=>
8
state<="10";
9
d_flm<='1';
10
when"10"=>
11
state<="00";
12
d_flm<='0';
13
endif;
14
endprocess;
Falk Brunner schrieb:> Nein. Siehe oben. Kriegen der AVR und dein CPLD den GLEICHEN Takt? Oder> verschiedene?
Nein, die kriegen einen anderen.
...check...gleicher ist nicht, dann ist der µC zu schnell. Bei halbem,
aber vom CPLD-Takt abgeleiteten Takt das gleiche Ergebnis.
Falk Brunner schrieb:> Woher sollen wird das wissen, ohne den Quellcode zu sehen?
Der war angehängt.
Ach ja, das Eintakten der Signale war meine erste Sorge, v.a. in
Hinblick auf die geringe Menge an FFs. Ich meinte, das wäre insofern im
gelben Bereich:
writing und c_d werden synchron gesetzt. c_oe ist asynchron und mag auch
'0' werden, bevor die Daten in c_d liegen, aber spätestens bei der
steigenden Flanke von c_oe liegen die sauber in c_d (aufgrund der Wait
States, deren Konfiguration aber auch keinen Unterschied macht).
1
m_a<=c_ah&c_al;
c_ah und c_al sind asynchron, aber gemäß XMEM-Timing war die Adresse
hier bereits gültig, falls im nächsten (CPLD)-Takt c_we '0' ist, also
dort geschrieben wird. Solange der µC-Takt <= CPLD-Takt/2 ist.
1
ifc_we='0'then
2
writing<=true;
3
c_d<=c_da;
4
endif;
c_da ist bei c_we = '0' gültig. Auch noch ein langes Momentchen nach der
steigenden Flanke von c_we.
Das zu den (von mir identifizierten) kritischen Stellen. Soll weder
heißen, dass ich keine übersehen habe, noch will ich ausschließen, dass
das trotzdem zu unsauber ist.
Allerdings sehe ich wie gesagt höchstens Schwierigkeiten bei zu hohem
µC-Takt (c_oe oder vor allem c_we low, weniger als ein CPLD-Takt nach
der Fallenden Flanke an c_ale). Und das war Gegenstand der Tests mit
händisch extrem langsam gehaltenem Timing und etlichen Takten
dazwischen.
Hab ich das doch zu früh ausgeschlossen?
Malte S. schrieb:> Hab ich das doch zu früh ausgeschlossen?
Ja. Hast du.
Denn hier ist z.B. c_al asynchron:
1
iffalling_edge(c_ale)then
2
c_al<=c_da;
3
:
4
:
5
waituntilrising_edge(clk);
6
-- setup address for client request
7
m_a<=c_ah&c_al;
Insgesamt ist das Design in höchstem Maße asynchron und somit
zufallsabhängig. Du hast also quer durch das ganze Design mit dem Effekt
der unterschiedlichen Laufzeiten zu kämpfen:
http://www.lothar-miller.de/s9y/archives/64-State-Machine-mit-asynchronem-Eingang.html
Probier mal, dein CPLD und den uC aus der selben Taktquelle zu bedienen
(z.B. uC über Vorteiler im CPLD, oder CPLD am CLKout des uC, oder beide
am selben Oszillator). Dann kommt das extreme Zufallsverhalten ein wenig
aus dem Konzept raus, und das gesamte Ding wird von vorne weg stabiler.
Malte S. schrieb:> alle vom Prozess main abhängigen Ausgänge stehen still.
Naja, hier blitzt ein wenig die Softwaredenkweise durch. Das CPLD "tut"
trotzdem was. Nur läuft da eben eine Statemachine Amok und es passt
nichts mehr zusamen.
@ Malte S. (maltest)
>> AHHH! Das NICHT! Was soll denn das? Das ist KEINE BEschreibung>> synthetisierbarer Hardware.>Ließ sich aber so synthetisieren? Ergibt eine FSM mit anonymen States,>die der Reihe nach durchlaufen werden.
Ja, aber das Ergebni ist nicht notwednigerweise das, was man erwartet.
Sowas bringt nur Ärger. Mach es "normal". Und nutze symbolische Namen
für deine States, damit ist das Ganze deutlich lesbarer. Die Kodierung
ist aufgabe des Compilers, kann man dort einstellen, beim CPLD natürlich
binär und nicht one hot oder so.
>...check...gleicher ist nicht, dann ist der µC zu schnell. Bei halbem,>aber vom CPLD-Takt abgeleiteten Takt das gleiche Ergebnis.
Die Pahsenlage der XMEM Signale ist nicht definiert, wenn gleich
irgendwie konstant. Muss man mal mit dem Oszi anschauen.
"Note that the XMEM interface is asynchronous and that the waveforms in
the following figures are related to the internal system clock. The skew
between the internal and external clock (XTAL1) is not guaranteed
(varies between devices, temperature, and supply voltage). Consequently
the XMEM interface is not suited for synchronous operation."
>> Woher sollen wird das wissen, ohne den Quellcode zu sehen?>Der war angehängt.
Oh, Entschuldigung, hab ich übersehen. War schon spät 8-0
Lothar Miller schrieb:> Insgesamt ist das Design in höchstem Maße asynchron und somit> zufallsabhängig.
Ja, habe jetz einige Varianten mit dem Handling von Adresse und Daten
durch. Teils mit Funktionseinbußen, weil es nicht mehr gereicht hat, den
kompletten Framebuffer zu adressieren. Trotzdem immer noch diese Fehler
bei Schreibzugriffen.
> Probier mal, dein CPLD und den uC aus der selben Taktquelle zu bedienen> (z.B. uC über Vorteiler im CPLD, oder CPLD am CLKout des uC, oder beide> am selben Oszillator). Dann kommt das extreme Zufallsverhalten ein wenig> aus dem Konzept raus, und das gesamte Ding wird von vorne weg stabiler
µC über Vorteiler durch 2 oder 4 im CPLD tut es genauso schlecht wie mit
internem RC-Osczillator. Der olle 8515 hat kein CLKout, also so herum
kein Test drin, und: beide am selben externen Takt passt nicht, da der
µC schon etwas gemächlicher sein muss.
Falk Brunner schrieb:> Die Pahsenlage der XMEM Signale ist nicht definiert, wenn gleich> irgendwie konstant. Muss man mal mit dem Oszi anschauen.
Daher sind die Versuche mit dem gemeinsamen Takt wohl auch eher
unsicher. Ganz klar ist mir vieles noch nicht, werde so oder so noch
einiges an Theorie durcharbeiten. Oszi hilft bestimmt, aber nicht meins
:) (Dieser Typ:
http://www.radiomuseum.org/r/grundig_oszillograph_219.html und die 3 MHz
"Breit"bandeinstellung mag nicht mehr).
> Mach es "normal". Und nutze symbolische Namen> für deine States, damit ist das Ganze deutlich lesbarer. Die Kodierung> ist aufgabe des Compilers, kann man dort einstellen, beim CPLD natürlich> binär und nicht one hot oder so.
Hab's jetzt umgeschrieben. Das Encoding war auf Auto und Xst hat
treffsicher One-Hot verwendet. Nachdem ich das korrigiert habe, sind
nicht nur eine Macrocell und ein paar Register mehr frei - was ich noch
nachvollziehen kann - sondern vor allem sind sämtliche "Hänger" in der
State Machine erledigt - was ich nicht nachvollziehen kann. Zumindest
dieses Problem ist verschwunden, auch bei 20 MHz stabil (nur da spielt
das Display nicht mehr mit).
Habe allerdings vorhin mit Schrecken gesehen, dass das CPLD bei 3.3V
doch nur min. 2.4V Voh hat. Das ist bei 2.4V Vih für das 5V-SRAM
vielleicht doch etwas dünn...
Lothar Miller schrieb:>> alle vom Prozess main abhängigen Ausgänge stehen still.> Naja, hier blitzt ein wenig die Softwaredenkweise durch. Das CPLD "tut"> trotzdem was. Nur läuft da eben eine Statemachine Amok und es passt> nichts mehr zusamen.
Und ich hab' noch krampfhaft versucht, mir zu sagen "Das ist kein
Programm, das ist kein Programm..." :) Daher war schon klar, dass nicht
einfach alles hängt, nur umso weniger, wie es dazu kommt, dass mit dem
Prozess gar nichts mehr los war.
So oder so, das Wochenende ist anders ausgebucht, werde wohl mindestens
einen Schritt zurück machen, das Ganze bei Gelegenheit nochmal auf ner
Platine aufbauen und sehen, was es bringt. Und wenn das nicht hiflt,
wohl akzeptieren, dass das Device zwar ausreicht, alle Signale irgendwie
zusammenzustückeln, aber nicht mit vernünftigem Timing.
Meine Erfahrungen zu diesem Thema:
1. ein 9572 ist für sowas ziemlich eng, da klemmt es ganz schnell an den
FF für die Zähler und für interne Puffer. Für ein QVGA Display würde ich
dir zum 95144 raten, wenn der dir nicht zu teuer ist. Ich benutze so
einen für TFT's bis zu 480x272x16 Bit Farben und er reicht dafür gut
aus.
2. du mußt dich schon zu einer von 2 Strategien durchringen:
Erste Strategie: Der uC trampelt der Videologik mit Springerstiefeln in
den Laden: mit dem Beginn von ALE wird der RAM brutal auf uC
umgeschaltet und mit der L-H Flanke von RD oder WR wird wieder
zurückgeschaltet. Entweder läuft die Videologik dabei im Hintergrund
weiter und liefert bloß Mist an das LCD, oder sie wird schlichtweg
angehalten. Was von beiden funktioniert, hängt vom LCD ab.
Zweite Strategie: Pro Pixeltakt gibt es 2 Zugriffe: einer für die
Displaylogik und der andere für den uC. Letzterer bleibt quasi blind,
wenn der uC nicht tatsächlich zugreift. Wenn der uC aber zugreifen will,
muß er das langsamer tun als die Displaylogik: Der uC Zugriff muß dazu
mindestens so lang sein wie ein ganzer Pixeltakt, wahrscheinlich noch
etwas länger, denn beim Lesen braucht es seitens des uC ja ne gewisse
Mindestzeit für das Anstehen der Daten. Eine Synchronisier-Logik muß nun
zusehen, beim Lesezugriff die gelesenen Daten solange vorzuhalten, wie
der uC noch zugreift.
W.S.
@ Malte S. (maltest)
>µC über Vorteiler durch 2 oder 4 im CPLD tut es genauso schlecht wie mit>internem RC-Osczillator.
Weil der Fehler woanders liegt. Dennoch ein Schritt in die richtige
Richtung, denn wenn man in der Konstellation mal die Signale sauber
synchronisiert hat, können sie nicht durch asynchrone Takte anderen
Unsinn erzeugen.
> Der olle 8515 hat kein CLKout,
Ist auch egal, eben weil es keine definierten Phasenlagen gibt.
>Hab's jetzt umgeschrieben. Das Encoding war auf Auto und Xst hat>treffsicher One-Hot verwendet. Nachdem ich das korrigiert habe, sind>nicht nur eine Macrocell und ein paar Register mehr frei - was ich noch>nachvollziehen kann - sondern vor allem sind sämtliche "Hänger" in der>State Machine erledigt - was ich nicht nachvollziehen kann. Zumindest>dieses Problem ist verschwunden, auch bei 20 MHz stabil (nur da spielt>das Display nicht mehr mit).
D.h. es läuft jetzt wie es soll? Stabil?
>Habe allerdings vorhin mit Schrecken gesehen, dass das CPLD bei 3.3V>doch nur min. 2.4V Voh hat. Das ist bei 2.4V Vih für das 5V-SRAM>vielleicht doch etwas dünn...
Die 2.4V VOH sind die offiziellen Zahlen, die unter allen Umständen
garantiert werden und "zufällig" mit den Definitionen für TTL
übereinstimmen. Real ziehen die Ausgänge bis wenige Dutzend mV nach VCC,
wenn keine riesigen Lasten dranhängen.
W.S. schrieb:> 1. ein 9572 ist für sowas ziemlich eng, da klemmt es ganz schnell an den> FF für die Zähler und für interne Puffer. Für ein QVGA Display würde ich> dir zum 95144 raten, wenn der dir nicht zu teuer ist. Ich benutze so> einen für TFT's bis zu 480x272x16 Bit Farben und er reicht dafür gut> aus.
Klingt gut. Finde es grundsätzlich schön, auch mit dem kleineren
überhaupt ein Bild zu kriegen, aber wenn mehr Luft ist für
Synchronisierung, ist das ja auch nicht verkehrt. Zumal dann auch noch
Extras wie Double Buffering durch zusätzliche Adressleitung drin sein
sollten. Preislich ist nicht so das Kriterium, es geht ja nicht um
Stückzahlen. http://www.ebay.de/itm/320890780165 würde schon passen.
> Zweite Strategie: Pro Pixeltakt gibt es 2 Zugriffe: einer für die> Displaylogik und der andere für den uC. Letzterer bleibt quasi blind,> wenn der uC nicht tatsächlich zugreift. Wenn der uC aber zugreifen will,> muß er das langsamer tun als die Displaylogik: Der uC Zugriff muß dazu> mindestens so lang sein wie ein ganzer Pixeltakt, wahrscheinlich noch> etwas länger, denn beim Lesen braucht es seitens des uC ja ne gewisse> Mindestzeit für das Anstehen der Daten. Eine Synchronisier-Logik muß nun> zusehen, beim Lesezugriff die gelesenen Daten solange vorzuhalten, wie> der uC noch zugreift.
Das entspricht in etwa meinem Ansatz. Der ist ein wenig schludrig, da
auch ohne /OE vom µC der Speicher an dann evtl. ungültiger Adresse
proaktiv gelesen wird. Geliefert wird dann bei /OE. Hier hätte ich noch
eher mit Ärger gerechnet als beim Schreiben, aber das Lesen ist völlig
stabil. Auch die falsch geschriebenen Bytes werden beim Lesen konsequent
in dieser Fälsche an den µC zurückgegeben.
Der µC muss natürlich langsam genug laufen, dann passt das soweit.
Theoretisch. Wäre es in der Praxis problemlos, gäbe es diesen Thread
nicht :)
Falk Brunner schrieb:> D.h. es läuft jetzt wie es soll? Stabil?
Was den für das Display ungesunden Teil - Treiber bleibt stehen -
betrifft, ja. Die State Machine läuft.
> Real ziehen die Ausgänge bis wenige Dutzend mV nach VCC,> wenn keine riesigen Lasten dranhängen.
Hatte ich auch so erwartet und mich daher vorher nur vergewissert, dass
es Luft zwischen Vih des SRAM und VCC des CPLD gibt. Dieser Fehler ist
leider immernoch drin, mit stark schwankender Häufigkeit. Beim Testen
von Grafikprimitiven ist das kaum zu sehen. Bei memset() auf den
gesamten Framebuffer ist fast immer irgendwo was daneben.
Das relativiert natürlich die Aussage, dass es stabil läuft, aber es
gibt immerhin "nur noch" eine Baustelle. Werde weiter versuchen, das
einzugrenzen.
Malte S. schrieb:> Daher war schon klar, dass nicht> einfach alles hängt, nur umso weniger, wie es dazu kommt, dass mit dem> Prozess gar nichts mehr los war.
Ich hatte letztens auch fremden Code unter den Fingern, wo irgendwie die
Empfangs-FSM einer RS232 hängen blieb. Ich hab für jeden State eine
Debug-LED leuchten lassen, um zu schauen, in welchem State es klemmt.
Man konnte schnell sehen, das nach mehr oder minder kurzer Zeit one-hot
zu cold wurde.
Die FSM stand, da kein State mehr aktiv war. Nachdem das einzige
Eingangssignal dieser FSM (rx) einsynchronisiert wurde, lief alles wie
am Schnürchen...
Duke