Реализация работы происходит на базе отладочной платы фирмы TerasicDE0-CV. DE0-CV это официальная отладочная плата, распространяемая Alter’ой, ее цена составляет 150$, а по академической 99$. На самой плате имеем:
‒ шесть семисегментных индикаторов, 10 светодиодов, 10 переключателей, 4 кнопки
‒ VGA разъем, PS/2 разъем, слот под micro SD карту
‒ SDRAM память объемом 64Мбайта
‒ два GPIO разъема на 35 выводов каждый.
Сам камень, установленный на плату, имеет следующие характеристики Cyclone V 5CEBA4F23C7N Device:
‒ 49K логических вентилей
‒ 3080 Kbits встроенной памяти
‒ 4 PLLs
‒ 1 физический контролер памяти
Работа VGA-блока.
Плата DE0 снабжена VGA выходом, в качестве ЦАП для выходов RGB используется простая схема на резисторах.
Интерфейс модуля выглядит следующим образом:
modulevga (
inputwire pixel_clock,
outputreg hsync,
outputreg vsync,
outputreg [11:0] rgb
Для начала работы с VGA нам нужно заглянуть в спецификацию VESA(http://tinyvga.com/vga-timing) и выбрать нужный режим работы. Соответственно посмотреть частоту необходимую и тайминги. Выберем видеорежим 1440x900 60Hz. Необходимая тактовая частота для этого режима 106,5Мгц.
На плате установлен кварц на 50МГц, с помощью специального блока PLL мы можем производить преобразование 50МГц в нужные нам 106,5. Для этого нам необходимо вытащить нужный блок на рабочую область и произвести его настройку.
Из документации берем необходимые значения таймингов:
Для более гибкой настройки модуля для работы с разными разрешениями экрана, константы отвечающие за значения таймингов вынесены отдельно и выполнены в параметрическом варианте:
parameter h_front_porch = 80;
parameter h_sync = 152;
parameter h_back_porch = 232;
parameter h_active_pixels = 1440;
parameter v_front_porch = 3;
parameter v_sync = 6;
parameter v_back_porch = 25;
parameterv_active_scanilines = 900;
При каждом положительном фронте поступившем на вход pixel_clock, увеличиваем на единицу счетчик pixel_count и в зависимости от его значения выставляется нужный логический уровень на выход горизонтальной синхронизации hsync,.
wire w_hsync = (pixel_count < h_sync);
always @(posedge pixel_clock)
begin
hsync <= (pixel_count < h_sync);
hvisible <= (pixel_count >= (h_sync+h_back_porch)) && (pixel_count < (h_sync+h_back_porch+h_active_pixels));
if(pixel_count < (h_sync+h_back_porch+h_active_pixels+h_front_porch) ) begin
pixel_count <= pixel_count + 1'b1;
char_count <= pixel_count;
end
else
begin
pixel_count <= 0;
end
end
Когда счетчик pixel_count доходит до конца строки, происходит увеличение счетчика строк line_count и соответственно в зависимости от заданных ранее параметров выставляются нужные значения на выход вертикальной синхронизации vsync.
wirew_hsync_buf = w_hsync&~hsync;
always @(posedge pixel_clock)
begin
if(w_hsync_buf)begin
vsync <= (line_count < v_sync);
vvisible <= (line_count >= (v_sync+v_back_porch)) && (line_count < (v_sync+v_back_porch+v_active_scanilines));
if(line_count < (v_sync+v_back_porch+v_active_scanilines+v_front_porch) )begin
line_count <= line_count + 1'b1;
line_count_out <= line_count;
end
else
begin
line_state <= 0;
line_count <= 0;
end
end
end
Когда pixel_count и line_count попадают в диапазон, принадлежащий видимой части экрана как по горизонтали, так и по вертикали, то visible выставляется в высокий уровень, тем самым разрешая блоку game начинать отрисовку экрана:
always @( hvisible or vvisible)
begin
visible = hvisible & vvisible;
end
В случае если visible принимает истинное значение, то выходному регистру rgb производится присвоение необходимого значения, что и отображается на мониторе.
Заключение
Реализуя проект, мы увидели, что с помощью FPGA достаточно просто можно реализовывать сложные интерфейсы такие как VGA, с очень высокими требованиями к таймингам которые трудно выдержать используя МК.
Статистика по занимаемым ресурсам в FPGA:
Литература:
- Журавлев М. Видеоадаптеры и видеомониторы EGA, VGA и SuperVGA: Справочное пособие. // Звезда и С. М. 1992 г. стр. 140
- Harris D. Digital design and computer architecture. // Elsevier, 2013 page 682