Сдвиг фазы сигнала на VHDL

от автора

Данная статья продолжение серии топиков Элемент задержки на VHDL, Элемент задержки на VHDL. Другой взгляд о элементах задержки на VHDL реализованных в ПЛИС.

Акцент будет сделан на конкретный прикладной пример, который любой желающий может запустить в симуляторе или реальном железе. Пример создан для удобной симуляции в среде Xilinx ISE с использованием Modelsim SE и с минимальными изменениями реализован в полноценное IP Core.

Постановка задачи

Осуществить сдвиг фазы импульсного сигнала на заданную величину (длительность импульса произвольна), возможно не синхронного с частотой работы логики ядра. Сделать это без перезагрузки или выключения модуля/устройства.

Инструменты

ДИП свич 8 позиций, на котором выставляется код задержки в двоичном коде (величина сдвига). Hard или Soft Reset — начальных сброс, установка параметров по умолчанию. Опорная частота 100 MHz, т.е 10 ns минимальное время смещения.

Реализация

Импульсом буду называть логическую единицу — 1.
Паузой, логический ноль — 0.

Код реализован в виде машины состояний, которая на мой взгляд благодаря пошаговой структуре и возможности дать внятное имя каждому этапу, весьма проста и понятна.

Помимо комментариев к коду, прилагается файл симуляции testbench.

Диаграмма конечного автомата:

image

Основная логика. Код отслеживает изменение уровня сигнала, далее запускается счетчик, когда его значение становится равным выставленному сдвигу, на выход подается тот же уровень, что и отслеживается и так по кругу.

freq_shift_half_cycle.vhd

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:

testbench_half_cycle.vhd

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 в реальном так сказать времени, с задержкой в работе логики:

Далее идет демонстрация ситуации если подстраиваемый сигнал и опорная частота асинхронны:

Предлагаю вам, проанализировать данную ситуацию и сделать собственные выводы.

Буду рад вашим комментариям и замечаниям, с помощью которых в следующей статье, этот код будет дополнен новыми функциональными возможностями.

Спасибо за внимание.

ссылка на оригинал статьи http://geektimes.ru/post/266218/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *