Wie ist es möglich, VGA-Displays mit so hohen Pixeltaktfrequenzen anzusteuern?

12

Ich arbeite an einer digitalen Schaltung mit diskreten Komponenten, um ein 640x480-VGA-Display in einem 80x30-Textmodus anzusteuern.

Bei einem 640 x 480-Display beträgt der Pixeltakt 25,175 MHz, was einer Periode von etwa 40 ns entspricht. Ich verstehe nicht, wie ich so oft ein neues Pixel für das Display bereitstellen soll.

Die grundlegende Architektur für meine Schaltung ist wie folgt:

  1. Der Binärzähler für horizontale Pixel zählt bei 25,175 MHz bis 800 (640 sichtbare Pixel + 160 für Veranda, Synchronisation, Veranda). Bei 800 den vertikalen Zeilenzähler erhöhen (und bei 525 Zeilen zurücksetzen)

  2. Leiten Sie unter Verwendung der horizontalen und vertikalen Position die x, y-Koordinate des aktuellen Zeichens ab.

  3. Indizieren Sie mithilfe der x-, y-Koordinate des Zeichens in den Videospeicher, um das ASCII-Zeichen abzurufen.

  4. Verwenden Sie das ASCII-Zeichen, um im Zeichen-ROM zu indizieren und ein Bitmuster für das Zeichen zu erhalten

  5. Verwenden Sie das Parallel-Seriell-Schieberegister, um eine 8-Pixel-Zeichenzeile in einzelne Bits mit Pixeltaktfrequenz umzuwandeln

Wenn Sie der Kette folgen, lautet sie: Zähler -> RAM -> ROM -> Parallel zum seriellen Schieberegister

Unter Verwendung der schnellsten Komponenten, die ich finden kann, summieren sich die Ausbreitungsverzögerungen und die Zugriffszeit auf ungefähr 15 ns + 20 ns + 70 ns + 15 ns = 120 ns, viel mehr als die 40 ns-Periode für 25 MHz.

Bei noch höheren Auflösungen und Bildwiederholraten können Sie Pixeltakte weit über 100 MHz haben, was einer Periode von 10 ns entspricht.

Wie ist es möglich, alle 10 ns neue Pixel für das Display bereitzustellen, wenn nur die Zugriffszeit für RAM / ROM bereits deutlich darüber liegt, ohne auch nur alle anderen Signale in Ihrem System zu berücksichtigen?

Supershirobon
quelle
7
Sie verwenden dedizierten Video-RAM und takten diesen direkt in Ihr Videosignal. Sie arbeiten daran, herauszufinden, was angezeigt werden soll, lange bevor Sie es tatsächlich anzeigen.
Herd
2
Lesen Sie mehr über Maximite . Es werden lediglich die Peripheriegeräte einer MCU und einige Widerstände zum Ansteuern eines VGA-Anschlusses verwendet. Untersuchen Sie zunächst das von ihm verwendete PIC32-Peripheriegerät. Funktioniert gut. (Ich habe hier einen Maximiten.)
Jonk
"The Cheap Video Cookbook" von "Don Lancaster"
Jasen

Antworten:

17

Es gibt zwei Hauptgründe, warum Sie dies als Herausforderung empfinden.

Erstens verwenden Sie ältere und diskretere Teile (Integration in geringerem Maßstab), als dies im Zeitalter von VGA der Fall gewesen wäre.

Aber als nächstes verwenden Sie sie auf atypische Weise. Insbesondere bedeutet Ihr Ansatz nicht pipelined, dass Sie bei der Bestimmung Ihres Intervalls und damit der Rate mehrere Verzögerungen addieren müssen .

Im Gegensatz dazu versuchen synchrone digitale Designs, die versuchen, Geschwindigkeit zu erreichen, so wenig wie möglich zwischen Registern zu tun.

Während sich die Details wahrscheinlich ein wenig unterscheiden würden, würde es grob gesagt ungefähr so ​​funktionieren:

  • Sie erhöhen oder setzen die Adresse zurück, dann geht das in ein Register.
  • Sie speichern die Adresse im synchronen Speicher
  • Sie speichern den Ausgang des synchronen Speichers
  • Sie verriegeln diese in die Adresse des Synchronzeichengenerator
  • Sie speichern den Ausgang des Zeichengenerators im Ausgangsregister
  • Wenden Sie die Palettensuche an ...
  • in den synchronen DAC ...

Wenn Sie eine Aufgabe wie diese aufschlüsseln, erhalten Sie nur eine kombinatorische Verzögerung plus eine gewisse Ausbreitungsverzögerung sowie Register-Setup- und Haltezeiten, die zwischen die Uhren passen müssen.

