Данная статья продолжение серии топиков Элемент задержки на VHDL, Элемент задержки на VHDL. Другой взгляд о элементах задержки на VHDL реализованных в ПЛИС.
Акцент будет сделан на конкретный прикладной пример, который любой желающий может запустить в симуляторе или реальном железе. Пример создан для удобной симуляции в среде Xilinx ISE с использованием Modelsim SE и с минимальными изменениями реализован в полноценное IP Core.
Постановка задачи
Осуществить сдвиг фазы импульсного сигнала на заданную величину (длительность импульса произвольна), возможно не синхронного с частотой работы логики ядра. Сделать это без перезагрузки или выключения модуля/устройства.
Инструменты
ДИП свич 8 позиций, на котором выставляется код задержки в двоичном коде (величина сдвига). Hard или Soft Reset — начальных сброс, установка параметров по умолчанию. Опорная частота 100 MHz, т.е 10 ns минимальное время смещения.
Реализация
Импульсом буду называть логическую единицу — 1.
Паузой, логический ноль — 0.
Код реализован в виде машины состояний, которая на мой взгляд благодаря пошаговой структуре и возможности дать внятное имя каждому этапу, весьма проста и понятна.
Помимо комментариев к коду, прилагается файл симуляции testbench.
Диаграмма конечного автомата:
Основная логика. Код отслеживает изменение уровня сигнала, далее запускается счетчик, когда его значение становится равным выставленному сдвигу, на выход подается тот же уровень, что и отслеживается и так по кругу.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity freq_shift_half_cycle is
Port (
Bus2IP_Clk : in STD_LOGIC; -- частота работы логики
Bus2IP_Reset : in STD_LOGIC; -- сброс
Clk_in : in STD_LOGIC; -- входной сигнал
Shift_reg : in STD_LOGIC_VECTOR (7 downto 0); -- знчение задержки в тактах Bus2IP_Clk
counter_reg_test : out STD_LOGIC_VECTOR (7 downto 0); -- тестовый счетчик
Clk_out : out STD_LOGIC -- выходной сигнал
);
end freq_shift_half_cycle;
architecture Behavioral of freq_shift_half_cycle is
type state_type is (set_level, wait_high_low, wait_low_high); -- описание машины состояний
signal current_stage : state_type;
signal counter_shift : STD_LOGIC_VECTOR (7 downto 0); -- внутренний счетчик
begin
shift_fsm : process (Bus2IP_Reset, Bus2IP_Clk, Clk_in, Shift_reg)
begin
if Shift_reg = x"00" or Bus2IP_Reset = '1' then -- если задержка нулевая или подан reset
Clk_out <= Clk_in;
counter_shift <= x"01";
counter_reg_test <= x"01"; -- тестовый счетчик
current_stage <= set_level;
elsif (Bus2IP_Clk'event and Bus2IP_Clk = '1') then
case current_stage is
when set_level =>
if counter_shift = Shift_reg then -- после выставленной задержки, подаём на выход 0 или 1
if Clk_in = '1' then
Clk_out <= '1';
current_stage <= wait_high_low;
else
Clk_out <= '0';
current_stage <= wait_low_high;
end if;
counter_shift <= x"01";
counter_reg_test <= x"01"; -- тестовый счетчик
elsif counter_shift < Shift_reg then
counter_shift <= counter_shift + 1;
counter_reg_test <= counter_shift + 1; -- тестовый счетчик
current_stage <= set_level;
end if;
when wait_high_low => -- ждем переключения 1 на 0 и возвращаемся в set_level
if Clk_in = '1' then
current_stage <= wait_high_low;
else
current_stage <= set_level;
end if;
when wait_low_high => -- ждем переключения 0 на 1 и возвращаемся в set_level
if Clk_in = '0' then
current_stage <= wait_low_high;
else
current_stage <= set_level;
end if;
when others =>
current_stage <= set_level;
end case;
end if;
end process shift_fsm;
end Behavioral;
Код симуляции для Modelsim:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY testbench_half_cycle IS
END testbench_half_cycle;
ARCHITECTURE behavior OF testbench_half_cycle IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT freq_shift_half_cycle
PORT(
Bus2IP_Clk : IN std_logic;
Bus2IP_Reset : IN std_logic;
Clk_in : IN std_logic;
Shift_reg : IN std_logic_vector(7 downto 0);
counter_reg_test : OUT std_logic_vector(7 downto 0);
Clk_out : OUT std_logic
);
END COMPONENT;
--Inputs
signal Bus2IP_Clk : std_logic := '0';
signal Bus2IP_Reset : std_logic := '0';
signal Clk_in : std_logic := '0';
signal Shift_reg : std_logic_vector(7 downto 0) := (others => '0');
--Outputs
signal counter_reg_test : std_logic_vector(7 downto 0);
signal Clk_out : std_logic;
-- Clock period definitions
constant Bus2IP_Clk_period : time := 10 ns;
constant Clk_in_period : time := 100 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: freq_shift_half_cycle PORT MAP (
Bus2IP_Clk => Bus2IP_Clk,
Bus2IP_Reset => Bus2IP_Reset,
Clk_in => Clk_in,
Shift_reg => Shift_reg,
counter_reg_test => counter_reg_test,
Clk_out => Clk_out
);
-- Clock process definitions
Bus2IP_Clk_process :process
begin
Bus2IP_Clk <= '1';
wait for Bus2IP_Clk_period/2;
Bus2IP_Clk <= '0';
wait for Bus2IP_Clk_period/2;
end process;
Clk_in_process :process
begin
Clk_in <= '1';
wait for Clk_in_period/2;
Clk_in <= '0';
wait for Clk_in_period/2;
-- wait for 1000 ns;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
Bus2IP_Reset <= '1';
wait for 500 ns;
Bus2IP_Reset <= '0';
wait for 5000 ns;
Shift_reg <= x"01"; -- выставляется задержка
wait for 5000 ns;
Shift_reg <= x"00";
wait for 5000 ns;
Shift_reg <= x"04";
wait for Bus2IP_Clk_period*10;
-- insert stimulus here
wait;
end process;
END;
Опытный электронщик мог заметить недостатки данного кода, а именно. Выставленная задержка не должна превышать:
— длительности импульса, если длительность импульса меньше длительности паузы;
— длительности паузы, если длительность паузы меньше длительности импульса.
Т.е. величина фазового сдвига не должна превышать 180° как для 0 так и для 1 в случае импульсного сигнала.
На схеме ниже вы можете видеть, как осуществляется сдвиг фазы входного сигнала на 40 ns в реальном так сказать времени, с задержкой в работе логики:
Далее идет демонстрация ситуации если подстраиваемый сигнал и опорная частота асинхронны:
Предлагаю вам, проанализировать данную ситуацию и сделать собственные выводы.
Буду рад вашим комментариям и замечаниям, с помощью которых в следующей статье, этот код будет дополнен новыми функциональными возможностями.
Спасибо за внимание.
Автор: lazifo