VHDL: как использовать CLK и RESET в процессе
Я написал код VHDL для контроллера VGA для спартанской платы 3E. Код имитирует и работает хорошо без сброса и процесса clk в приведенном ниже коде. Но после вставки процесса (reset,clk) счетчики h_count и v_count перестают считать и приводятся к XXXXX, неопределенному в симуляции. Куда я иду не так? Код работает отлично без clk, процесса сброса (тот, что выделен жирным шрифтом), я также протестировал код на аппаратном обеспечении.
Код для контроллера VGA
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity vga_controller is
port(clk : inout std_logic;
clk_50 : in std_logic;
hsync, vsync : out std_logic;
video_on : out std_logic;
x_pos, y_pos : out std_logic_vector(9 downto 0);
sw : in std_logic_vector(2 downto 0) := "100";
rgb : out std_logic_vector(2 downto 0)
);
end vga_controller;
architecture Behavioral of vga_controller is
signal h_count, v_count : unsigned(9 downto 0) := (others => '0');
begin
-- Frequency divider to get 25 MHz clk from 50 MHz clock of Spartan 3E **
freq_dividr : entity work.t_ff port map(clk_50, clk);
-- If i remove this process everyting works fine. Why ????**
process(clk, reset)
begin
if reset = '1' then
h_count <= (others => '0');
v_count <= (others => '0');
video_on <= '0';
elsif clk'event and clk = '1' then
h_count <= h_count;
v_count <= v_count;
end if;
end process;
process(clk) -- Process for horizontal counter
begin
if clk'event and clk = '1' then
if h_count = 799 then
h_count <= (others => '0');
else
h_count <= h_count + 1;
end if;
end if;
end process;
process(clk) -- Process for vertical counter
begin
if clk'event and clk = '1' and h_count = 799 then
if v_count = 524 and h_count = 799 then
v_count <= (others => '0');
else
v_count <= v_count + 1;
end if;
end if;
end process;
hsync <= '0' when (h_count >= 656 and h_count <= 751) else '1';
vsync <= '0' when (v_count >= 490 and v_count <= 491) else '1';
video_on <= '1' when (h_count <= 649 and v_count <= 479) else '0';
rgb <= sw when (h_count <= 649 and v_count <= 479) else "000";
x_pos <= std_logic_vector(h_count);
y_pos <= std_logic_vector(v_count);
end Behavioral;
2 ответа
Вы должны управлять сигналом только от одного процесса. Просто поместите свою функцию сброса в счетчик процессов, и она должна работать. Например:
process(clk) -- Process for horizontal counter
begin
if(rising_edge(clk)) then
if(rst = '1') then
h_count <= 0;
else
if h_count = 799 then
h_count <= (others => '0');
else
h_count <= h_count + 1;
end if;
end if;
end if;
end process;
Несколько других заметок:
Как вы можете видеть, я использовал синхронный сброс в приведенном выше фрагменте. Если вам абсолютно не нужна асинхронная перезагрузка, используйте вместо нее синхронную перезагрузку. Это помогает синтезатору, так как есть некоторые специальные конструкции, которые недоступны при асинхронном сбросе, и помогает предотвратить проблемы, когда ваш проект становится большим (и триггеры внезапно начинают сбрасываться в разное время из-за перекоса сигнала).
Кроме того, не проверяйте ничего, кроме ребер (или сброса) в исходном операторе if синхронизированного процесса. Для вашего вертикального счетчика у вас есть проверка для h_count = 799. Вместо этого сделайте следующее:
process(clk)
begin
if(rising_edge(clk)) then
if(h_count = 799) then
(...)
Это намного понятнее и не так подвержено ошибкам.
Как последнее, я изменил clk'event and clk=1
к более современному способу сделать это, rising_edge(clk)
, Это не должно иметь большого значения (если только при определенных обстоятельствах в симуляции), но rising_edge
имеет несколько дополнительных встроенных проверок, чтобы убедиться, что у вас действительно есть преимущество.
Вы не можете иметь несколько драйверов для одного сигнала. Если у вас нет (clk, reset)
обработать hcount
а также vcount
каждый сигнал управляется только одним процессом. Но когда вы добавляете (clk, reset)
Процесс имеет параллельные драйверы.