Im Rahmen meiner Beschäftigung mit Mikrocontrollern zeigte sich, dass diese Chips auch in der Lage sind, ein VGA-Signal zu erzeugen. Aufgrund ihrer Flexibilität bieten sich dabei vielfältige Möglichkeiten – sogar die Einblendung eines Hintergrundbildes oder eine Textdarstellung sind möglich.
In diesem Abschnitt soll jedoch einfach die Nachbildung des VGA-Moduls in Software mittels eines Atmel AVR ATMega88 erfolgen. Zum Thema AVR sind sehr gute Tutorials im Netz verfügbar, so dass ich hier nur eine kurze Übersicht gebe.
Die AVR-Mikrocontroller bieten digitale (teilweise sogar analoge) Aus- und Eingänge, die per Software programmiert werden können. Typische Computerfunktionen wie Timer und Interrupts stehen dabei zur Verfügung. Mithilfe des T1-Timers des ATMega88 gelingt es nun, das VGA-Signal und sämtliche Steuersignale Q1-Q8 (gemäß Video-Modul des EE3023) und sogar noch ein paar zusätzliche Signale zu erzeugen.
Ein paar Grundlagen zum VGA-Signal
Der ATMega88 wird mit 20 MHz getaktet, jeder Befehl dauert also mindestens 50 Nanosekunden. Das klingt wenig, aber für eine ganze VGA-Bildzeile stehen dann gerade einmal 508 Takzyklen zur Verfügung. Das ist bereits zu wenig, um die vollen 640 Pixel einer VGA-Zeile getrennt ansteuern zu können. Für die Signale Q1-Q8 des Videomoduls (mit jeweils maximal achtfacher Frequenz gegenüber den Synchronsignalen) sollte es hingegen reichen, wenn man clever programmiert. Das linke Bild zeigt denn auch eine einwandfreie Farbtreppe, wie sie letztlich erreicht wurde. Das rechte stammt aus einem frühen Versuchsstadium; der Hintergrund für die verbogenen Balken ist eine zeitliche Überforderung des Mikrocontrollers – pro Zeile stand nicht genug Zeit für alle nötigen Operationen zur Verfügung.
Das VGA-Signal ist exakt spezifiziert; allerdings sind moderne Monitore sehr tolerant gegenüber Fehlern, so dass auch noch stärkere Abweichungen von der Spezifikation zu einem sichtbaren Bild führen (können – oder auch nicht: siehe Nachtrag unten).
Das Bild zeigt die einzelnen Signale und ihre jeweilige Dauer. Man erkennt, dass die Synchronimpulse etwa ein Viertel der gesamten Datenmenge ausmachen. Sie bestehen aus dem eigentlichen (negativen) Synchronimpuls und den vorderen und hinteren Schwarzschultern (Front und Back Porch), während derer das Bild einfach dunkel ist und keine Information übertragen werden darf.
Wie bereits erwähnt, stehen dem AVR keine 640 Takte (bzw. 800 Takte inklusive der Synchrondaten) zur Verfügung, die Taktangaben verkürzen sich daher auf 508 sichtbare Takte, und 12, 76 und 38 Takte für HFP, HS und HBP.
Mittels eines Timers kann der horizontale Synchronimpuls sehr genau erzeugt werden. Auf dieselbe Weise können auch die Signale Q1-Q4 (62,5 KHz, 125 kHz, 250 kHz) und die linke und rechte „Wand“ erzeugt werden. Problematisch sind die vertikalen Elemente einschließlich des Bildimpulses, da sie ebenfalls während des Timers eingestellt werden müssen und zusätzliche Zeit benötigen. Im Programm wurden daher horizontale und vertikale Schaltbefehle verzahnt. Außerdem wurde auf Abfragen der Portzustände komplett verzichtet; es werden gleichzeitig immer alle aktivierten Ausgänge eines Ports gesetzt. Deshalb liegen alle vertikalen Ausgänge auf Port C und die horizontalen auf Port D. Einzige Ausnahme ist das vertikale Synchronsignal, das allein auf Port B0 liegt. Damit lässt sich ein sehr sauberes VGA-Signal erzeugen – deutlich sauberer als das der VGA-Module auf CMOS-Technik. Da zudem der Mikrocontroller-Aufbau auch noch Platz und Bauteile spart, empfehle ich diesen für einen Nachbau.
Das hier gezeigte VGA-Modul enthält neben dem eigentlichen VGA-Teil auch den Sinus-Rechteckgenerator, das Oszilloskop und eine Schaltung zur Darstellung von vier Wandelementen.
Das Oszilloskop hat gegenüber dem Original eine Verbesserung erhalten. Es wird nun statt durch Transistoren durch zwei Operationsverstärker gesteuert. Einer von ihnen ist wie beim Sprite-Modul verantwortlich für die lineare Aussteuerung der grünen senkrechten Linie, der andere ist ein 2:1-Verstärker und erzeugt die notwendige Empfindlichkeit der Schaltung.
Quelltext zum Download: VGA-Module
Nachtrag: Es zeigte sich bei Tests, dass das vom ATMega88 erzeugte Signal genügt, den hier gezeigten Multisync-Monitor zu synchronisieren. Der an anderer Stelle verbaute kleine TFT-Bildschirm zeigte sich jedoch zickiger – offenbar sind kleine Unregelmäßigkeiten beim Synchronsignal die Ursache. Diese Unregelmäßigkeiten stammen von der Erzeugung der vertikalen Bildsignale – ein Problem, das sich leider nicht mehr softwareseitig lösen ließ. Interessanterweise synchronisierte der kleine Monitor ohne Probleme auf das VGA-Modul in CMOS-Technik – dort sind zwar die Sync-Signale nicht vollständig VGA-konform; dafür ist deren Abfolge innerhalb eines Bildes durch die harte Taktung mittels CMOS-Zähler offenbar exakter.
Daher wurde als Lösung die Erzeugung der vertikalen Signale (mit Ausnahme der Synchronimpulse) in einen zweiten AVR vom Typ ATTiny26 verlagert. Dieser wird mit dem eingebauten Oszillator bei 8MHz betrieben und kommt so mit einem Minimum an externer Beschaltung aus. Er wird extern durch den horizontalen Synchronimpuls getriggert und durch den vertikalen Synchronimpuls mit dem Bild synchronisiert und erzeugt nun die zusätzlichen Bildsignale, ohne den Hauptprozessor zu belasten. Damit lässt sich auch auf dem kleinen TFT-Bildschirm ein perfekt stehendes Bild erzeugen.
Es ist nicht auszuschließen, dass auch andere Monitore dieses Problem aufweisen. Andere Lösungsmöglichkeiten liegen in der Verwendung anderer, leistungsstärkerer Mikrocontroller und möglicherweise auch in der Programmierung in Assembler statt in C – beides hatte für mich zu wenig Attraktivität und wurde deshalb nicht weiter verfolgt.
Download VGA-Horizontalsteuerung (ATMega88)
Hallo,
Gefällt mir, aber eine Ergänzung um Schaltplan und Source-Code wäre super.
Johannes
Der Schaltplan ist noch in Arbeit, ein paar Tage wird es aber noch dauern. Den Code habe ich im Source bereits zur Verfügung gestellt.