Jump to content

    
Sign in to follow this  
dak

Изменение фронта сигнала по сигналу разрешения.

Recommended Posts

Здравствуйте. Что-то не могу понять, как сделать такую вещь: допустим, есть какой-то тактовый сигнал, и надо по сигналу разрешения изменить его фронт.

 

Например, сигнал разрешения в один момент времени поднимается в '1' и далее не опускается. Надо,чтобы с сразу же или с задержкой в пару тактов более быстрого клока сделать фронт исходного тактового сигнала '1' если он был '0', и оставить '1', если он и так был высоким. Хотелось бы при этом,чтобы до этого на выходе блока был '0' (чтобы в момент изменения сигнала разрешения и при изменении фронта для последующих блоков фиксировалось изменение фронта).

 

Резюме: есть 2 клока - один условно называем быстрым (порядок сотен МГц), и медленный (порядок единиц МГц). У блока есть так же вход сигнала разрешения. На выходе хочу получить периодический сигнал такой же частоты (назову этот выходной сигнал А), что и медленный клок, но с условием: в момент изменения сигнала разрешения (или через пару тактов быстрого клока) последующие блоки фиксировали изменение фронта А (используя язык VHDL - rising_edge(A) ).

 

Пробывал так:

 

process(enb,fast_clock,slow_clock)
begin
  if rising_edge(fast_clock) then
    if enb='1' then
      if slow_clock='1' then
        clock_out <= slow_clock;
      elsif slow_clock='0' then
        clk_out <= not(slow_clock);
      end if;
    else
      clk_out <= '0';
    end if;
  end if;
  end process;

 

 

Такой блок фиксирует высокий фронт, и не делает всего,что мне надо...

 

 

Мне надо 2 независимых друг от друга потока данных передавать синхронно с меткой времени.

 

Сама метка имеет такой вид: 100 нс она единичка,и 1 секунду она ноль.

 

Итак,я делаю так: по приходу первой метки,я поднимаю в единицу сигнал разрешения. По этому сигналу начинают работу некоторые блоки. Потоки данных я пишу в RAM; получая разрешение на запись временным сдвигом полученного ранее сигнала разрешения, а разрешение на чтение генерирую на основе метки времени (тут ве работает как надо). Вот пытаюсь получить клок для чтения.

Edited by dak

Share this post


Link to post
Share on other sites

А просто сделать операцию XOR сигнала разрешения с тактовым не пробовали. Тогда получите то, что хотите.

Вот только это будет уже не сигнал клока, а некий сигнал синхронность которого под вопросом...

А в целом любые игры с клоком это всегда признак плохого подхода.

По хорошему клок отдельно, дизайн отдельно.

Edited by twix

Share this post


Link to post
Share on other sites
А просто сделать операцию XOR сигнала разрешения с тактовым не пробовали. Тогда получите то, что хотите.

Вот только это будет уже не сигнал клока, а некий сигнал синхронность которого под вопросом...

А в целом любые игры с клоком это всегда признак плохого подхода.

По хорошему клок отдельно, дизайн отдельно.

Спасибо.

 

Надо выдавать данные синхронно с меткой. К RAM перешел потому,что частоты потоков не постоянны и могут меняться,никаких конкретных таймингов нет. Понимаю,что кривенько,но как еще можно сделать - не знаю.

 

 

По идее, делая операцию XOR по быстрому клоку (частота более чем в 100 раз больше частоты медленного клока) я могу довольно точно замечать перепады медленного клока.... Спасибо,попробую. Правда,как я понимаю,частота выходного сигнала может скакать в этом случае....

 

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

Edited by dak

Share this post


Link to post
Share on other sites

 

может как-то по аналогии? (Xilinx)

 

В этом описании, когда run_switch в '0' счетчик работает по переднему фронту тактовой частоты clk, но если вы измените run_switch на '1', то счетчик будет увеличиваться на единицу каждый раз, по изменению single_step. Используется примитив BUFGMUX для переключения между двумя источниками тактовых частот.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

library UNISIM;
use UNISIM.VComponents.all;

entity clock_step is
Port ( clk		 : in  STD_LOGIC;
	   run_switch  : in  STD_LOGIC;
	   single_step : in  STD_LOGIC;
	   LED		 : out  STD_LOGIC_VECTOR (7 downto 0));
end clock_step;

architecture Behavioral of clock_step is

COMPONENT debounce
PORT(
	clk : IN std_logic;
	i : IN std_logic;		  
	o : OUT std_logic
	);
END COMPONENT;

  signal run_switch_debounced		: std_logic := '0';
  signal single_step_debounced		   : std_logic := '0';

  signal counter : unsigned(7 downto 0);

  signal switched_clk : std_logic;
  signal switched_clk_unbuffered : std_logic;
  signal clk_buffered : std_logic;
begin

i_BUFG: BUFG port map (
  I => clk,
  O => clk_buffered
  );

Inst_debounce1: debounce PORT MAP(
	clk => clk_buffered,
	i => run_switch,
	o => run_switch_debounced 
);

Inst_debounce2: debounce PORT MAP(
	clk => clk_buffered,
	i => single_step,
	o => single_step_debounced
);

BUFGMUX_inst : BUFGMUX port map (
  O  => switched_clk,		   -- Clock MUX output
  I0 => clk_buffered,		   -- Clock0 input
  I1 => single_step_debounced,  -- Clock1 input
  S  => run_switch_debounced	-- Clock select input
  );

process(switched_clk)
  begin
  if rising_edge(switched_clk) then
	 counter <= counter + 1;		
  end if;
  end process;

  LED <= std_logic_vector(counter);

end Behavioral;

