FPGA PLL锁相环控制LED闪烁程序设计与仿真

开发软件:Quartus 13.0    开发组件:Cyclone IV EP4CE10F17C8   仿真:Modelsim 10.1d

文章目录

  • PLL锁相环
  • 一、程序设计
  • 二、仿真测试
  • 问题总结


PLL锁相环

PLL:Phase Locked Loop(锁相环)是一种反馈控制电路,其特点是利用外部输入的参考信号控制环路内部震荡信号的频率和相位。它可以将FPGA的系统时钟转化所需的倍频及相位时钟,是IC开发中很重要的一个部分。PLL的工作原理图如下图所示:

FPGA PLL锁相环控制LED闪烁程序设计与仿真_第1张图片

锁相环通常由鉴相器(FPD,Frequency Phase Detector)、滤波器(LF,Loop Filter)和压控振荡器(VCO,Voltage Controlled Oscillator)3部分组成前向通路,由VCO分频器组成频率相位的反馈通路。PLL的组成结构如下图所示:

FPGA PLL锁相环控制LED闪烁程序设计与仿真_第2张图片

 摘自: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仿真文件、仿真。

代码如下:

My_PLL.v (例化PLL IP核的顶层文件)
`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
PLL_ip.v (从Quartus中调用的PLL IP核)
`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

二、仿真测试

My_PLL_tb.v (测试程序)
`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 
仿真波形

FPGA PLL锁相环控制LED闪烁程序设计与仿真_第3张图片

 逻辑电路FPGA PLL锁相环控制LED闪烁程序设计与仿真_第4张图片

如上图所示,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. 语法错误

解决方法:自行校正。

你可能感兴趣的:(FPGA,fpga开发,嵌入式硬件)