此次笔记记录的是 FPGA 片内时钟管理单元 PLL,该单元可以实现系统时钟的分频、 倍频,是 FPGA 设计开发必备组件之一
在FPGA系统设计中,几乎所有地方都可以用到PLL,也有些地方是非用到PLL不可。
在某些对系统时钟频率没有固定要求的系统中,外部晶振输入的时钟可以直接作为逻辑驱动时钟,也可以通过PLL将该时钟进行降频,以得到较低的工作时钟,在不影响系统功能实现的前提下降低系统功耗。
另外一些应用,则必须在指定频率的时钟信号下才能正常工作,常见于通信协议类应用,如以太网、USB、PCIE等等,在这些应用中,必须使用指定频率的时钟信号,如果没有刚好满足条件的外部时钟源,则必须通过片内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
仿真波形图:
文章评论(0条评论)
登录后参与讨论