iosifk 3 13 февраля, 2019 Опубликовано 13 февраля, 2019 · Жалоба 16 часов назад, Nikolas72_91 сказал: Если задержать на 2 такта в плане синхронизации с клоком то тут не страшно или ввести в клоковый домен. А если 10 тактов то это черезчур. Да и не проблема это вовсе... Как делается у микроконтроллеров с предвыборкой переходов? Ставим 2 счетчика. Один продолжает считать, а второй останавливается передним же фронтом. Ну а дальше, если это глитч, то первый так и продолжает считать, а второй - сбрасывается. А если не глитч, то первый - сбрасывается, а второй продолжает считать... Нужен еще аппарат, который выбирает правильный результат... Результат счета на лету переписывается из первого регистра в момент запуска второго или еще раз по окончании полупериода. Задержка на "10" тактов может быть учтена в выходном регистре, т.к. похоже на то, что импульсы длительностью "10" тактов реально существовать не будут... А небольшой цифровой фильтр лишнем не будет.. Как-то так... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dvlwork 0 13 февраля, 2019 Опубликовано 13 февраля, 2019 · Жалоба Вообще задача несколько мутная. Впечатление такое что это попытка решить простую задачу сложными способами. Почему нельзя у автогенератора порезать гармоники? Почему формирование этого сигнала нельзя сделать полностью цифровым способом? Ну если нельзя так нельзя. Задача, как я понял, сводится к тому чтобы пропускать входной сигнал если фронты находятся в допустимых пределах и мультиплексировать его на референсный если фронт появился не вовремя. И делать это как можно быстрее. Ну например такая асинхронщина: детекторы фронтов с разрешением допустимого диапазона и мультиплексор сигнала. 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 сами цифровым способом. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nikolas72_91 0 13 февраля, 2019 Опубликовано 13 февраля, 2019 · Жалоба 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 элементов всего. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nikolas72_91 0 14 февраля, 2019 Опубликовано 14 февраля, 2019 · Жалоба Всем снова здравствуйте, написал код должен синхронно работать как вы говорили надо сделать, асинхронный только сброс. Что думаете на счет такого кода по измерению полупериодов или я опять криво написал? Хочу узнать ваши отзывы, переписал теперь используется 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; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 168 14 февраля, 2019 Опубликовано 14 февраля, 2019 · Жалоба Чем тактуется счётчик? Зачем понадобился сигнал разрешения счёта? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nikolas72_91 0 14 февраля, 2019 Опубликовано 14 февраля, 2019 · Жалоба 30 минут назад, Plain сказал: Чем тактуется счётчик? Зачем понадобился сигнал разрешения счёта? Не совсем понял, плис тактируется от мк на ножку, и все внутрь плис и больше ничего. Сигнал разрешения, чтобы счетчик не считал когда нет сигнала для измерения, а то если сигнал reset установился в 1 счетчик и начинал считать. Если у вас есть какие то предложения по улучшению можете их написать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 168 14 февраля, 2019 Опубликовано 14 февраля, 2019 · Жалоба Да, всё нормально, просто "end if" пропустил. Про улучшения уже говорили — можно выход оконного компаратора, которого сейчас нет, выдавать сразу как результат — это сбрасываемый вместе со счётчиком флаг, который меняют два сравнения на равно с границами диапазона полупериода, объединённых по "исключающее ИЛИ". Для возможной экономии ресурсов, можно эти границы задавать снаружи не явно, а как частоту и полосу, и вычислять на ходу, т.е. тоже с нулевой задержкой. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nikolas72_91 0 14 февраля, 2019 Опубликовано 14 февраля, 2019 · Жалоба 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; Что то к вечеру уже голова не варит, пока так и не понял как точно это реализовать, то что вы написали. Можете пример написать или может, что то в интернете есть скинуть для примера посмотреть как правильно такое сделать, что вы написали. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 14 февраля, 2019 Опубликовано 14 февраля, 2019 · Жалоба 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; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nikolas72_91 0 14 февраля, 2019 Опубликовано 14 февраля, 2019 · Жалоба 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; Потом тогда поизучаю ваш код, впринципе да можно от регистра хранения можно отказаться. Получается по сигналу валидности можно сравнивать данные с константами я так понял без использования регистра хранения. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 168 14 февраля, 2019 Опубликовано 14 февраля, 2019 (изменено) · Жалоба 41 минуту назад, Nikolas72_91 сказал: 1 час назад, Plain сказал: сбрасываемый вместе со счётчиком флаг, который меняют два сравнения на равно с границами диапазона полупериода, объединённых по "исключающее ИЛИ" не понял как точно это реализовать Это одна строка под тактом — присваивание флагу результата "исключающее ИЛИ" его и результатов двух сравнений. Ну и сброс этого флага по перепадам, вместе со счётчиком. Потому что фактически, у всей Вашей схемы однобитный выход "выход полупериода за границы" — как раз вот такой вот флаг. Изменено 14 февраля, 2019 пользователем Plain Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться