Перейти к содержанию

    

Измерение длительности полупериодов

16 часов назад, Nikolas72_91 сказал:

Если задержать на 2 такта в плане синхронизации с клоком то тут не страшно или ввести в клоковый домен. А если 10 тактов то это черезчур.

Да и не проблема это вовсе... Как делается у микроконтроллеров с предвыборкой переходов? Ставим 2 счетчика. Один продолжает считать, а второй останавливается передним же фронтом. Ну а дальше, если это глитч, то первый так и продолжает считать, а второй - сбрасывается. А если не глитч, то первый - сбрасывается, а второй продолжает считать... Нужен еще аппарат, который выбирает правильный результат...  Результат счета на лету переписывается из первого регистра в момент запуска второго или еще раз по окончании полупериода. Задержка на "10" тактов может быть учтена в выходном регистре, т.к. похоже на то, что импульсы длительностью "10" тактов реально существовать не будут... А небольшой цифровой фильтр лишнем не будет.. Как-то так...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще задача несколько мутная. Впечатление такое что это попытка решить простую задачу сложными способами.

Почему нельзя у автогенератора порезать гармоники?

Почему формирование этого сигнала нельзя сделать полностью цифровым способом?

 

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

Ну например такая асинхронщина: детекторы фронтов с разрешением допустимого диапазона и мультиплексор сигнала.

always @(posedge clk or negedge en_pos)
if (~en_pos) pos_front <= 1'b0;
else pos_front <= 1'b1;

always @(negedge clk or negedge en_neg)
if (~en_neg) neg_front <= 1'b0;
else neg_front <= 1'b1;
                          
assign clk_out = (pos_front | neg_front) ? ref_clk : clk;

Ну и формирование en_pos, en_neg сами цифровым способом.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
5 часов назад, dvlwork сказал:

Вообще задача несколько мутная. Впечатление такое что это попытка решить простую задачу сложными способами.

Почему нельзя у автогенератора порезать гармоники?

Почему формирование этого сигнала нельзя сделать полностью цифровым способом?

 

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

Ну например такая асинхронщина: детекторы фронтов с разрешением допустимого диапазона и мультиплексор сигнала.


always @(posedge clk or negedge en_pos)
if (~en_pos) pos_front <= 1'b0;
else pos_front <= 1'b1;

always @(negedge clk or negedge en_neg)
if (~en_neg) neg_front <= 1'b0;
else neg_front <= 1'b1;
                          
assign clk_out = (pos_front | neg_front) ? ref_clk : clk;

Ну и формирование en_pos, en_neg сами цифровым способом.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всем снова здравствуйте, написал код должен синхронно работать как вы говорили надо сделать, асинхронный только сброс. Что думаете на счет такого кода по измерению полупериодов или я опять криво написал? Хочу узнать ваши отзывы, переписал теперь используется 1 счетчик 1 регистр хранения. 

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;


entity PULSE_MEASHURE is
generic (
  N                           : integer:=511;         -- Размерность счетчика
  FREQ_CLK	                  : natural := 48000000;  -- Тактовая частота плис (Hz)
  MAX_FREQ_PERIOD             : natural := 280000;    -- Максимальная частота измеряемого при котором переключается на генератор (Hz)
  MIN_FREQ_PERIOD             : natural := 230000     -- Минимальная частота пропускаемого измеряемого периода (Hz)
  );
port (
  clk                         : in  std_logic;        -- порты входа тактовой частоты
  reset                       : in  std_logic;        -- сигнал сброса и выключения
  signal_in                   : in  std_logic;        -- измеряемый сигнал, измеряется каждый полупериод
  Period                      : out integer           -- вывод числа тиков измеренного каждого полупериода
     );
end PULSE_MEASHURE;

architecture Behavioral of PULSE_MEASHURE is

signal r_count                            : integer range 0 to N := 0;
signal len_pulse                          : integer range 0 to N := 0;
signal shift_reg                          : std_logic_vector(1 downto 0);
signal r_count_ena                        : std_logic;
signal all_edge                           : std_logic;

begin

edge_detector : process(clk,reset)    -- детектор фронтов на сдвиговом регистре вырабатывает короткие импульсы равные 1 периода clk 
begin
 if(reset='0') then                   -- обнуление сигналов сдвигового регистра асинхронно 
    shift_reg <= (others=>'0');
 elsif(rising_edge(clk)) then
    shift_reg <= shift_reg (0) & signal_in;        --    __________-------_________   измеряемый сигнал 
 end if;
    all_edge <=  shift_reg(0) xor shift_reg(1);   --    ___________п______п________          выдает короткий импульс равный 2 такта по возрастающему фронту	 
end process edge_detector;


pulse_counter : process(clk,reset)
begin
  if(reset='0') then        -- обнуление всех сигналов и счетчиков при 0 reset асинхронно
    r_count_ena  <= '0';
    r_count      <= 0;
    len_pulse    <= 0;
  elsif(rising_edge(clk)) then  -- по возрастающему фронту clk и детектору возрастающего фронта устанавливаюся сигналы в разрешения работы счетчика и вывод данных в регистр хранения
    if(all_edge='1') then
      r_count_ena  <= '1';      -- установка сигнала разрешения счета
		len_pulse  <= r_count;    -- запись данных в регистр
  end if;

    if(r_count_ena='1') then
        r_count <= r_count + 1;
	 if(all_edge='1') then
	    r_count <= 0;
	 end if;
   end if;	 
  end if;
end process pulse_counter;

Period <= len_pulse;
	
end Behavioral;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Чем тактуется счётчик? Зачем понадобился сигнал разрешения счёта?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
30 минут назад, Plain сказал:

Чем тактуется счётчик? Зачем понадобился сигнал разрешения счёта?

Не совсем понял, плис тактируется от мк на ножку, и все внутрь плис и больше ничего. Сигнал разрешения, чтобы счетчик не считал когда нет сигнала для измерения, а то если сигнал reset установился в 1 счетчик и начинал считать. Если у вас есть какие то предложения по улучшению можете их написать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, всё нормально, просто "end if" пропустил. Про улучшения уже говорили — можно выход оконного компаратора, которого сейчас нет, выдавать сразу как результат — это сбрасываемый вместе со счётчиком флаг, который меняют два сравнения на равно с границами диапазона полупериода, объединённых по "исключающее ИЛИ". Для возможной экономии ресурсов, можно эти границы задавать снаружи не явно, а как частоту и полосу, и вычислять на ходу, т.е. тоже с нулевой задержкой.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
10 минут назад, Plain сказал:

Да, всё нормально, просто "end if" пропустил. Про улучшения уже говорили — можно выход оконного компаратора, которого сейчас нет, выдавать сразу как результат — это сбрасываемый вместе со счётчиком флаг, который меняют два сравнения на равно с границами диапазона полупериода, объединённых по "исключающее ИЛИ". Для возможной экономии ресурсов, можно эти границы задавать снаружи не явно, а как частоту и полосу, и вычислять на ходу, т.е. тоже с нулевой задержкой.

Еще немного упростил и переписал, теперь вот так вот все.

pulse_counter : process(clk,reset)
begin
  if(reset='0') then        -- обнуление всех сигналов и счетчиков при 0 reset асинхронно
    r_count_ena  <= '0';
    r_count      <= 0;
    len_pulse    <= 0;
  elsif(rising_edge(clk)) then  -- по возрастающему фронту clk и детектору возрастающего фронта устанавливаюся сигналы в разрешения работы счетчика и вывод данных в регистр хранения
   if(all_edge='1') then
      r_count_ena  <= '1';      -- установка сигнала разрешения счета
		r_count <= 0;             -- установка счетчика в 0
		len_pulse  <= r_count;    -- запись данных в регистр
   elsif(r_count_ena='1') then
      r_count <= r_count + 1;
   end if;	
  end if;
end process pulse_counter;

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
1 час назад, Nikolas72_91 сказал:

Еще немного упростил и переписал, теперь вот так вот все.


pulse_counter : process(clk,reset)
begin
  if(reset='0') then        -- обнуление всех сигналов и счетчиков при 0 reset асинхронно
    r_count_ena  <= '0';
    r_count      <= 0;
    len_pulse    <= 0;
  elsif(rising_edge(clk)) then  -- по возрастающему фронту clk и детектору возрастающего фронта устанавливаюся сигналы в разрешения работы счетчика и вывод данных в регистр хранения
   if(all_edge='1') then
      r_count_ena  <= '1';      -- установка сигнала разрешения счета
		r_count <= 0;             -- установка счетчика в 0
		len_pulse  <= r_count;    -- запись данных в регистр
   elsif(r_count_ena='1') then
      r_count <= r_count + 1;
   end if;	
  end if;
