Делитель частоты: классика на счётчике

Учимся получать из быстрого системного такта медленные сигналы — например, мигание светодиода раз в секунду.

Делитель частоты — схема на счётчике, которая из тактового сигнала высокой частоты формирует сигнал меньшей частоты, переключаясь раз в N тактов.

Системный такт FPGA обычно очень быстрый — 50, 100 или даже 200 МГц. Но человеку нужны медленные события: мигание светодиода раз в секунду, обновление дисплея, тики часов. Напрямую замедлить такт нельзя, зато можно поделить его счётчиком — это одна из первых практических схем, которую собирает каждый FPGA-инженер.

Идея деления

Принцип прост: считаем такты и переключаем выход каждые N тактов. Если входная частота 100 МГц (10^8 тактов в секунду), а нужен сигнал 1 Гц (одно переключение в секунду), счётчик должен досчитать до половины — потому что один полный период выхода состоит из «высокого» и «низкого» полупериодов. Сколько считать — простой расчёт:

# Расчёт предела счётчика для делителя частоты
f_in = 100_000_000     # входная частота, Гц (100 МГц)
f_out = 1              # желаемая частота на выходе, Гц (1 Гц — мигание раз в сек)

# выход переключается дважды за период (вкл/выкл), поэтому делим на 2
half_period_ticks = f_in // (2 * f_out)
bits_needed = (half_period_ticks).bit_length()

print(f"Считать до: {half_period_ticks} тактов")
print(f"Нужна разрядность счётчика: {bits_needed} бит")
print(f"Проверка: {f_in} / (2 * {half_period_ticks}) = {f_in/(2*half_period_ticks):.1f} Гц")

Вывод:

Считать до: 50000000 тактов
Нужна разрядность счётчика: 26 бит
Проверка: 100000000 / (2 * 50000000) = 1.0 Гц

Итак, чтобы из 100 МГц получить 1 Гц, надо переключать выход каждые 50 миллионов тактов, а счётчику нужно минимум 26 бит. Эти числа — прямой вход в Verilog-модуль.

Делитель на Verilog

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

module clk_divider #(
    parameter integer MAX = 50_000_000 - 1   // 50 млн тактов на полупериод
)(
    input  wire clk,        // быстрый системный такт (100 МГц)
    input  wire rst,
    output reg  slow        // медленный выход (1 Гц)
);
    reg [25:0] counter;     // 26 бит хватает на 50 млн

    always @(posedge clk) begin
        if (rst) begin
            counter <= 0;
            slow    <= 0;
        end else if (counter == MAX) begin
            counter <= 0;          // досчитали — сбрасываем
            slow    <= ~slow;      // и переключаем выход
        end else begin
            counter <= counter + 1;
        end
    end
endmodule

Логика прозрачна: пока счётчик не дошёл до MAX — инкремент; дошёл — обнуляем счётчик и инвертируем slow. Так slow переключается ровно раз в полупериод, давая на выходе 1 Гц.

Как работает под капотом

Важно понимать: делитель не «замедляет» сам такт — он остаётся 100 МГц. Делитель создаёт новый сигнал, который меняется медленно, но по-прежнему синхронизирован с быстрым тактом. Промоделируем маленький делитель на 3 (переключение каждые 3 такта) на Python:

# Делитель: переключаем выход каждые MAX+1 тактов
MAX = 2          # переключение каждые 3 такта (0,1,2)
counter = 0
slow = 0
print("такт | counter | slow")
print("-----+---------+-----")
for tick in range(10):
    print(f"  {tick}  |    {counter}    |  {slow}")
    if counter == MAX:
        counter = 0
        slow = 1 - slow      # инвертируем выход
    else:
        counter += 1

Вывод:

такт | counter | slow
-----+---------+-----
  0  |    0    |  0
  1  |    1    |  0
  2  |    2    |  0
  3  |    0    |  1
  4  |    1    |  1
  5  |    2    |  1
  6  |    0    |  0
  7  |    1    |  0
  8  |    2    |  0
  9  |    0    |  1

Выход slow переключается каждые 3 такта, его период — 6 тактов, то есть частота в 6 раз ниже входной. Точно так же 26-битный счётчик даёт 1 Гц из 100 МГц.

Частые ошибки

  • Забыть про деление на 2. Полный период выхода — это два полупериода, поэтому считают до f_in/(2·f_out), а не f_in/f_out.
  • Узкий счётчик. Для больших коэффициентов деления нужна большая разрядность; узкий счётчик переполнится и даст неверную частоту.
  • Делать «новый такт» и тактировать им другую логику. Тактировать схему делёным сигналом как обычным проводом — плохая практика; для смены частоты используют специальные тактовые ресурсы (PLL), а делёный сигнал чаще применяют как разрешение (clock enable).

Итог

  • Делитель частоты на счётчике формирует медленный сигнал из быстрого такта.
  • Считать нужно до f_in/(2·f_out) — период состоит из двух полупериодов.
  • Разрядность счётчика подбирают под коэффициент деления.
  • Сам такт не замедляется — создаётся новый синхронный сигнал.
Проверьте себя
1. Чтобы из 100 МГц получить 1 Гц, до скольких тактов должен считать делитель в каждом полупериоде?
A100 000 000
B50 000 000
C1 000 000
D2
2. Почему при расчёте делителя частоту делят ещё и на 2?
AДля запаса по точности
BПотому что полный период выхода состоит из двух полупериодов (высокого и низкого)
CИз-за ограничений FPGA
DЧтобы уменьшить разрядность
3. Что делает делитель частоты с самим системным тактом?
AФизически замедляет его
BНе меняет такт, а создаёт новый медленный сигнал, синхронизированный с быстрым тактом
CОстанавливает его
DУдваивает частоту