[Из песочницы] Сдвиг фазы сигнала на 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 в реальном так сказать времени, с задержкой в работе логики:

db23dcfe7740400084097616b2ff79c7.png

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

656ded56122643e3965acad942a64301.png

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

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

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

© Geektimes