end process pulse_counter;

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

А зачем вам вообще асинхронный сброс (снятие которого надо ещё синхронизировать с clk) ? Насколько я помню MAX II должен поддерживать инициализацию триггеров нулями. Тут можно вообще без сброса обойтись.

Зачем на выходе триггеры ? Формируйте сигнал валидности данных, и все. Это ещё сэкономит 9 триггеров. Тем более у вас фактически готов сигнал валидности - это выход с детектора фронтов. 

Я бы описал так:

library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;

entity PULSE_MEASHURE is
    generic 
    (
        N                           : natural := 511;         -- Размерность счетчика
        FREQ_CLK	                : natural := 48000000;  -- Тактовая частота плис (Hz)
        MAX_FREQ_PERIOD             : natural := 280000;    -- Максимальная частота измеряемого при котором переключается на генератор (Hz)
        MIN_FREQ_PERIOD             : natural := 230000     -- Минимальная частота пропускаемого измеряемого периода (Hz)
    );
    port 
    (
        clk                         : in  std_ulogic;             -- порты входа тактовой частоты
        enable                      : in  std_ulogic;             -- сигнал включения/отключения
        signal_in                   : in  std_ulogic;             -- измеряемый сигнал, измеряется каждый полупериод
        Period                      : out integer range 0 to N;   -- вывод числа тиков измеренного каждого полупериода
        Period_valid                : out std_ulogic    -- вывод числа тиков измеренного каждого полупериода
    );
end entity;

architecture Behavioral of PULSE_MEASHURE is
    --============================================
    -- Крайне желательно добавить атрибуты синтеза
    -- Чтобы САПР не "оптимизировал" их
    -- syncronizer0 Синхронизирует signal_in
    -- syncronizer1 Синхронизирует disable
    --============================================
    signal syncronizer0  : std_logic_vector(1 downto 0)  := (others => '0');
    signal syncronizer1  : std_logic_vector(1 downto 0)  := (others => '0');
    
    --============================================
    -- Детектирование фронта
    --============================================
    signal edge_detector   : std_ulogic                     := '0';
    signal all_edge        : std_ulogic                     := '0';

    --====================================================================================================
    -- Счетчик периода. Если коэф. Пересчета 2^n-1 (полный счетчик) то лучше объявить счетчик как Unsigned,
    --  т.к нет необходимости явного описания что делать при переполнении
    --====================================================================================================
    signal pulse_counter   : unsigned (8 downto 0)    := (others => '0');

