VHDL: создание очень медленных тактовых импульсов на основе очень быстрых тактовых импульсов

(Я бы разместил это в EE, но, похоже, здесь гораздо больше вопросов по VHDL ...)

Предпосылки. Я использую ПЛИС Xilinx Spartan-6LX9 с Xilinx ISE 14.4 (веб-пакет).

Сегодня я наткнулся на ужасное предупреждение «PhysDesignRules: 372 - Gated Clock», и я вижу, что по этому поводу в целом ведется МНОГО дискуссий. Похоже, что консенсус состоит в том, чтобы использовать один из DCM на FPGA для деления тактовой частоты, но ... мой DCM, похоже, не способен перейти от 32 МГц до 4,096 кГц (согласно мастеру он достигает нижней границы на 5 МГц на основе 32 МГц ... и кажется абсурдным пытаться объединить несколько DCM в цепочку для этой низкочастотной цели).

Моя текущая конструкция использует clk_in для подсчета до указанного значения (15265), сбрасывает это значение на ноль и переключает бит clk_out (так что у меня рабочий цикл равен 50%, FWIW). Он выполняет свою работу, и я легко могу использовать передний край clk_out для перехода к следующему этапу моего дизайна. Кажется, все работает нормально, но ... синхронизированные часы (даже если они не входят в диапазон, в котором асимметрия часов, ИМХО, будет очень актуальна). (Примечание: все тесты часов выполняются с использованием функции rise_edge () в процессах, чувствительных к данным часам.)

Итак, мои вопросы:

  • Если мы говорим о получении относительно медленного clk_out из гораздо более быстрого clk_in, считается ли стробирование плохим? Или этот вид «подсчитать до x и отправить импульс» довольно типичен для ПЛИС для генерации «часов» в диапазоне кГц, и вместо этого может запускаться какой-то другой ненужный побочный эффект это предупреждение?

  • Есть ли лучший способ создать тактовую частоту с низким кГц-диапазоном из основных тактовых импульсов с МГц-диапазоном, имея в виду, что использование нескольких DCM здесь кажется излишним (если это вообще возможно, учитывая очень низкую выходную частоту)? Я понимаю, что 50% -ный рабочий цикл может быть излишним, но если предположить, что один тактовый сигнал и не используются встроенные DCM, как еще можно выполнить основное деление тактовой частоты с помощью FPGA?

Изменить: учитывая следующее (где CLK_MASTER - это входная частота 32 МГц, а CLK_SLOW - желаемая частота медленной частоты, а LOCAL_CLK_SLOW была способом сохранить состояние часов для всего рабочего цикла), я узнал, что эта конфигурация вызывает предупреждение:

architecture arch of clock is
    constant CLK_MASTER_FREQ: natural := 32000000; -- time := 31.25 ns
    constant CLK_SLOW_FREQ: natural := 2048;
    constant MAX_COUNT: natural := CLK_MASTER_FREQ/CLK_SLOW_FREQ;
    shared variable counter: natural := 0;
    signal LOCAL_CLK_SLOW: STD_LOGIC := '0';
begin
    clock_proc: process(CLK_MASTER)
    begin
        if rising_edge(CLK_MASTER) then
            counter := counter + 1;
            if (counter >= MAX_COUNT) then
                counter := 0;
                LOCAL_CLK_SLOW <= not LOCAL_CLK_SLOW;
                CLK_SLOW <= LOCAL_CLK_SLOW;
            end if;
        end if;
    end process;
end arch;

Принимая во внимание, что эта конфигурация НЕ вызывает предупреждение:

architecture arch of clock is
    constant CLK_MASTER_FREQ: natural := 32000000; -- time := 31.25 ns
    constant CLK_SLOW_FREQ: natural := 2048;
    constant MAX_COUNT: natural := CLK_MASTER_FREQ/CLK_SLOW_FREQ;
    shared variable counter: natural := 0;
begin
    clock_proc: process(CLK_MASTER)
    begin
        if rising_edge(CLK_MASTER) then
            counter := counter + 1;
            if (counter >= MAX_COUNT) then
                counter := 0;
                CLK_SLOW <= '1';
            else
                CLK_SLOW <= '0';
            end if;
        end if;
    end process;
end arch;

Итак, в данном случае это было все из-за отсутствия другого (как я уже сказал, рабочий цикл 50% изначально был интересен, но в конечном итоге не был обязательным требованием, и переключение бита «локальных» часов казалось довольно умным при время ...) Похоже, я был в основном на правильном пути.

На данный момент мне не ясно, почему использование счетчика (в котором хранится много битов) не вызывает предупреждений, а бит вывода с сохранением и переключением действительно вызывает предупреждения. < / strong> Мысли?


person MartyMacGyver    schedule 06.03.2013    source источник


Ответы (4)


Если вам просто нужны часы для управления другой частью вашей логики в ПЛИС, простой ответ - использовать включение часов.

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

signal clk_enable_200kHz  : std_logic;
signal clk_enable_counter : std_logic_vector(9 downto 0);

--Create the clock enable:
process(clk_200MHz)
begin
  if(rising_edge(clk_200MHz)) then
    clk_enable_counter <= clk_enable_counter + 1;
    if(clk_enable_counter = 0) then
      clk_enable_200kHz <= '1';
    else
      clk_enable_200kHz <= '0';
    end if;
  end if;
end process;


--Slow process:
process(clk_200MHz)
begin
  if(rising_edge(clk_200MHz)) then
    if(reset = '1') then
      --Do reset
    elsif(clk_enable_200kHz = '1') then
      --Do stuff
    end if;
  end if;
end process;

Тем не менее, 200 кГц являются приблизительными, но указанное выше может быть расширено практически до любой частоты включения тактовой частоты, которая вам нужна. Кроме того, он должен поддерживаться напрямую аппаратным обеспечением FPGA в большинстве FPGA (по крайней мере, в частях Xilinx).

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

Часы не лишены этих недостатков. Все работает в одном и том же тактовом домене (хотя и с разной скоростью), поэтому вы можете легко использовать одни и те же сигналы без каких-либо синхронизаторов или подобных.

person sonicwave    schedule 06.03.2013
comment
Интересно ... это почти то, чем я уже занимался, хотя я использовал логику для переключения локального бита std_logic, когда он достиг необходимого значения (без предложения else), а затем назначил его выходу (значение рабочего цикла 50% было в любом случае больше не требуется). Убрав этот переключатель, а затем добавив предложение else (эквивалент вашего clk_enable_200kHz ‹= '0'; выше), вы избавились от предупреждения! Так что у меня была правильная идея, за исключением моей попытки получить 50% -ный рабочий цикл таким образом ... поэтому я задаюсь вопросом, был ли просто тот факт, что я фактически создал триггер, причиной всего этого? - person MartyMacGyver; 06.03.2013
comment
Звучит странно. Использовали ли вы стробируемый тактовый сигнал одинаково в обеих ситуациях? Предупреждение должно зависеть от логического сигнала, используемого в качестве часов, а не от того, как этот логический сигнал генерируется. - person sonicwave; 06.03.2013
comment
Я обновил свой вопрос кодом до и после (я тестировал обе формы, и только перед тем, как вывести эту ошибку ... хотя, очевидно, в нем есть дополнительный бит, как вы увидите). На данный момент это немного академично, но было бы очень приятно понять, почему то, что я сделал с самого начала, было неправильным (все, что я могу понять, это связано либо с отсутствием другого, либо с переключением дополнительного бита, либо с комбинацией обоих, при прочих равных.) - person MartyMacGyver; 06.03.2013

Обратите внимание, что в этом примере работает эта строка,

сигнал clk_enable_counter: std_logic_vector (от 9 до 0);

должен быть изменен на

signal clk_enable_counter: беззнаковый (от 9 до 0);

и вам нужно будет включить эту библиотеку,

библиотека ieee; используйте ieee.numeric_std.all;

person Greg    schedule 20.08.2014

Оба сэмпла создают сигнал, один из которых переключается с медленной скоростью, а другой - с «медленным» импульсом узким импульсом. Если оба этих сигнала поступят на тактовые входы других триггеров, я бы ожидал предупреждений о неоптимальной маршрутизации тактовых импульсов.

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

gated_clock <= clock when en = '1' else '0';
person Martin Thompson    schedule 07.03.2013
comment
Я думаю, что LOCAL_CLK_SLOW - это стробируемые часы здесь ... хотя почему переменная счетчика не имеет такой эффект, мне до сих пор неясно. - person MartyMacGyver; 08.03.2013
comment
Но LOCAL_CLOCK_SLOW - это просто сигнал, записываемый синхронно, как и весь другой нормальный синхронный код ... Происходит что-то очень странное! - person Martin Thompson; 08.03.2013

Вот полный пример кода:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;

ENTITY Test123 IS

    GENERIC (
        clk_1_freq_generic : unsigned(31 DOWNTO 0) := to_unsigned(0, 32); -- Presented in Hz
        clk_in1_freq_generic : unsigned(31 DOWNTO 0) := to_unsigned(0, 32) -- Presented in Hz, Also
    );

    PORT (
        clk_in1 : IN std_logic := '0';
        rst1 : IN std_logic := '0';
        en1 : IN std_logic := '0';
        clk_1 : OUT std_logic := '0'
    );

END ENTITY Test123;

ARCHITECTURE Test123_Arch OF Test123 IS
    --
    SIGNAL clk_en_en : std_logic := '0';
    SIGNAL clk_en_cntr1 : unsigned(31 DOWNTO 0) := (OTHERS => '0');
    --
    SIGNAL clk_1_buffer : std_logic := '0';
    SIGNAL clk_1_freq : unsigned(31 DOWNTO 0) := (OTHERS => '0'); -- Presented in Hz, Also
    SIGNAL clk_in1_freq : unsigned(31 DOWNTO 0) := (OTHERS => '0'); -- Presented in Hz
    --
    SIGNAL clk_prescaler1 : unsigned(31 DOWNTO 0) := (OTHERS => '0'); -- Presented in Cycles (Relative To The Input Clk.)
    SIGNAL clk_prescaler1_halved : unsigned(31 DOWNTO 0) := (OTHERS => '0');
    --

