Я пытаюсь сгенерировать тактовую частоту 40 МГц на FPGA 100 МГц, и я нахожу это своего рода борьбой с использованием кода Verilog.
Я перенаправил часы на пин, чтобы проверить функциональность 100Mhz:
assign pin1= clock; //gives me a 100MHz clock
assign pin2= ~clock; //gives me a 100MHz inverse clock
Блок always
:
reg clock1;
reg [4:0] prescaler1;
always @(posedge clk) begin
if(reset==1'b1)begin
clock1=1'b0;
prescaler1=2'b0;
end else begin
if(prescaler1==2'b01) begin
clock1=~clock1;
prescaler1=1'b0;
end else begin
prescaler1=prescaler1+1'b1;
clock1=clock1;
end
end
end
Это дает мне 50, 25, 16,66 и 12,5 МГц в зависимости от того, установлен ли прескалер на 0, 1, 2, 3.
Есть ли хитрость, как это сделать?
Это Zedboard Zynq-7000 Z-7020. XPS позволяет назначить 4 такта фабрики PL, но я считаю, что они должны быть кратны 33 МГц.
В чем разница между ARM_PLL, IO_PLL и DRR_PLL?
Простой прескалер, который вы реализовали, следует формуле
Многие FPGA включают в себя специализированные блоки генерации тактовых импульсов, такие как PLL (фазовая автоподстройка частоты). Это специализированная аналоговая схема, реализованная на кремнии FPGA, которую можно настроить для работы с более быстрым внутренним тактовым сигналом, чем применяемый главный тактовый генератор. Таким образом, внешняя тактовая частота 100 МГц может быть удвоена до 200 МГц или, может быть, до 400 МГц. В PLL используется принцип контура управления, аналогичный тому, что используется в операционных усилителях, для обеспечения стабильной более высокой внутренней частоты из стабильного внешнего опорного сигнала более низкой частоты.
Некоторые Xilinx FPGA имеют DCM (Digital Clock Manager). Altera называет такие вещи «мегафункцией», если я правильно помню, должна быть мегафункция для PLL. Зависит от того, какую именно FPGA вы используете. Обратитесь к основному техническому паспорту FPGA.
Если у вас нет PLL, вам нужен счетчик деления на 5 (до 20 МГц), версия того же счетчика с задержкой 1,5 цикла (используйте противоположный фронт тактового сигнала для 0,5 цикла) и логический элемент XOR (с исправленной версией). , вентиля ИЛИ будет достаточно, так как оба сигнала никогда не равны «1» одновременно)
Это даст вам сигнал 40 МГц с постоянным соотношением 40% (но не 50% ... отредактировано!)
Обратите внимание, что вентиль ИЛИ добавит некоторый перекос по отношению к прямому делению часов. Если ваша FPGA имеет регистры DDR, вы можете очистить это.
process(clk)
variable count : natural range 0 to 4;
begin
if rising_edge(clk) then
if count = 4 then
count := 0;
clk_20 <= '1';
else
count := count + 1;
clk_20 <= '0';
end if;
clk_20d1 <= clk_20; -- delay, thanks to signal assignment semantics
end if;
end process;
process(clk)
begin
if falling_edge(clk) then
clk_20d15 <= clk_20d1; -- +0.5 cycle delay
end if;
end process;
clk_40 <= clk20 or clk_20d15;
Должно быть просто перевести на Verilog.
Да, для этого есть хитрость. Это называется дробным делением тактовых импульсов и часто выполняется с помощью двойного модуля предварительного масштабирования .
Вот веб-страница с примером кода на VHDL (извините, без verilog): дробное-тактовое-деление-двойной-модуль
Используя эти методы, вы сможете получить 40-мегагерцовый сигнал из 100-мегагерцового тактового сигнала, но имейте в виду, что джиттер будет увеличиваться, и вы можете получить сигнал, который не имеет 50-процентного рабочего цикла.
Поскольку вы работаете с FPGA: проверьте, содержит ли ваша FPGA диспетчер цифровых часов. Это аппаратные блоки, которые могут генерировать широкий диапазон частот из существующих часов, сначала умножая частоту, а затем разделяя ее. Вы получите лучшую производительность от цифрового диспетчера часов, чем от написанного от руки предварительного делителя с двойным модулем.
Лучшим способом будет PLL, как упоминалось в других ответах, - умножьте на 4, затем разделите на 10. Вы можете сделать x2/5, но это не даст вам 50% рабочего цикла (может быть, это не проблема).
Но вдобавок к этому есть второй вариант, если PLL недоступен, что не рекомендуется, поскольку он основан на асинхронной логике. Это будет выглядеть примерно так:
wire clock2x;
wire clock2xDelay;
assign clock2x = clock100M ^ clock2xDelay;
assign clock2xDelay = ...; //I need to be clock2x delayed by about 5ns
reg [2:0] divider;
always @ (posedge clock2x or posedge reset) begin
if (reset) begin
divider <= 3'b0;
end else if (divider == 3'd4) begin
divider <= 3'b0;
end else begin
divider <= divider + 3'b1
end
end
assign clock50M = divider[1]; // 40% Duty cycle, 50MHz clock
Приведенный выше код не совсем завершен — вы заметите, что clock2xDelay не завершен. По сути, именно здесь должен произойти интересный момент, и это будет зависеть от вашего устройства. В основном вам нужно добавить достаточную задержку (через задержку цепочки переноса, задержки LUT и т. д.), чтобы XOR создавал достаточно широкий импульс, чтобы не вызывать ошибок синхронизации минимальной ширины импульса. Синтезатору также нужно сказать, чтобы он не оптимизировал цепочку задержки.
Этот код не рекомендуется, так как асинхронная задержка зависит от температуры и характеристик устройства, что приводит к дрожанию часов.
Энди ака
Полиномиальный
Пэббельс