VHDL: Как я могу задержать сигналы VGA?
Я использую Basys3 FPGA и у меня есть генератор тестовых шаблонов, который отображает набор изображений на мониторе. Проблема в том, что каждое изображение "сбито", что означает, что первый пиксель в каждой горизонтальной строке - это пиксель из предыдущей строки. Например, если бы у меня был черно-белый экран с верхней половиной белого и нижней половиной черного, первый пиксель в первой черной линии был бы белым. По сути, похоже, что весь первый вертикальный столбец смещен вниз на один пиксель.
Из того, что мне сказал мой профессор, проблема вызвана тем фактом, что сигналы (h_sync, v_sync, RGB) не синхронизированы, h_sync и v_sync опережают на 1 бит из-за задержки сигналов RGB, когда Я делаю выбор изображений. Под выбором я подразумеваю, что у меня есть 4 активных переключателя, которые (в зависимости от их состояния ВКЛ / ВЫКЛ) выбирают изображения "двоичным способом". (пример: 4 переключателя находятся в состоянии 0101, затем отображается 5-е изображение. Состояние 0011, отображается 3-е изображение и т. д.)
Это код для выбора:
type Colors is array (0 to 15) of STD_LOGIC_VECTOR (7 downto 0);
signal redArr : Colors;
signal greenArr : Colors;
signal blueArr : Colors;
process (CLK)
begin
if (CLK'EVENT and CLK = '1') then
if flagAV = '1' then
RED <= redArr (conv_integer (SW));
GREEN <= greenArr (conv_integer (SW));
BLUE <= blueArr (conv_integer (SW));
else
RED <= "00000000";
GREEN <= "00000000";
BLUE <= "00000000";
end if;
LED <= SW;
end if;
end process;
Массив (Colors) имеет 16 элементов, потому что у меня 16 изображений, таким образом, для отображения всех из них достаточно 4 переключателей (SW). Я использовал 8 бит на цвет. flagAV
это просто проверить, являюсь ли я активным регионом или нет.
У меня есть отдельный модуль (VGADraw) для этого выбора изображений, и еще один (VGADrive), где я определяю синхронизацию H/V, пустые сигналы H/V. Затем счетчики встраиваются в модуль выбора изображений с помощью сигналов холостого / высокого напряжения от VGADrive.
Синхронизация H/V и пустые сигналы, определенные в VGADrive:
HorizontalSync: process (CLK)
begin
if (CLK'EVENT and CLK = '1') then
if (inCntHor = RES.cstHorFP + RES.cstHorAL - 1) then
inHS <= '0';
elsif (inCntHor = RES.cstHorFP + RES.cstHorAL + RES.cstHorPW - 1) then
inHS <= '1';
end if;
end if;
end process;
HorizontalBlanking: process (CLK)
begin
if (CLK'EVENT and CLK = '1') then
if (inCntHor = RES.cstHorAL - 1) then
inHBL <= '1';
elsif (inCntHor = RES.cstHorTotSize - 1) then
inHBL <= '0';
end if;
end if;
end process;
VerticalSync: process (CLK)
begin
if (CLK'EVENT and CLK = '1') then
if (inCntVer = RES.cstVerFP + RES.cstVerAL - 1) then
inVS <= '0';
elsif (inCntVer < RES.cstVerFP + RES.cstVerAL + RES.cstVerPW - 1) then
inVS <= '1';
end if;
end if;
end process;
VerticalBlanking: process (CLK)
begin
if (CLK'EVENT and CLK = '1') then
if (inCntVer = RES.cstVerAL - 1) then
inVBL <= '1';
elsif (inCntVer = RES.cstVerTotSize - 1) then
inVBL <= '0';
end if;
end if;
end process;
Счетчики встроены в модуль выбора изображений (VGADraw) с использованием сигналов гашения:
VerticalCounter: process (CLK)
begin
if (CLK'EVENT and CLK = '1') then
HBLold <= HBL;
if HBL = '0' and HBLold = '1' then
if VBL = '1' then
incntVer <= 0;
else
incntVer <= incntVer + 1;
end if;
end if;
end if;
end process;
HorizontalCounter: process (CLK)
begin
if (CLK'EVENT and CLK = '1') then
if HBL = '1' then
incntHor <= 0;
else
incntHor <= incntHor + 1;
end if;
end if;
end process;
cstHorAL - пиксели / активные линии
cstHorFP - пиксели / переднее крыльцо
cstHorPW - пиксели / ширина импульса
cstHorBP - пиксели / заднее крыльцо
cstHorTotSize - пиксели / общее количество строк
cstVerAL - линии / активные линии
cstVerFP - линии / переднее крыльцо
cstVerPW - ширина линии / импульса
cstVerBP - линии / задний подъезд
cstVerTotSize - строки / общее количество кадров
HBLold - используется для обнаружения падения края
Мой вопрос: как мне задержать сигналы h_sync и v_sync на этот 1 бит, чтобы изображения отображались правильно без смещения этих первых пикселей, и в каком модуле мне это делать?
1 ответ
Поскольку вы сказали, что реализовали задержку одного цикла, попробуйте больше задержек цикла, таких как:
process(CLK) is
begin
if rising_edge(CLK) then
a_q <= a;
a_q_q <= a_q;
a_q_q_q <= a_q_q;
-- etc
end if;
end process;
Если вы хотите более чистый код, вы можете использовать цикл FOR для задержки любого сигнала столько раз, сколько вы хотите, например
-- In Architecture
constant num_cycles : INTEGER := 3;
signal a_v : std_logic_vector(num_cycles downto 0);
begin
a_v(0) <= a;
process(CLK) is
begin
if rising_edge(CLK) then
for i in 0 to num_cycles loop
a_v(i+1) <= a_v(i);
end loop;
end if;
end process;
end architecture;
В этом случае a может быть h_sync или v_sync. num_cycles - это количество циклов, которое вы хотите отложить. a_v - это вектор. Чтобы использовать ваш задержанный сигнал просто используйте a_v(num_cycles)