开发软件:Quartus 13.0 开发组件:Cyclone IV EP4CE10F17C8 仿真:Modelsim 10.1d
PLL:Phase Locked Loop(锁相环)是一种反馈控制电路,其特点是利用外部输入的参考信号控制环路内部震荡信号的频率和相位。它可以将FPGA的系统时钟转化所需的倍频及相位时钟,是IC开发中很重要的一个部分。PLL的工作原理图如下图所示:
锁相环通常由鉴相器(FPD,Frequency Phase Detector)、滤波器(LF,Loop Filter)和压控振荡器(VCO,Voltage Controlled Oscillator)3部分组成前向通路,由VCO分频器组成频率相位的反馈通路。PLL的组成结构如下图所示:
摘自:https://blog.csdn.net/weixin_48956120/article/details/130695162
任务:利用FPGA的PLL IP核实现LED闪烁控制。
思路:通过FPGA的4个I/O口连接4个LED,设定这些I/O为输出模式。内部计数器完成计数后改变该各I/O口的电平状态,实现LED灯的闪烁效果。
步骤:建立工程、新建顶层文件、调用PLL IP核、编写Testbench仿真文件、仿真。
代码如下:
`timescale 1ps/1ps
module My_PLL (
input wire clk, // inclk0.clk
input wire rst, // arest.rst
output wire outclk_0, // outclk0.clk
output wire outclk_1, // outclk1.clk
output wire outclk_2, // outclk2.clk
output wire outclk_3, // outclk3.clk
output wire outclk_4, // outclk4.clk
output wire locked // locked.export
);
PLL_ip My_PLL_u1 (
.inclk0 (clk), // inclk0.clk
.areset (~rst), // areset.rst
.c0 (outclk_0), // outclk0.clk
.c1 (outclk_1), // outclk1.clk
.c2 (outclk_2), // outclk2.clk
.c3 (outclk_3), // outclk3.clk
.c4 (outclk_4), // outclk4.clk
.locked(locked) //locked.export
);
endmodule
`timescale 1 ps / 1 ps
// synopsys translate_on
module PLL_ip (
areset,
inclk0,
c0,
c1,
c2,
c3,
c4,
locked);
input areset;
input inclk0;
output c0;
output c1;
output c2;
output c3;
output c4;
output locked;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
tri0 areset;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_on
`endif
wire [4:0] sub_wire0;
wire sub_wire6;
wire [0:0] sub_wire9 = 1'h0;
wire [3:3] sub_wire5 = sub_wire0[3:3];
wire [4:4] sub_wire4 = sub_wire0[4:4];
wire [2:2] sub_wire3 = sub_wire0[2:2];
wire [0:0] sub_wire2 = sub_wire0[0:0];
wire [1:1] sub_wire1 = sub_wire0[1:1];
wire c1 = sub_wire1;
wire c0 = sub_wire2;
wire c2 = sub_wire3;
wire c4 = sub_wire4;
wire c3 = sub_wire5;
wire locked = sub_wire6;
wire sub_wire7 = inclk0;
wire [1:0] sub_wire8 = {sub_wire9, sub_wire7};
altpll altpll_component (
.areset (areset),
.inclk (sub_wire8),
.clk (sub_wire0),
.locked (sub_wire6),
.activeclock (),
.clkbad (),
.clkena ({6{1'b1}}),
.clkloss (),
.clkswitch (1'b0),
.configupdate (1'b0),
.enable0 (),
.enable1 (),
.extclk (),
.extclkena ({4{1'b1}}),
.fbin (1'b1),
.fbmimicbidir (),
.fbout (),
.fref (),
.icdrclk (),
.pfdena (1'b1),
.phasecounterselect ({4{1'b1}}),
.phasedone (),
.phasestep (1'b1),
.phaseupdown (1'b1),
.pllena (1'b1),
.scanaclr (1'b0),
.scanclk (1'b0),
.scanclkena (1'b1),
.scandata (1'b0),
.scandataout (),
.scandone (),
.scanread (1'b0),
.scanwrite (1'b0),
.sclkout0 (),
.sclkout1 (),
.vcooverrange (),
.vcounderrange ());
defparam
altpll_component.bandwidth_type = "AUTO",
altpll_component.clk0_divide_by = 1,
altpll_component.clk0_duty_cycle = 50,
altpll_component.clk0_multiply_by = 4,
altpll_component.clk0_phase_shift = "0",
altpll_component.clk1_divide_by = 1,
altpll_component.clk1_duty_cycle = 50,
altpll_component.clk1_multiply_by = 2,
altpll_component.clk1_phase_shift = "0",
altpll_component.clk2_divide_by = 1,
altpll_component.clk2_duty_cycle = 50,
altpll_component.clk2_multiply_by = 1,
altpll_component.clk2_phase_shift = "-3333",
altpll_component.clk3_divide_by = 1,
altpll_component.clk3_duty_cycle = 50,
altpll_component.clk3_multiply_by = 1,
altpll_component.clk3_phase_shift = "3333",
altpll_component.clk4_divide_by = 2,
altpll_component.clk4_duty_cycle = 50,
altpll_component.clk4_multiply_by = 1,
altpll_component.clk4_phase_shift = "0",
altpll_component.compensate_clock = "CLK0",
altpll_component.inclk0_input_frequency = 40000,
altpll_component.intended_device_family = "Cyclone IV E",
altpll_component.lpm_hint = "CBX_MODULE_PREFIX=PLL_ip",
altpll_component.lpm_type = "altpll",
altpll_component.operation_mode = "NORMAL",
altpll_component.pll_type = "AUTO",
altpll_component.port_activeclock = "PORT_UNUSED",
altpll_component.port_areset = "PORT_USED",
altpll_component.port_clkbad0 = "PORT_UNUSED",
altpll_component.port_clkbad1 = "PORT_UNUSED",
altpll_component.port_clkloss = "PORT_UNUSED",
altpll_component.port_clkswitch = "PORT_UNUSED",
altpll_component.port_configupdate = "PORT_UNUSED",
altpll_component.port_fbin = "PORT_UNUSED",
altpll_component.port_inclk0 = "PORT_USED",
altpll_component.port_inclk1 = "PORT_UNUSED",
altpll_component.port_locked = "PORT_USED",
altpll_component.port_pfdena = "PORT_UNUSED",
altpll_component.port_phasecounterselect = "PORT_UNUSED",
altpll_component.port_phasedone = "PORT_UNUSED",
altpll_component.port_phasestep = "PORT_UNUSED",
altpll_component.port_phaseupdown = "PORT_UNUSED",
altpll_component.port_pllena = "PORT_UNUSED",
altpll_component.port_scanaclr = "PORT_UNUSED",
altpll_component.port_scanclk = "PORT_UNUSED",
altpll_component.port_scanclkena = "PORT_UNUSED",
altpll_component.port_scandata = "PORT_UNUSED",
altpll_component.port_scandataout = "PORT_UNUSED",
altpll_component.port_scandone = "PORT_UNUSED",
altpll_component.port_scanread = "PORT_UNUSED",
altpll_component.port_scanwrite = "PORT_UNUSED",
altpll_component.port_clk0 = "PORT_USED",
altpll_component.port_clk1 = "PORT_USED",
altpll_component.port_clk2 = "PORT_USED",
altpll_component.port_clk3 = "PORT_USED",
altpll_component.port_clk4 = "PORT_USED",
altpll_component.port_clk5 = "PORT_UNUSED",
altpll_component.port_clkena0 = "PORT_UNUSED",
altpll_component.port_clkena1 = "PORT_UNUSED",
altpll_component.port_clkena2 = "PORT_UNUSED",
altpll_component.port_clkena3 = "PORT_UNUSED",
altpll_component.port_clkena4 = "PORT_UNUSED",
altpll_component.port_clkena5 = "PORT_UNUSED",
altpll_component.port_extclk0 = "PORT_UNUSED",
altpll_component.port_extclk1 = "PORT_UNUSED",
altpll_component.port_extclk2 = "PORT_UNUSED",
altpll_component.port_extclk3 = "PORT_UNUSED",
altpll_component.self_reset_on_loss_lock = "OFF",
altpll_component.width_clock = 5;
endmodule
`timescale 1ps/1ps
module My_PLL_tb();
reg clk; // clk.clk
reg rst; // areset.rst
wire outclk_0; // outclk0.clk
wire outclk_1; // outclk1.clk
wire outclk_2; // outclk2.clk
wire outclk_3; // outclk3.clk
wire outclk_4; // outclk4.clk
wire locked; // locked.export
initial clk = 0;
always #5 clk = ~clk;
initial begin
rst = 0;
#100;
rst = 1;
#100;
$stop;
end
My_PLL My_PLL_tb_u1(
.clk (clk), // clk.clk
.rst (rst), // areset.rst
.outclk_0(outclk_0), // outclk0.clk
.outclk_1(outclk_1), // outclk1.clk
.outclk_2(outclk_2), // outclk2.clk
.outclk_3(outclk_3), // outclk3.clk
.outclk_4(outclk_4), // outclk4.clk
.locked (locked) //locked.export
);
endmodule
如上图所示,PLL模块有两个输入,分别为clk和rst。c为PLL输出,locked为输出时钟使能信号,高电平时表示输出有效。根据波形图可知,程序设计基本符合预期。
1. 使用Modelsim进行仿真时出现错误:Instantiation of ‘****’ failed. The design unit was not found。参考自:https://blog.csdn.net/qq_52450571/article/details/125765689
原因:Modelsim未导入IP核。
解决方法:设置testbench的时候需要将除被仿真的主体文件之外的其他模块,比如IP核、仿真模型等也添加进去。
2. altpll模块找不到。
原因:未导入altpll.v
解决方法:同上。
3. 使用PLL进行led控制时,仿真波形显示不正常,无期望输出波形。
原因:信号例化错误。
解决方法:PLL中的(areset)rst信号是高电平有效的。在例化时须将rst取反。
.areset(~Rst_n)
4. 语法错误
解决方法:自行校正。