Ein auf diese Weise erstelltes Design benötigt viele Takte, um eine Ausgabe zu erzeugen - die Latenz ist tatsächlich höher als bei einem rein kombinatorischen Design. Es erzeugt jedoch bei jedem Zyklus eines viel schnelleren Takts eine neue korrekte Ausgabe.

Und hey, es ist ein Video, es spielt keine Rolle, ob die CRT ein Dutzend Pixel hinter dem Pixelzähler zeichnet - das berücksichtigen Sie natürlich beim Timing der Synchronisationssignale, damit sie im Vergleich zu den tatsächlichen Daten korrekt sind kommt aus dem DAC.

In der Praxis funktionieren fast alle komplexen digitalen Systeme auf diese Weise, da dies eine großartige Idee ist - bis eine Pipeline-CPU auf eine Abhängigkeit von einem früheren Rechenergebnis oder einem bedingten Zweig stößt ... Dann werden die Dinge interessant, wenn sie darüber sprechen in der nächsten Vorlesung einer Klasse für digitale Systeme - aber zum Glück ist Ihre VGA-Situation viel einfacher, insbesondere wenn Sie sich noch keine Gedanken über Zerreißeffekte machen, wenn sich der Zeichenpuffer während des Zeichnens des Bildschirms ändert.

Wenn Sie dies erstellen möchten, tun Sie dies praktisch in einem FPGA. Dadurch werden Ihnen ziemlich viele synchrone Speicher aufgezwungen, wenn Sie interne Speicher verwenden, oder synchrone E / A-Register, wenn Sie externen Speicher verwenden. Wenn Sie einen Fehler machen, müssen Sie nur mit den Daumen drehen, während er neu kompiliert wird, anstatt einen langen Tag mit der Neuverdrahtung zu verbringen .

Chris Stratton
quelle
"Vor allem, wenn Sie sich noch keine Gedanken über Zerreißeffekte machen, wenn sich der Zeichenpuffer während des Zeichnens des Bildschirms ändert" - deshalb hatten die Coprozessoren seit den frühesten Tagen der Videokoprozessoren die Möglichkeit, den Hauptprozess darüber zu informieren, dass dies nicht der Fall ist Sie speichern derzeit ihren Speicher auf dem Bildschirm und wenn sie den Videopuffer ändern möchten, sollten sie dies jetzt tun.
John Dvorak
Ich denke, Sie machen das zu kompliziert. Er gab bereits an, dass er ein 8-Bit-Schieberegister verwendet, das ein Bit pro Pixeltakt ausgibt. Vermutlich ist dies ein 8-Bit-Schieberegister mit Latch. Das heißt, er muss nur einmal pro 8-Pixel-Takt ein neues Byte abrufen, also eine Rate von 3,125 MHz. Das gibt Ihnen alle 320 ns, um die Daten zum Schieberegister-Latch zu bringen, was viel länger ist als die 120 ns, die er angekündigt hat.
Chris_F
Für einen sehr einfachen monochromen Fall mit niedriger Auflösung wäre das Timing der Bytes zwar nicht allzu schwierig, aber ein wesentlicher Teil der Frage war, dass der Fragesteller zu verstehen versuchte, wie die Leistung typischer "realer" Systeme mit nicht trivialer Auflösung ist ist möglich. Und die Antwort ist dieselbe wie bei allen anderen nützlichen digitalen Systemen: schnellere Technologie und synchrones Pipeline-Design.
Chris Stratton
2

Unter Verwendung der schnellsten Komponenten, die ich finden kann, summieren sich die Ausbreitungsverzögerungen und die Zugriffszeit auf ungefähr 15 ns + 20 ns + 70 ns + 15 ns = 120 ns, viel mehr als die 40 ns-Periode für 25 MHz.

Sie vergessen, dass ein Grafikadapter niemals nur ein einzelnes Pixel zeichnen würde - sondern zumindest eine vollständige Scanlinie. Dies wäre also ein vollständig pipelinisierbares Problem.

Vergessen Sie auch nicht, dass es bisher fünf Jahrzehnte Videoproduktionshardware gibt. Ihr Problem wird normalerweise mit einem speziellen RAM-Typ gelöst, in den Sie Ihre Buchstaben an einem Port rendern und der nacheinander in einen Videosignal-DAC ausgelesen wird. Diese Hardware ist viel, viel schneller als das, was Sie sich ansehen.

Die grundlegende Architektur für meine Schaltung ist wie folgt:

  1. Der Binärzähler für horizontale Pixel zählt bei 25,175 MHz bis 800 (640 sichtbare Pixel + 160 für Veranda, Synchronisation, Veranda). Bei 800 den vertikalen Zeilenzähler erhöhen (und bei 525 Zeilen zurücksetzen)

  2. Leiten Sie unter Verwendung der horizontalen und vertikalen Position die x, y-Koordinate des aktuellen Zeichens ab.