BEGIN
    clk_en_gen : PROCESS (clk_in1)
    BEGIN
        IF (clk_en_en = '1') THEN

            IF (rising_edge(clk_in1)) THEN
                clk_en_cntr1 <= clk_en_cntr1 + 1;

                IF ((clk_en_cntr1 + 1) = clk_prescaler1_halved) THEN   -- a Register's (F/F) Output Only Updates Upon a Clock-Edge : That's Why This Comparison Is Done This Way !

                    clk_1_buffer <= NOT clk_1_buffer;
                    clk_1 <= clk_1_buffer;
                    clk_en_cntr1 <= (OTHERS => '0');

                END IF;

            END IF;

        ELSIF (clk_en_en = '0') THEN

            clk_1_buffer <= '0';
            clk_1 <= clk_1_buffer;
            clk_en_cntr1 <= (OTHERS => '0'); -- Clear Counter 'clk_en_cntr1'

        END IF;

    END PROCESS;

    update_clk_prescalers : PROCESS (clk_in1_freq, clk_1_freq)
    BEGIN
        clk_prescaler1 <= (OTHERS => '0');
        clk_prescaler1_halved <= (OTHERS => '0');
        clk_en_en <= '0';

        IF ((clk_in1_freq > 0) AND (clk_1_freq > 0)) THEN

            clk_prescaler1 <= (clk_in1_freq / clk_1_freq); -- a Register's (F/F) Output Only Updates Upon a Clock-Edge : That's Why This Assignment Is Done This Way !
            clk_prescaler1_halved <= ((clk_in1_freq / clk_1_freq) / 2); -- (Same Thing Here)

            IF (((clk_in1_freq / clk_1_freq) / 2) > 0) THEN -- (Same Thing Here, Too)
                clk_en_en <= '1';
            END IF;

        ELSE
            NULL;
        END IF;

    END PROCESS;

    clk_1_freq <= clk_1_freq_generic;
    clk_in1_freq <= clk_in1_freq_generic;

END ARCHITECTURE Test123_Arch;
person Mr. Z.    schedule 04.07.2017
comment
Вы выкопаете вопрос четырехлетней давности, на который уже есть принятый ответ, и ответите на него, разместив массу кода с неправильным отступом. Это даже не полный минимально проверяемый пример. Пожалуйста, не делай этого - person JHBonarius; 05.07.2017
comment
@JHBonarius: Ну, код в этом «принятом ответе» не работал для меня, и моя основная часть кода занимает всего ~ 40 LOC в любом случае. - person Mr. Z.; 06.07.2017
comment
Извините, но в вашем коде нет пояснений или комментариев. И, например, посмотрите на процесс proc1_running_at_clk_1: он пуст ... И почему сигналы clk_in1_freq и clk_1_freq, когда кажется, что они должны быть константами .... и даже не 64-битными unsigned, а просто целыми числами. Если заглянуть глубже в свой код, это не имеет никакого смысла. - person JHBonarius; 06.07.2017
comment
Я верю, что мой код имеет смысл и что он очень удобен. Согласно процессу proc1_running_at_clk_1 - очевидно, что это просто заполнитель. Согласно clk_in1_freq & clk_1_freq - Тот, кто хочет превратить их в константы, может сделать это очень легко, просто при этом - возможность корректировок времени выполнения будет потеряна. - person Mr. Z.; 06.07.2017
comment
Как вы думаете, clk_prescaler1 <= clk_in1_freq / clk_1_freq будет работать в FPGA, если значения не являются константами ... И почему вы набираете каждое слово с большой буквы? - person JHBonarius; 07.07.2017
comment
Что ж, Singal clk_en_en вместе с Process update_clk_prescalers предназначены для динамической корректировки генерируемых часов во время выполнения. - person Mr. Z.; 08.07.2017
comment
Не могли бы вы прояснить свой вопрос? - person Mr. Z.; 09.07.2017
comment
У меня один вопрос: знаете ли вы, что писать каждое слово в английском языке с заглавной буквы грамматически неправильно? - person JHBonarius; 10.07.2017
comment
И затем мой комментарий: вы предлагаете, чтобы ваш не комментируемый неописанный дизайн предлагал переменную тактовую частоту, которую вы могли бы достичь, изменив clk_in1_freq и / или clk_1_freq, каждый из которых является 64-битным беззнаковым. Затем вы помещаете строку, содержащую clk_prescaler1 <= clk_in1_freq / clk_1_freq, которая будет вычислять коэффициент деления. Так что предложено реализовать 64-битное деление в vhdl в комбинаторном процессе ... FPGA не имеет жестко зашитых делителей. Как вы можете себе представить, что это происходит? Если не верите: сделайте вместо сигналов clk_in1_freq и clk_1_freq порты. - person JHBonarius; 10.07.2017
comment
Я вижу, вы редактировали свой код ... теперь это 32-битное деление вместо 64-битного. Но это не решает проблему. - person JHBonarius; 10.07.2017
comment
Думаю, пора перестать кормить тебя, как сейчас. - person Mr. Z.; 11.07.2017