Делитель частоты на VHDL

Для подачи тактовых сигналов в микросхему ПЛИС можно использовать один или несколько специальных контактов микросхемы. Чаще всего в нашем приборе имеется только одна опорная частота, к примеру, 100 МГц.  Для формирования банка опорных частот внутри ПЛИС используются так называемые блоки DCM (в FPGA). Они предоставляют широкие возможности деления и умножения опорной частоты. Но эти блоки представлены в сильно ограниченном количестве (в xc3s200 – TQ144 их 4 шт.) В микросхемах CPLD многофункциональных блоков DCM вообще нет, а стандартные возможности синтеза частот ограничиваются лишь библиотечными делителями на четное число (2, 4, 8…).

Следовательно, возникает необходимость создания делителя с любым целым коэффициентом деления.

Нарисуем схему делителя частоты с коэффициентом деления 125.

Рисунок 1. "Железная" структура делителя

Как видно,  это обычный 7 – разрядный счетчик, на вход которого подается импульсный периодический сигнал с частотой следования импульсов 100 МГц. На выходах же счетчика стоит элемент, сравнивающий st (значение счетчика), преобразованное в десятичный вид, с числом 124 (то есть с N-1). Почему сравнение происходит с числом 124, а не с числом 125? Потому что следующий, 125-й импульс сбросит значения выходного 7 разрядного сигнала в состояние “0000000”.

Перед Вами текст VHDL – программы делителя частоты с коэффициентом деления 125. После символа  до конца строки следует текст, не подлежащий обработке компилятором. Следовательно, после символа  можно писать различные комментарии и служебную информацию.

library IEEE;                                                                       - – декларация библитек IEEE

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity div125 is - – описание внешних подключений компонента

Port ( CLK : in std_logic;                                           – – описание входного вывода CLK

Q : out std_logic);                                               – – описание выходного вывода Q

end div125;

architecture Behavioral of div125 is – описание поведения делителя

signal st : std_logic_vector(6 downto 0);              – декларация сигнала st как 7 – проводной шины

begin

process(CLK)                                                    – в списке чувствительности находится сигнал на порте CLK

begin

if CLK ‘event and CLK = ‘1’ then                – описание фронта сигнала на порте CLK (1)

if conv_integer(st) = 124 then                                                           – (2)

st <= conv_std_logic_vector(0,7);                                           – (3)

else st <= st + 1;                                                                 — (4)

end if;                                                                                                     — (5)

end if;                                                                                                                      – (6)

end process;

Q <= ‘1’ when conv_integer(st) = 124 else ‘0’;  – присвоение сигналу порту Q значения ‘1’ либо ‘0’

end Behavioral;

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

После ключевого слова entity – «сущность» – идет декларация портов компонента div125. Порты – это все входы и выходы устройства. В нашем делителе их всего два – один вход и один выход.

Порт CLK декларируется (представляется) как in (вход) и ему назначается тип std_logic , т.е имеющий только два значения – ‘0’ и ’1’. Для справки – тип std_logic является подтипом главного типа std_ulogic, а уж тот имеет 9 различных значений, включая и третье состояние с высоким импедансом.

Порт Q декларируется как out (выход).

После ключевого слов architecture идет описание поведения компонента div125.

До ключевого слова begin необходимо продекларировать все внутренние сигналы компонента. В данном случае мы имеем только один внутренний сигнал st – это сигнал, отображающий состояние счетчика в данный момент времени. Имеет тип std_logic_vector(6 downto 0). В скобках указаны начальный и конечный номер провода в шине. Видно, что в данном случае первым стоит старший бит.

Далее следует оператор под названием process. Это параллельный оператор, который имеет своем списке чувствительности (в данном случае) сигнал CLK. Как работает этот оператор? Очень просто! В теле оператора process (после строки begin до строки end process) мы наблюдаем 6 строчек. Почти дословный перевод этих строчек означает следующее:

1)            если на входе CLK появился положительный фронт сигнала (перепад из нуля в единицу), то

2)            если десятичное значение сигнала st равно 124, то тогда

3)            нужно присвоить сигналу st десятичное значение 0, преобразованное в двоичный вид и выраженное семью разрядами (т.е. семь нулей, что соответствует количеству линий в шине st).

4)            иначе (т.е если десятичное значение сигнала st ещё не равно 124) сигналу st нужно присвоить значение st + 1 (т.е. счетчик должен продолжать счет).

5)            выражение, завершающее последовательный оператор if во второй строке.

6)            выражение, завершающее последовательный оператор if в первой строке.

Далее следует присвоение выходному порту Q значения ‘1’ в том случае, если десятичное значение сигнала st равно 124, и значения ‘0’, если это не так.

На примере данного делителя мы разобрали принцип построения VHDL-программы, а так же рассмотрели подробно некоторые операции. Следует отметить, что оператор process, являясь параллельным оператором, выполняется одновременно со строкой, в которой порту Q присваивается ‘1’ или ‘0’.

 


 

Об авторе admin

Инженер. Окончил НГТУ по специальности "Радиосвязь, телевидение и радиовещание". С 2003 г. занимаюсь разработкой электронной начинки различных радиотехнических устройств и приборов.
Запись опубликована в рубрике VHDL-коды, Все статьи. Добавьте в закладки постоянную ссылку.

14 комментариев на «Делитель частоты на VHDL»

  1. Nick говорит:

    Кстати, вместо “if conv_integer(st) = 124 then” можно просто “if(st) = 124 then” библиотека позволяет

  2. Nick говорит:

    Тоже поначалу думал(что то там не получалось красиво представить код в статье), потом забил и сделал в виде картинки JPG http://nick17.ru/radiotehnika/fpga/a-myi-podklyuchaem-enkoder-k-plis/ пока устраивает и так

  3. Nick говорит:

    Ок, спасибо за совет, попробую :)

  4. SA говорит:

    Спасибо за описание.
    А подскажите, как правильно, использовать этот сигнал Q в дальнейшем коде программы?

    • admin говорит:

      Очень хороший вопрос! Дело в том, что в статье мною допущена ошибка (описка). На самом деле Q – это же не сигнал, а порт! В ближайшем будущем обязательно исправлю. При чем это выходной порт. То есть ему мы можем присвоить какое-то значение, а вот значение его самого присвоить какому либо порту либо сигналу мы не можем (если только не попробовать обозначить этот порт как “inout”.

  5. А я использую такой делитель :)

    if cnt_125 = x”7C” then
    cnt_125 <= x"00";
    Q <= '1';
    else
    cnt_125 <= cnt_125 + 1;
    Q <= '0';
    end if;

    Могу показать делитель с дробным коэффициентом деления :)

  6. На самом деле это просто счетчик разрядностью скажем 24 (чем больше разрядность, тем точнее), лучше использовать сумматор 48 разрядов на DSP элементе:

    cnt <= cnt + x"0AF8B0"; (3 МГц из 70 МГц)

    В итоге получается просто "пила", а старший разряд cnt(23) и будет частота 3 МГц.

    x"0AF8B0" – вычисляется по формуле: (X/Y)*2(в степени Z), где X-получаемая частота (3МГц), Y-опорная частота (70МГц), Z-разрядность сумматора (24),
    или так (3МГц/70МГц)*2 (в степени 24) = 719024 что соответствует x"0AF8B0".

    Только тут есть минус, частота получается с джиттером.

  7. Swordman говорит:

    “Порт CLK декларируется (представляется) как in (вход) и ему назначается тип std_logic , т.е имеющий только два значения – ‘0’ и ’1’. Для справки – тип std_logic является подтипом главного типа std_ulogic, а уж тот имеет 9 различных значений, включая и третье состояние с высоким импедансом.”
    Тут вообще какбэ ошибка xD. std_logic отличается от std_ulogic тем что для последнего существует таблица (в библиотеке) определяющая результат взаимодействия двух сигналов отличных от 1 и 0 (т.н. функция разрешения).
    Популярнее здесь: http://www.dsol.ru/stud/book7/chapter4/page4_03.html
    или здесь: http://www.velocityreviews.com/forums/t538967-what-is-the-difference-between-the-types-std_logic-and-std_ulogic.html

  8. длительность импульса всегда будет ровна длительности при первоначальной частоте . иными словами при увеличении коэффициента деления скважность импульса снижается. проверил в железе , проверил осциллографом . на частоте в единицы герцев получил длительность импульса НАНОсекунды.
    добавьте в условие “if conv_integer(st) = 124 then” сигнал, который изменяет свое значение при достижении st = 124 на противоположный вместе с тем и меняет выход. тогда скважность будет адекватной .

  9. Дядя Артем говорит:

    Написал под свои нужды такой вот код. Компилирует уже 1:50.
    В чем дело?

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.STD_LOGIC_ARITH.ALL;
    use IEEE.STD_LOGIC_UNSIGNED.ALL;
    entity shortgen is
    Port ( input: in std_logic;
    output: out std_logic);
    end shortgen;
    architecture Behave of shortgen is
    signal st: std_logic_vector(23 downto 0);
    begin
    process(input,st)
    begin
    if input’event and input = ‘1’ then
    if st = “111000010000000000000000” then
    st <= "000000000000000000000000";
    else st <= st + 1;
    end if;
    end if;
    end process;
    output <= '1' when st = "111000010000000000000000" else '0';
    end Behave;

    • admin говорит:

      1) В списке чувствительности оператора PROCESS, судя по смыслу, должен быть только сигнал INPUT, а именно – process(input). Других багов не нашел.
      2) Разные типы кавычек у многозначных чисел. Нужно привести их к единообразию.

Оставить комментарий