Nein, warum würdest du das tun? Sie würden Ihr Zeilenpixel einfach in einen zusammenhängenden Speicherbereich einfügen und linear an Ihren DAC ausgeben. Wenn es sich um eine CPU / MCU-Implementierung handelt, würden Sie dies nicht einmal Ihrer CPU überlassen, sondern einer programmierten DMA-Einheit nichts anderes zu tun, als einen Wert nach dem anderen zu nehmen und ihn beispielsweise an einen parallelen Datenport ohne CPU-Kerninteraktion auszugeben.

  1. Indizieren Sie mithilfe der x-, y-Koordinate des Zeichens in den Videospeicher, um das ASCII-Zeichen abzurufen.

Ah, Sie möchten im laufenden Betrieb rendern - gute Wahl, aber ungewöhnlich bei modernen RAM-Kosten. Stattdessen würden Sie das Zeichen einfach vorher in einen Frame-Puffer rendern oder, wenn Ihr Gerät extrem schlank ist, die Zeichenzeile direkt an den DAC weiterleiten (siehe meine DMA-Erklärung oben).

Marcus Müller
quelle
1
Während moderne Sachen vorgerenderte Framebuffer bevorzugen, sind sie offensichtlich eine schlechte Wahl, wenn Sie versuchen, ohne viel RAM zu arbeiten. Wenn Sie dies in einem FPGA tun, können Sie die DMA-Zustandsmaschine einfach dazu bringen, Adressen aus der Zeichenzellenzuordnung zu übernehmen und dann aus den entsprechenden Zeichenzeichen zu lesen.
R .. GitHub STOP HELPING ICE
stimme hier voll und ganz zu! daher mein Antwortabschnitt zur dritten Frage.
Marcus Müller
2

Ganz abgesehen vom Pipelining (was genau das ist, was Sie tun sollten), fehlt Ihnen etwas Wichtiges ...

Das Parallel-In- und Serial-Out-Schieberegister taktet zwar mit ungeraden 25 MHz, aber wenn Ihre Zeichen beispielsweise 8 Pixel breit sind, liegt der Eingang bei nur ~ 3,2 MHz, was für die LS-Serie der VGA-Ära dennoch leicht zu erreichen ist Sie müssen das nächste Byte bereit haben, wenn das Schieberegister mit dem aktuellen beendet ist (hier kommt die Pipeline ins Spiel).

Erzeugen Sie einen Pixeltakt mit ~ 25 MHz und einen Speichertakt mit 1/8 davon, um den Textpuffer und das CG-ROM anzusteuern, und leiten Sie dann das Speicher- und CG-ROM-Zugriffsmaterial weiter.

Ein weiterer Trick: Die Textpufferausgabe wird für jede Zeile innerhalb einer bestimmten Textzeile wiederholt. Sie können also die 80 Byte Text in einen Ringpuffer takten und dann den RAM für die nächsten 7 Zeilen nicht mehr lesen (unter der Annahme einer 8) Zeilenzeichen), damit Sie den Speicher für die CPU freigeben können, wobei 80 Byte RAM an der Seite des Objekts erforderlich sind.

Dan Mills
quelle
1

Das funktioniert also offensichtlich nicht. Du brauchst eine Pipeline.

1) Speichern Sie die Zeichen zusammenhängend im Speicher. Beginnen Sie oben links.

2) Rufen Sie während des Austastintervalls ein Zeichen ab. Rufen Sie weiterhin Zeichen in der Speicherreihenfolge ab.

3) Pipeline jedes decodierte Zeichen plus Zeilenindex in das ROM.

4) Pipeline der ROM-Ausgabe in einen Puffer.

5) Den Puffer in ein Schieberegister leiten. Lesen Sie die Pixel kontinuierlich in Intervallen von 40 ns aus.

(Das bedeutet, dass Sie alle 320 ns ein neues Zeichen in das Schieberegister laden müssen, was möglicherweise sogar möglich ist, ohne den gesamten Rest des Systems zu pipelinen.)

6) Kehren Sie während der horizontalen Austastung entweder zum Zeilenanfang zurück oder fahren Sie mit dem nächsten Zeichen fort (dh dem Beginn der nächsten Zeile).

Bonusfunktion: Da Sie nur alle 320 ns ein Zeichen benötigen, können Sie auch ein Zeichen + Farbpaar lesen und entweder MSDOS- oder Spectrum-Farbzeichen verwenden.

pjc50
quelle