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

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 eine Periode von etwa 40 ns hat. Ich verstehe nicht, wie ich das Display so oft mit einem neuen Pixel versorgen 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 aufwärts bis 800 (640 sichtbare Pixel + 160 für Front Porch, Sync, Back Porch). Bei 800 vertikalen Zeilenzähler inkrementieren (und bei 525 Zeilen zurücksetzen)

  2. Unter Verwendung der horizontalen und vertikalen Position die x-, y-Koordinate des aktuellen Zeichens ableiten.

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

  4. Verwenden Sie ASCII-Zeichen zum Indizieren im Zeichen-ROM, um Bitmuster für Zeichen zu erhalten

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

Folgt man der Kette, so geht das: Counter -> RAM -> ROM -> Parallel to Serial Shift Register

Bei Verwendung der schnellsten Komponenten, die ich finden kann, summieren sich die Ausbreitungsverzögerungen und die Zugriffszeit auf etwa 15 ns + 20 ns + 70 ns + 15 ns = 120 ns, viel größer als die 40 ns-Periode für 25 MHz.

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

Wie ist es möglich, dem Display alle 10 ns neue Pixel zur Verfügung zu stellen, wenn nur die Zugriffszeit für RAM / ROM bereits weit darüber liegt, nicht einmal alle anderen Signale in Ihrem System berücksichtigen?

Sie verwenden dedizierten Video-RAM und takten diesen direkt in Ihr Videosignal ein. Sie arbeiten daran, herauszufinden , was angezeigt werden soll, lange bevor Sie es tatsächlich anzeigen.
Lesen Sie etwas über Maximite . Es verwendet nur die Peripheriehardware einer MCU und ein paar Widerstände, um einen VGA-Anschluss anzusteuern. Beginnen Sie mit der Untersuchung des PIC32-Peripheriegeräts, das er verwendet. Funktioniert gut. (Ich habe hier eine Maximite.)
„Das billige Video-Kochbuch“ von „Don Lancaster“

Antworten (4)

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

Erstens verwenden Sie ältere und diskretere Teile (Integration auf niedrigerer Ebene), als dies in der Ära von VGA verwendet worden wäre.

Aber als nächstes verwenden Sie sie auf atypische Weise. Insbesondere ist Ihr Ansatz nicht, was bedeutet, dass Sie mehrere Verzögerungen pipelinedaddieren müssen , wenn Sie Ihr Intervall und damit Ihre Rate bestimmen.

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

Während die Details wahrscheinlich ein wenig abweichen 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
  • Diesen verriegeln Sie in die Adresse des Synchronzeichengenerators
  • Sie speichern die Ausgabe des Zeichengenerators im Ausgaberegister
  • Wenden Sie die Palettensuche an ...
  • in den synchronen DAC ...

Wenn Sie eine Aufgabe auf diese Weise aufschlüsseln, erhalten Sie nur eine kombinatorische Verzögerung plus eine gewisse Ausbreitungsverzögerung und registrieren Setup- und Hold-Zeiten, die zwischen die Uhren passen müssen.

Ein auf diese Weise aufgebautes Design benötigt viele Takte, um eine Ausgabe zu erzeugen - die Latenz ist tatsächlich höher als bei einem rein kombinatorischen Design. Aber es erzeugt bei jedem Zyklus einer viel schnelleren Uhr eine neue korrekte Ausgabe.

Und hey, es ist Video, es spielt keine Rolle, ob die CRT ein Dutzend Pixel hinter dem Pixelzähler zeichnet - Sie berücksichtigen das natürlich beim Timing der Sync-Signale, 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 Berechnungsergebnis oder einer bedingten Verzweigung trifft ... Dann wird es interessant, wie sie sprechen würden in der nächsten Vorlesung einer Klasse für digitale Systeme - aber zum Glück ist Ihre VGA-Situation viel einfacher, besonders wenn Sie sich noch keine Gedanken über Tearing-Effekte machen, wenn sich der Zeichenpuffer ändert, während der Bildschirm gezeichnet wird.

Wenn Sie dies bauen möchten, tun Sie dies praktischerweise in einem FPGA. Das wird Ihnen ziemlich synchrone Speicher aufzwingen, wenn Sie interne verwenden, oder synchrone IO-Register, wenn Sie externen Speicher verwenden. Sie werden viel Anstoß zu einem richtigen Design bekommen, der Stoff selbst wird schneller sein als Ihre diskreten Teile, und wenn Sie einen Fehler machen, müssen Sie natürlich nur mit den Däumchen drehen, während er neu kompiliert wird, anstatt einen langen Tag mit der Neuverkabelung zu verbringen .