---------------------------------------------------
---------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity debounce is
Port ( clk : in  STD_LOGIC;
	   i : in  STD_LOGIC;
	   o : out  STD_LOGIC);
end debounce;

architecture Behavioral of debounce is
  signal debounce_counter : unsigned (20 downto 0) := (others => '0');
  signal synced		   : std_logic := '0';
  signal debounced		: std_logic := '0';

begin
process(clk)
  begin
  if rising_edge(clk) then
	 if synced = '1' then
		if debounce_counter(debounce_counter'high) = '1' then
		   debounce_counter <= (others => '1');
		   o <= '1';
		else
		   debounce_counter <= debounce_counter + 1;
		end if;
	 else
		if debounce_counter(debounce_counter'high) = '0' then
		   debounce_counter <= (others => '0');
		   o <= '0';
		else
		   debounce_counter <= debounce_counter - 1;
		end if;
	 end if;
	 synced <= i;
  end if;
  end process;

end Behavioral;

 

Можно попробовать на run_switch подать медленный клок (коректнее сформировать этот сигнал на высокой частоте)

Share this post


Link to post
Share on other sites

Я нарисовал временную диаграмму того,что я собственно хочу.

 

Mark of time - моя временна меточка;

 

enable_1 - сигнал разрешения, по которому начинают работу некоторые блоки;

 

Далее идут сигналы разрешения на чтение и запись в/из RAM;

 

Потом красненьким нарисован как раз тот сигнал,который я хочу получить.

 

Ну и последний - один (для упрощения) из двух моих потоков данных на выходе.

 

может как-то по аналогии? (Xilinx)

 

Спасибо, посмотрю.

post-90315-1458082491_thumb.jpg

Share this post


Link to post
Share on other sites
Я нарисовал временную диаграмму того,что я собственно хочу.

 

На рисунке на выходе - просто стробированный тактовый с "залипанием" сигнала его разрешения. Берущегося, исходно, в виде временнОй метки. Кроме того, фаза тактового подогнана ко времени прихода метки.

Вам надо именно это?

 

Если так - то, с учётом последнего ограничения выше, предложу, разве что, генерировать выходной тактовый в виде сигнала данных "быстрого" домена.

Share this post


Link to post
Share on other sites

В общем, поковыряв все это дело и полазив в интернете, что-то придумал. На идею натолкнул Maverick.

 

 

Сразу скажу, что в стартовом посте мой косяк: я не сказал, что клоки для RAM получаются делением некой отдельной тактовой частоты; при этом клок для первого потока получается непосредственно из деления входящего клока,а клок для второго потока получается делением клока для первого потока.

 

Погуглив, нашел такой примитив Xilinx - BUFG_CTLR. При определенной настройке этот примитив работает как клоковый мультиплексор, который по мере своей возможности мгновенно переключает клоки (проверено на железе осциллографом).

 

Итак, как это работает по шагам:

 

1) получение сигнала разрешения.

 

Использую схему определения изменения фронта сигнала из 0 в 1 (вот такую http://marsohod.org/verilog/157-verilogedges). С каждым изменением проверяю, поднят ли у меня внешний управляющий сигнал,и если поднят, то отправляю единицу:

 

process(arst,mark_imp,control)
begin
if arst='1' then
enable <= '0';
elsif rising_edge(mark_imp) then
if control <='1' then
enable <= '1';
else
enable <= '0';
end if;
end if;
end process;

 

Буду называть этот сигнал разрешения сигналом EN_1.

 

2) теперь у меня поднят сигнал разрешения по импульсу метки. К моменту приходу следующего импульса метки мне надо сделать свои дела.

 

Первый поток данных я считаю из ROM внутри ПЛИС. Клок для него я запускаю сразу, но считывать хочу начинать не сразу после поднятия сигнала разрешения, а уже ближе к подходу следующей. Для этого мне нужен счетчик, который отсчитает нужное количество времени, а потом заблокируется и перестанет считать. Здесь я и использую указанный выше примитив. На один из входов данных заводится сигнал разрешения, который я получил при приходе метки, а на второй - тот,который хочу получить, и его же использую для адресации. При сбросе этот сигнал устанавливается в 0. Счетчик, пока не отсчитает нужное количество времени, получает сигнал разрешения EN_1, а после (через инвертор) - сигнал разрешения EN_2.

 

Проверка на то,досчитал ли счетчик до нужного значения выполняется так:

 

process(clk240Mhz,arst)
begin
  if arst = '1' then
    en_2 <= '0';
elsif rising_edge(clk240MHz) then
  if unsigned(counter) = "нужное число в бинарном виде" then
    en_2 <= '1';
  else
    en_2 <= '0';
end if;
  end if;
end process;

 

То есть, при старте этот сигнал сбрасывается в 0. Потом, пока счетчик не досчитает до нужного значения держит ноль,а после поднимается в 1. При этом этот EN_2 переключает клоковый мультиплексор и сам служит в качестве данных.

 

 

3) чтобы начать считывать что-то в определенный момент времени, надо чтобы в этот момент времени клок для считывания изменил фронт с 0 в 1.

Для этого, к двум делителям, которые запукаются при подъеме EN_1, я добавляю еще два, который запустятся по третьему сигналу разрешения EN_3; при этом делить начинают сразу с высокого фронта. EN_3 получаю аналогично EN_2.

 

Теперь что касается фронтов. Использую все тот же клоковый мультиплексор. На один вход данных подаю константу 0, а на другой подключаю выход делителя,работающего по EN_3. EN_3 так же переключает адреса мультиплексора. Так я надеюсь получить имитацию смены фронта.

 

Что скажите?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this