Generování VGA signálu s Arduino Uno
Způsobů, jak si u Arduina poradit s VGA je hned několik. Mezi ty nejjednodušší patří využití některého z mnoha VGA shieldů, které obsahují svůj vlastní procesor a jsou vybaveny VGA konektorem. Dalším způsobem je vytváření videosignálu přímo v rámci Arduina. V takovém případě toho už ale na svém Arduino mnoho dalšího nerozběhnete, protože většina výkonnostní kapacity procesoru padne právě na generování signálu. A nyní konečně přichází na scénu třetí způsob, který je dílem Damiana Pecketta. Připravte se na bastlení se širokým záběrem!
Obsah článku:
VGA bez dalšího hardware
Damian pro svůj Arduino projekt nechtěl využít žádný VGA shield a na procesoru Arduina potřeboval rozběhnout relativně náročné aplikace, takže musel přijít s nějakým jiným řešením. Ale abychom pochopili, s čím se Damian potýkal, musíme se nejprve seznámit s protokolem VGA. VGA většinou označuje kromě vlastního protokolu také rozlišení 640×480 pixelů. Kromě tohoto rozlišení ale protokol VGA podporuje i další a to jak menší, tak větší.
Zobrazení jedné řádky
Skutečné rozlišení je vždy větší než viditelná část(v případě 640×480 je to 800×525). Máme tedy 525 řádků na jeden snímek. To znamená, že s obnovovací frekvencí VGA 60Hz je to 31500 řádek za sekundu. Každá řádka se navíc skládá z 800 pixelů (25MHz) a její časový průběh vypadá následovně.
Nejdříve je vidět levý okraj, který se nezobrazuje. Poté přichází na řadu vlastní video signál (25,4 μs). Poté přichází pravý okraj. S malým zpožděním je pak sníženo napětí horizontální synchronizace a po 3,8 μs je opět zvýšeno, čímž je započata nová řádka.Zobrazení snímku
Vertikální synchronizace je oproti tomu mnohem jednodušší. V tomto případě máme opět okrajové části a mezi nimi indikujeme, že jsou vysílány video signály. Na konci je pomocí vertikální synchronizace započat další snímek.
Řešení Daminana Pecketta
Nyní se tedy můžeme dostat k vlastní problematice implementace VGA protokolu na Arduino.
Z diagramu horizontální synchronizace je patrné, že na vykreslení jedné řádky máme 25,4 μs. S AVR, které běží na 16MHz to představuje 400 cyklů na řádku. Pokud bychom tedy chtěli zobrazit 40 znaků na řádce, zbylo by nám 10 cyklů na znak. Změna na pinu zabere 2 cykly a pokud navíc chceme, aby se znaky měnil a bylo možné ho natáhnout z paměti, vychází nám, že jsme schopni vykreslit znak s pouhými 2 horizontálními pixely.
Tento problém vyřešil Damian využitím posuvného registru s paralelním vstupem a sériovým výstupem, který na Arduino slouží k ovládání SPI portu. Tímto způsobem se dostaneme na 5 horizontálních pixelů na znak.
Ve výsledku po připočítání nějakého toho zpoždění dostaneme 4 horizontální pixely na znak. To je celkem klasické rozlišení pro fonty, ale nesmíme zapomenout, že musíme přidat mezery mezi jednotlivé znaky, takže nakonec skončíme s rozlišením znaku 3px. To by mohl být problém. Lze vůbec s tak málo pixely vytvořit čitelný font. Damianovi se ale podařilo najít font z roku 1983 „Tiny Alice“, který má rozlišení znaku 3x5px.
Pak přichází otázka: kam uložit buffer snímků? Jediným možnou odpovědí je SRAM, vzhledem k tomu, že EEPROM je příliš pomalá. SRAM paměť na použitém Arduinu má pouze 512 B a pokud chcete používat přerušení, funkce a podobné, musíte si nechat nějaký prostor navíc. S přihlédnutím na rozlišení displeje a další veličiny autoru vyšlo nejlepší rozlišení displeje 32×15 znaků.
Nakonec přichází nejtěžší otázka. Jak vyřešit problém s CPU? Prvotním cílem přece bylo nezatížit procesor přespříliš. Damian proto využil čip Atmega16u2, který na Arduino slouží jako převodník mezi sériovou linkou a USB, který k tomuto účelu přeprogramoval.
Článek byl zpracován na základě návodu od Daminana Pecketta http://damian.pecke.tt/vga-on-the-arduino-with-no-external-parts. Na stejném místě naleznete více informací a také zdrojové kódy.