"insbesondere wenn Sie sich noch keine Gedanken über Tearing-Effekte machen, wenn sich der Zeichenpuffer ändert, während der Bildschirm gezeichnet wird" - deshalb hatten die Coprozessoren seit den frühesten Tagen der Video-Coprozessoren eine Möglichkeit, den Hauptprozess darüber zu informieren, dass dies nicht der Fall ist derzeit ihren Speicher auf dem Bildschirm ausgeben und wenn sie den Videopuffer ändern möchten, sollten sie es jetzt tun.
Ich finde du verkomplizierst das zu sehr. Er hat bereits gesagt, dass er ein 8-Bit-Schieberegister verwendet, das ein Bit pro Pixeltakt ausgibt. Vermutlich ist dies ein 8-Bit-Schieberegister mit Latch. Das bedeutet, dass er nur alle 8 Pixeltakte ein neues Byte holen muss, 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, von denen er sagte, dass es dauern würde.
Für einen sehr einfachen monochromen Fall mit niedriger Auflösung wäre das Timing von Bytes nicht allzu schwierig, aber ein wichtiger Teil der Frage war, dass der Fragesteller versuchte zu verstehen, wie die Leistung typischer "echter" Systeme mit nicht trivialer Auflösung ist ist möglich. Und die Antwort ist die gleiche wie bei allen anderen nützlichen digitalen Systemen: schnellere Technologie und synchrones Design in Pipelines.

Ganz abgesehen vom Pipelining (was Sie eigentlich tun sollten), verpassen Sie etwas Wichtiges ....

Das Schieberegister mit parallelem Eingang und seriellem Ausgang taktet zwar mit ungeraden 25 MHz, aber wenn Ihre Zeichen beispielsweise 8 Pixel breit sind, liegt sein Eingang bei nur ~3,2 MHz, was für die LS-Serie der VGA-Ära leicht erreichbar ist Sie müssen das nächste Byte fertig haben, wenn das Schieberegister mit dem aktuellen fertig ist (hier kommt die Pipeline ins Spiel).

Generieren Sie einen Pixeltakt bei ~25 MHz und einen Speichertakt bei 1/8 davon, um den Textpuffer und das CG-ROM anzusteuern, und leiten Sie dann diese Speicher- und CG-ROM-Zugriffsdaten weiter.

Ein weiterer Trick: Die Ausgabe des Textpuffers wird für jede Zeile innerhalb einer beliebigen Textzeile wiederholt, also könnten Sie vielleicht die 80 Bytes Text in einen Ringpuffer takten und dann für die nächsten 7 Zeilen aufhören, den RAM zu lesen (unter der Annahme einer 8 Zeilenzeichen), so können Sie den Speicher für die Verwendung durch die CPU freigeben, auf Kosten von 80 Bytes RAM, die an der Seite des Dings hängen.

Bei Verwendung der schnellsten Komponenten, die ich finden kann, summieren sich die Ausbreitungsverzögerungen und die Zugriffszeit auf etwa 15 ns + 20 ns + 70 ns + 15 ns = 120 ns, viel größer als die 40 ns-Periode für 25 MHz.

Dabei vergisst man, dass eine Grafikkarte niemals nur einen einzelnen Pixel zeichnen würde – sondern zumindest eine ganze Scanzeile. Somit wäre dies ein vollständig Pipeline-fähiges Problem.

Vergessen Sie auch nicht, dass es bisher fünf Jahrzehnte Hardware zur Videoproduktion gegeben hat. Ihr Problem würde normalerweise mit einem speziellen RAM-Typ gelöst, in den Sie Ihre Buchstaben auf einem Port rendern und der sequentiell 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 aufwärts bis 800 (640 sichtbare Pixel + 160 für Front Porch, Sync, Back Porch). Bei 800 vertikalen Zeilenzähler inkrementieren (und bei 525 Zeilen zurücksetzen)

  2. Unter Verwendung der horizontalen und vertikalen Position die x-, y-Koordinate des aktuellen Zeichens ableiten.

Nein, warum würdest du das tun? Sie würden einfach Ihr Zeilenpixel in einen zusammenhängenden Speicherbereich legen und es 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 zu tun, als einen Wert nach dem anderen zu nehmen und ihn ohne CPU-Kern-Interaktion zB an einen parallelen Datenport auszugeben.

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

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

Während modernes Zeug dazu neigt, vorgerenderte Framebuffer zu 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 Zeichenzellenabbildung zu entnehmen und dann aus den entsprechenden Zeichenglyphen zu lesen.
stimme hier voll und ganz zu! daher mein Antwortabschnitt zur dritten Frage.

Das funktioniert also offensichtlich nicht; Sie brauchen eine Rohrleitung.

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

2) Abrufen eines Zeichens während des Austastintervalls. Fahren Sie fort, Zeichen in Speicherreihenfolge abzurufen.

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

4) Leite die ROM-Ausgabe in einen Puffer.

5) Leite den Puffer in ein Schieberegister. Pixel kontinuierlich im Abstand von 40 ns daraus auslesen.

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

6) Während der horizontalen Ausblendung entweder zum Anfang der Zeile zurückkehren oder zum nächsten Zeichen vorrücken (d. h. zum Beginn der nächsten Zeile).

Bonusfunktion: Da Sie nur alle 320 ns ein Zeichen benötigen, können Sie auch ein Zeichen-Farb-Paar lesen und entweder Farbzeichen im MSDOS-Stil oder im Spectrum-Stil erstellen.