特别注意:在PFGA中能用全局时钟资源clk就用全局时钟资源,尽量避免用这种分频出来的时钟作为时钟源,因为这种分频出来的时钟走的不是快速通道,信号到别的寄存器这一段路程会产生相对较大的延迟。
//这部分代码有错,仅用于分析,不可用于仿真
module division( input clk, input rst_n, output sclk //分频后的时钟 ); paramater N = SYS_CLK/SCLK ; //N表示几分频系数,当前系统时钟频率/所需模块时钟频率 //reg define reg [7:0] cnt //仅支持2 ~ 128 的偶数分频 //cnt计数模块 always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 1'd0; esle if(cnt < N - 1) //注意这里是个小于符号,计数器cnt进行0--N-1循环计数 cnt <= cnt + 1'b1; else cnt <= 1'd0; end //分频模块 always@(posedge clk or negedge rst_n)begin if(!rst_n) sclk <= 1'd1; else if(cnt == N >> 1) //注意N>>1代表M向右平移一位,即N/2; N >> 2代表M向右平移两位,即N/4;......... sclk <= 1'b0; else if(cnt == 1'b0) sclk <= 1'b1; else sclk <= sclk ; end //假如用产生的sclk信号作为触发信号去驱动别的模块,则会产生一定的延迟。避免用这种分频出来的时钟作为时钟源,因为这种分频出来的时钟走的不是快速通道,信号到别的寄存器这一段路程会产生相对较大的延迟。 always@(posedge sclk or negedge rst_n)begin if(!rst_n) sclk <= 1'd1; else if(cnt == ......) ....; else if(cnt == ......) ....; else ....; end //上面的always块程序会产生延迟,应该用以下的形式 always@(posedge clk )begin case(cnt) 0 : sclk <= 1'b0 ; 1 : .... 2 : sclk <= 1'b1; ... ... //根据cnt计数器来变换sclk和执行其它条件 ... end endmodule
分频器设计:
以下为分频器设计代码:
当分频系数N = sys_clk/scl_clk(系统系统时钟频率/模块所需时钟频率)为偶数时:(只能实现2,4,6,8......128分频)
/**********************.v文件************************/ module Division( input clk, input rst_n, output reg sclk //分频后的时钟 ); parameter SYS_CLK = 25_000_000; parameter SCLK = 12500_000; parameter N = SYS_CLK/SCLK; //N表示几分频系数,当前系统时钟频率/所需模块时钟频率 //reg define reg [7:0] cnt; //仅支持2 ~ 128 的偶数分频 //cnt计数模块 always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 8'd0; else if(cnt < N - 1) //注意这里是个小于符号,计数器cnt进行0--N-1循环计数 cnt <= cnt + 1'b1; else cnt <= 8'd0; end //分频模块 always@(posedge clk or negedge rst_n)begin if(!rst_n) sclk <= 1'b1; else if(cnt == (N >> 1)) //注意N>>1代表N向右平移一位,即N/2; N >> 2代表N向右平移两位,即N/4;......... sclk <= 1'b0; else if(cnt == 8'd0) sclk <= 1'b1; else sclk <= sclk; end endmodule /*************************tb文件***********************/ `timescale 1ns/1ps `define period_clk 20 module tb; reg sys_clk; reg sys_rst_n; wire sclk; /*---------------例化DDS模块------------------*/ Division #(.N(2)//, // .SYS_CLK(25_000_000) ) Division( .clk(sys_clk), .rst_n(sys_rst_n), .sclk(sclk) ); initial sys_clk = 1'b1; always #(`period_clk/2) sys_clk = ~sys_clk; initial begin sys_rst_n = 1'b0; #10; sys_rst_n = 1'b1; #1_000; $stop; end endmodule
当N=2,分频系数为2时下的仿真波形:
计数器设计:
上图为cnt计数器计数N = 5个数的波形;即 cnt < N - 1 ;
计数器设计时应该注意的事情:假如要计数N个数:
always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 1'd0; esle if(cnt < N - 1) //注意这里是个小于符号 cnt <= cnt + 1'b1; else cnt <= 1'd0; end
假如在计数满N个数时,需要执行别的事情:
always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 1'd0; esle if(cnt < N - 1) //注意这里是个小于符号 cnt <= cnt + 1'b1; else cnt <= 1'd0; end always@(posedge clk or negedge rst_n)begin if(!rst_n) ..... esle if(cnt == N - 1) ..... else ..... end
当分频系数N = sys_clk/scl_clk(系统系统时钟频率/模块所需时钟频率)为奇数时: