Бих искал да споделя собствения си опит при извеждането на изображение на монитор чрез VGA интерфейса. Разбирам, че тази задача е решавана многократно, от различни хора и на различно оборудване. Но има още много какво да се каже.
На етажерката събира прах подобна на показаната по-долу платка за отстраняване на грешки, на която няма нищо друго освен FPGA и SDRAM (разбира се, без да броим бутоните, светодиодите и т.н.).
Налагаше се да направя проект за извеждане на изображение на монитор от платка, която няма подобен интерфейс и се налага да избирам между HDMI, DVI и VGA. Имах идея за проект, в който трябваше да извеждам изображение на монитор; бих казал, че неразделна част от проекта е извеждането на монитора. Тъй като на платката няма интерфейс, трябваше да избирам между HDMI, DVI и VGA. Предварително ще кажа, че макар интерфейсите да са различни, те по същество осигуряват едно и също нещо: три цветни линии (червена, синя, зелена) и два сигнала за синхронизация – синхронизация по редове и синхронизация по кадри.
Преглед на вариантите
HDMI
След като прочетох за този интерфейс, се оказа, че той е сериен, което означава, че ако вземете резолюция на екрана 640×480 пиксела при кадрова честота 60Hz, изходната честота на пикселите е около 25MHz, а след серийния модул – всичките 250MHz. Освен това този интерфейс изисква TMDS модул, а аз изобщо не исках да се занимавам с него, така че на този етап разглеждането на този интерфейс бе спряно.
DVI
Този интерфейс има няколко режима. Двата основни са цифров (DVI-D) и аналогов (DVI-A). Аналоговата опция по принцип е същата като опцията VGA, затова ще бъде разгледана по-късно. В рамките на този интерфейс, както и при HDMI, има LVDS линии, които също налагат използването на сериализатор и енкодер. Затова по същите причини (мързел) ще пропусна и този интерфейс.
VGA
Вероятно най-опростеният и най-старият интерфейс (също и част от DVI-A). За да се изведе изображение, трябва да се генерират три нива на цвят (червен, син, зелен) и два синхронизиращи сигнала (прогресивен и кадър по кадър). И в този основен вариант вече могат да се получат 8 различни цвята. На изображението по-горе е показано разположението на изводите на интерфейса VGA при свързване към FPGA и предложения китайски модул с VGA. На входа на модула има три 8-битови цветови шини и два синхронизиращи сигнала (модулът има два чипа с повторители на сигнала и масив от резистори за формиране на нивото). Естествено, китайският модул е красив и удивителен, но аз тръгнах по друг път – реших да сглобя всичко сам.
Реализацията
След като прочетох няколко статии в интернет по темата за извеждане на изображението на монитора, забелязах редица основни особености:
- VGA интерфейсът има стандарт за изхода (очевидно е, но все пак). Всеки режим има своя собствена продължителност на невидимите части на полето, честота на извеждане на пикселите и полярността на синхронизиращите сигнали. Така например за разделителна способност 640×480 полярността на тактовите сигнали 60Hz и 100Hz е различна
- В много статии се набляга, че невидимите зони отдясно и отляво на работната зона трябва да бъдат ясно разделени.
Този метод е малко труден за разбиране и реализация, затова реших да използвам друго представяне:
Активната област се премества в горния ляв ъгъл, а полетата се показват отдясно и отдолу.
- Друг основен момент е, че нивото на RGB сигналите е 0,7 V при входно съпротивление 75 Ω, но това разбрах по-късно
Житейски опит № 1
Въз основа на разположението на изводите (показано по-горе) могат да се използват 8 различни цвята. Реших да използвам разделителна способност 640×480 с честота на кадрите 60Hz, като според стандарта е ясно, че общата площ е 800×525 пиксела. Алгоритъмът за извеждане е изключително опростен, с два вертикални и хоризонтални брояча. Линиите се изчертават хоризонтално линия по линия (това е добре известен факт) и докато броячите са в рамките на работната област (640×480) – изображението се извежда.
Ако по отношение на алгоритъма всичко е ясно, в стандарта се посочва и честотата на пикселите. Тя е 25,175 MHz. На този етап вече започва да се усеща болка. В много примери за проекти с PLL на Altera е било възможно да се генерира широк диапазон от честоти, но в моя случай PLL бе ограничен и не искаше да даде това, което ми трябваше. Чрез болка и страдание поставих двата PLL последователно и получих 25,185 MHz. Като цяло допустимата грешка не е много голяма – около 0,04% (на този етап си помислих, че честотата трябва да е точно както казва стандартът, иначе картината ще е плаваща или изобщо няма да се синхронизира). Но както се оказа, не бях прав…).
В крайна сметка получих заветните осем ивици:
Докато си играех, установих, че въпреки че стандартът VGA има сигнали за синхронизация, без които картината не се извежда (проверих по-късно…), а и никак не е добре картината да завършва с черна лента. Веднага се разваля синхронизацията и мониторът я счита за невидима област и я скрива, оставяйки само 7 ленти. След като прочетох по темата и зададох неудобни въпроси на различни хора, се оказа, че някои монитори се синхронизират и по един от цветовете.
Житейски опит № 2
Осемте цвята не ми бяха достатъчни и като цяло нямах достатъчно ивици на монитора. Но тъй като свързах интерфейса директно, в крайна сметка получих еднобитов цвят. След известно обмисляне реших да разширя диапазона с помощта на ШИМ. Вдигнах честотата на модула до 100,74 MHz и се опитах да формирам RGB сигнали с различни ширини на импулсите.
Мониторът се оказа по-умен от мен. Първия път той успя да се адаптира към моя ШИМ и създаде същата гладка картина като първия път, когато го пуснах без използване на ШИМ. Но след редица насилствени мерки мониторът все пак реагира само че за съжаление не получих цветен градиент. Получих накъсани ивици. На изображението се опитах да направя 4 ленти с различна широчина на импулса. Първата лента е без ШИМ, втората е с 25%, третата – с 50%, а четвъртата – със 75%. След като се поразрових в този вариант, осъзнах, че ще трябва да направя един нормален ЦАП.
Житейски опит № 3
От института знаех, че има ЦАП на резистори, и че това е най-бързият ЦАП; с недостатъка, че е необходимо резисторите да бъдат подбрани възможно най-прецизно, като резултатът зависи от тази прецизност. В моя случай точността не е важна, най-важното е да изглежда вярно. Схемата на ЦАП от типа R-2R е добре известна в интернет и изглежда по следния начин:
Взех поялник и комплект резистори 1 КΩ и 2 КΩ и се заех с работата. Направих 5-битов ЦАП. Резултатът е следният:
След като свързах няколко кабела, го стартирах:
Снимката е направена в пълен мрак. Отне ми известно време да се сетя да изгася осветлението и не осъзнах какво съм направил погрешно. Когато проверих запояването с мултицет, видях, че напрежението в ЦАП-а се променя, ако на входа приложа различна стойност. Тогава забелязах, че мониторът не е равномерно черен, а сякаш е разделен на сектори, и тогава изключих светлината. Отново започнах да задавам серии от въпроси, които ме накараха да се почувствам най-неудобно, защото разбирам темата и защо не се бях сетил за това сам, не знам. А проблемът беше в това, че съпротивлението на приемника (в монитора за всеки RGB ред) беше 75 Ω, а аз свързах ЦАП със съпротивление повече от 2 КΩ. В резултат на това генерираното напрежение в приемника не надхвърляше 123mV (в най-добрия случай), докато на мен ми бяха необходими 700mV.
Отново отворих браузъра, за да проуча въпроса – какъв ЦАП ми трябва, за може изображението да отговаря на очакваното от мен. Едни от вариантите бе същият R2R ЦАП, но с резистори с много по-малко съпротивление – от около 70-150 Ω. Вторият вариант не с паралелно свързани резистори. Ето я схемата:
Този метод се използва в много платки за дебъгване, като например платката Altera. Естествено, без да се замислям много, направих подобен ЦАП с 5 бита на цвят:
И като резултат се получи първият адекватен резултат:
На фигурата са показани 32786 нюанса (всеки цвят – син, зелен и червен – има 32 нива на яркостта).
Житейски опит № 4
Сега остава нищо работа – само да настроим механизма за извеждане на изображението от буфера на паметта. Свързах чип SDRAM памет и описах автоматизма, който го запълва с кадър с градиент, подобен на тези по-горе. Описах и автоматичната процедура, която чете кадъра от паметта и го изпраща към модула с VGA изход. Като цяло всичко проработи от първия път (е, знаете какво имам предвид – нищо не работи от първия път). Но тук трябва да се разбере, че всичко се получи без изпиляване на нервите.
Като цяло изображението си е там, то е статично, което е индикация, че се актуализира правилно в паметта, и не е плаващо, така че прочитането е адекватно. Но ако се вгледате внимателно, ще видите вълнообразни линии по границата на градиентите.
Тук трябва да се разбере, че проектът ми вече се е разраснал – добавих SDRAM контролер, няколко автомата, FIFO, обработка на бутони и мигане на светлини (като част от дебъгването), както и ChipScope. Тоест, когато описвах VGA модула отделно, нямаше нищо допълнително и границите бяха равни, но ето че се това чудо се появи – и имам нова купчина въпроси.
След дълга дискусия по темата бе изразена идеята, че е необходимо да се премахнат двата последователно свързани PLL-а. Първо, платката е китайска и е малко вероятно осцилаторът с честота 50 MHz да дава идеални стойности. Освен това самият PLL внася допълнително трептене, а като се има предвид, че има два PLL модула, ефектът на трептене става много по-забележим.
В този момент изгубих представа откъде да взема 25,175 MHz (които стандартът изисква), след като PLL-ът не може да го осигури. В отчаянието си предприех отчаяната стъпка (според мен) да настроя изходната честота на пикселите на 25 MHz (използвайки един PLL) при 640×480@60Hz. В крайна сметка всичко започна да работи, приятно и гладко. За пореден път осъзнах, че мониторът е много по-умен, отколкото си мислех!).
След това описах UART интерфейса, написах програма на QT за зареждане на изображението чрез UART на FPGA и успях да заредя първия си миньон там!) Ето го миньона:
Цветовете малко се размиха, но както се оказа по-късно, бях загубил един бит от цвета (от страната на компютъра). В резултат на това се загуби един канал, мисля, че беше зеленият. Но в крайна сметка видеото започна да изглежда много добре.
Кодът
Модулът чете 16 бита данни от FIFO, конфигуриран в режим AXI-Stream. От които долните 15 бита са RGB, а горните 16 бита се използват за синхронизиране на кадъра между модулите. Само в случай, че има загуба на данни или някаква повреда, модулът за VGA интерфейса извършва синхронизация по старшия бит. Той се вдига в края на кадъра, като се изпълнява нещо като своеобразен last.. Модулът реализира VGA формат 640×480@60 Hz по индустриален стандарт (тактова честота на пикселите 25,175 MHz). За да се адаптира към други режими, е необходимо да се определят полярността на синхронизиращите импулси и размерът на изходната област.
Всичко важно от света на технологиите, директно в пощата ти.
С абонирането приемате нашите Условия и Политика за поверителност. Може да се отпишете с един клик по всяко време.
Коментирайте статията в нашите Форуми. За да научите първи най-важното, харесайте страницата ни във Facebook, и ни последвайте в Google Новини, TikTok, Telegram и Viber или изтеглете приложението на Kaldata.com за Android, iPhone, Huawei, Google Chrome, Microsoft Edge и Opera!
