begin

    --==============================================
    -- Синхронизация signal_in с клоковым доменом
    -- Синхронизация disable   с клоковым доменом
    --==============================================
    syncronizer_proc : process(clk)      
    begin
        if (rising_edge(clk)) then
            syncronizer0 <= syncronizer0(syncronizer0'left - 1 downto 0) & signal_in;    
            syncronizer1 <= syncronizer1(syncronizer1'left - 1 downto 0) & enable;    
        end if;
    end process;
    
    --==============================================
    -- Детектирование фронтов
    --==============================================
    all_edge_detector : process(clk)      
    begin
        if (rising_edge(clk)) then
            edge_detector <= syncronizer0(syncronizer0'left);  
        end if;
    end process;
    all_edge <=  edge_detector xor syncronizer0(syncronizer0'left);

    --==============================================
    -- Счетчик периода
    --==============================================
    pulse_counter_proc : process(clk)
    begin
        if(rising_edge(clk)) then  
            pulse_counter <= pulse_counter + "1";
            if (all_edge = '1') then
                pulse_counter <= (others => '0');
            end if;
        end if;
    end process;
    
    Period       <= to_integer(pulse_counter);
    period_valid <= all_edge when (syncronizer1(syncronizer1'left) = '1' ) else '0'; -- При отключении модуля, просто маскируем сигнал валидности
	
end architecture;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
4 минуты назад, Flip-fl0p сказал:

А зачем вам вообще асинхронный сброс (снятие которого надо ещё синхронизировать с clk) ? Насколько я помню MAX II должен поддерживать инициализацию триггеров нулями. Тут можно вообще без сброса обойтись.

Зачем на выходе триггеры ? Формируйте сигнал валидности данных, и все. Это ещё сэкономит 9 триггеров. Тем более у вас фактически готов сигнал валидности - это выход с детектора фронтов. 

Я бы описал так:


library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;

entity PULSE_MEASHURE is
    generic 
    (
        N                           : natural := 511;         -- Размерность счетчика
        FREQ_CLK	                : natural := 48000000;  -- Тактовая частота плис (Hz)
        MAX_FREQ_PERIOD             : natural := 280000;    -- Максимальная частота измеряемого при котором переключается на генератор (Hz)
        MIN_FREQ_PERIOD             : natural := 230000     -- Минимальная частота пропускаемого измеряемого периода (Hz)
    );
    port 
    (
        clk                         : in  std_ulogic;             -- порты входа тактовой частоты
        enable                      : in  std_ulogic;             -- сигнал включения/отключения
        signal_in                   : in  std_ulogic;             -- измеряемый сигнал, измеряется каждый полупериод
        Period                      : out integer range 0 to N;   -- вывод числа тиков измеренного каждого полупериода
        Period_valid                : out std_ulogic    -- вывод числа тиков измеренного каждого полупериода
    );
end entity;

architecture Behavioral of PULSE_MEASHURE is
    --============================================
    -- Крайне желательно добавить атрибуты синтеза
    -- Чтобы САПР не "оптимизировал" их
    -- syncronizer0 Синхронизирует signal_in
    -- syncronizer1 Синхронизирует disable
    --============================================
    signal syncronizer0  : std_logic_vector(1 downto 0)  := (others => '0');
    signal syncronizer1  : std_logic_vector(1 downto 0)  := (others => '0');
    
    --============================================
    -- Детектирование фронта
    --============================================
    signal edge_detector   : std_ulogic                     := '0';
    signal all_edge        : std_ulogic                     := '0';

    --====================================================================================================
    -- Счетчик периода. Если коэф. Пересчета 2^n-1 (полный счетчик) то лучше объявить счетчик как Unsigned,
    --  т.к нет необходимости явного описания что делать при переполнении
    --====================================================================================================
    signal pulse_counter   : unsigned (8 downto 0)    := (others => '0');

begin

    --==============================================
    -- Синхронизация signal_in с клоковым доменом
    -- Синхронизация disable   с клоковым доменом
    --==============================================
    syncronizer_proc : process(clk)      
    begin
        if (rising_edge(clk)) then
            syncronizer0 <= syncronizer0(syncronizer0'left - 1 downto 0) & signal_in;    
            syncronizer1 <= syncronizer1(syncronizer1'left - 1 downto 0) & enable;    
        end if;
    end process;
    
    --==============================================
    -- Детектирование фронтов
    --==============================================
    all_edge_detector : process(clk)      
    begin
        if (rising_edge(clk)) then
            edge_detector <= syncronizer0(syncronizer0'left);  
        end if;
    end process;
    all_edge <=  edge_detector xor syncronizer0(syncronizer0'left);

    --==============================================
    -- Счетчик периода
    --==============================================
    pulse_counter_proc : process(clk)
    begin
        if(rising_edge(clk)) then  
            pulse_counter <= pulse_counter + "1";
            if (all_edge = '1') then
                pulse_counter <= (others => '0');
            end if;
        end if;
    end process;
    
    Period       <= to_integer(pulse_counter);
    period_valid <= all_edge when (syncronizer1(syncronizer1'left) = '1' ) else '0'; -- При отключении модуля, просто маскируем сигнал валидности
	
end architecture;

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
41 минуту назад, Nikolas72_91 сказал:
1 час назад, Plain сказал:

сбрасываемый вместе со счётчиком флаг, который меняют два сравнения на равно с границами диапазона полупериода, объединённых по "исключающее ИЛИ"

не понял как точно это реализовать

Это одна строка под тактом — присваивание флагу результата "исключающее ИЛИ" его и результатов двух сравнений. Ну и сброс этого флага по перепадам, вместе со счётчиком. Потому что фактически, у всей Вашей схемы однобитный выход "выход полупериода за границы" — как раз вот такой вот флаг.

Изменено пользователем Plain

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти