Augus

8.菜鸟初入FPGA之PLL的简单实用

1
阅读(4031)

    此次笔记记录的是 FPGA 片内时钟管理单元 PLL,该单元可以实现系统时钟的分频、 倍频,是 FPGA 设计开发必备组件之一
            

    在FPGA系统设计中,几乎所有地方都可以用到PLL,也有些地方是非用到PLL不可。

         在某些对系统时钟频率没有固定要求的系统中,外部晶振输入的时钟可以直接作为逻辑驱动时钟,也可以通过PLL将该时钟进行降频,以得到较低的工作时钟,在不影响系统功能实现的前提下降低系统功耗。

         另外一些应用,则必须在指定频率的时钟信号下才能正常工作,常见于通信协议类应用,如以太网、USBPCIE等等,在这些应用中,必须使用指定频率的时钟信号,如果没有刚好满足条件的外部时钟源,则必须通过片内PLL生成相应的时钟信号来进行驱动。在某些实时性要求较高的应用中,如数字信号处理,图像处理等等,提高系统工作时钟能够提升系统的性能,这一类应用中,也往往使用PLL进行倍频和分频,以得到较高频率的时钟,用以提升系统整体性能。

         再有一个常见的应用就是生成两路频率相同,相位不同的时钟供SDRAM控制器和SDRAM芯片使用。根据SDRAM芯片的工作原理,SDRAM控制器的工作时钟和SDRAM芯片的工作时钟需要保持180°的相位差才能保证正确的读写数据。所以这里就可以使用PLL的相位控制功能来产生两路相位不同的时钟,以分别供控制器和SDRAM芯片使用。


下面我们看一下实用PLL设置不同频率控制led闪烁例程:

//Top.v
module PLL_LED(     
	Clk,
	Rst_n,
	LED
);

	input Clk;
	input Rst_n;
	output [3:0]LED;
	
	wire c0;	//25M
	wire c1;	//75M
	wire c2;	//100M
	
	wire locked;
	
	pll pll(
		.areset(~Rst_n),
		.inclk0(Clk),
		.c0(c0),
		.c1(c1),
		.c2(c2),
		.locked(locked)
	);
	
	counter
	#(
		.CNT_MAX(25'd24_999_999)    ///////////////////
	)
	counter0(
		.Clk(c0),
		.Rst_n(Rst_n),
		.led(LED[0])
	);
	
	counter
	#(
		.CNT_MAX(25'd24_999_999)     ///////////////////
	)
	counter1(
		.Clk(c1),
		.Rst_n(Rst_n),
		.led(LED[1])
	);

	counter	
	#(
		.CNT_MAX(25'd24_999_999)      ///////////////////
	)
	counter2(
		.Clk(c2),
		.Rst_n(Rst_n),
		.led(LED[2])
	);
	
	counter
	#(
		.CNT_MAX(25'd24_999_999)      ///////////////////
	)
	counter3(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.led(LED[3])
	);

endmodule

module counter(Clk,Rst_n,led);

	input Clk;	//系统时钟
	input Rst_n;	//全局复位,低电平复位
	
	output reg led;	//led输出
	
	reg [24:0]cnt;	//定义计数器寄存器
	
	parameter CNT_MAX = 25'd24_999_999;

//计数器计数进程	
	always@(posedge Clk or negedge Rst_n)
	if(Rst_n == 1'b0)
		cnt <= 25'd0;
	else if(cnt == CNT_MAX)
		cnt <= 25'd0;
	else
		cnt <= cnt + 1'b1;

//led输出控制进程
	always@(posedge Clk or negedge Rst_n)
	if(Rst_n == 1'b0)
		led <= 1'b1;
	else if(cnt == CNT_MAX)
		led <= ~led;
	else
		led <= led;

endmodule

//`tb
`timescale 1ns/1ps
`define clk_period 20

module PLL_LED_tb;
	reg Clk;
	reg Rst_n;

	wire [3:0]LED;
	
	PLL_LED PLL_LED(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.LED(LED)
	);
	
	 ///////////////////
	defparam PLL_LED.counter0.CNT_MAX = 24;
	defparam PLL_LED.counter1.CNT_MAX = 24;
	defparam PLL_LED.counter2.CNT_MAX = 24;
	defparam PLL_LED.counter3.CNT_MAX = 24;
	
	initial Clk = 1;
	always #(`clk_period/2)Clk = ~Clk;

	initial begin
		Rst_n = 1'b0;
		#(`clk_period * 20 + 1);
		Rst_n = 1'b1;
		#(`clk_period * 2000);
		$stop;
	end

endmodule

   仿真波形图:

2016-03-29_000210.jpg