verilog时钟分频设计(来源:http://blog.csdn.net/moon9999/article/details/75020355)

1.偶分频模块设计

偶分频意思是时钟模块设计最为简单。首先得到分频系数M和计数器值N。

M = 时钟输入频率 / 时钟输出频率

N = M / 2

如输入时钟为50M,输出时钟为25M,则M=2,N=1。偶分频则意味着M为偶数。

以M=4,N=2为例,我们希望得到的输出时钟时序如下:


因此只需要将counter以clk_in为时钟驱动计数,当counter = (N-1)时,clk_out翻转即可。

verilog代码如下,其中WIDTH为(N的位宽-1):

[plain]  view plain  copy
  1. module time_adv_even #(  
  2. parameter N = 2,  
  3.     WIDTH = 7  
  4. )  
  5. (  
  6.     input clk,  
  7.     input rst,  
  8.     output reg clk_out  
  9.     );  
  10.   
  11. reg [WIDTH:0]counter;  
  12. always @(posedge clk or posedge rst) begin  
  13.     if (rst) begin  
  14.         // reset  
  15.         counter <= 0;  
  16.     end  
  17.     else if (counter == N-1) begin  
  18.         counter <= 0;  
  19.     end  
  20.     else begin  
  21.         counter <= counter + 1;  
  22.     end  
  23. end  
  24.   
  25. always @(posedge clk or posedge rst) begin  
  26.     if (rst) begin  
  27.         // reset  
  28.         clk_out <= 0;  
  29.     end  
  30.     else if (counter == N-1) begin  
  31.         clk_out <= !clk_out;  
  32.     end  
  33. end  
  34.   
  35. endmodule  

testbench测试8分频即N=4,ISE仿真结果如下:



2.奇分频模块设计

奇分频需要通过两个时钟共同得到。首先得到分频系数M和计数器值N。

M = 时钟输入频率 / 时钟输出频率

N = (M-1) / 2

如输入时钟为50M,输出时钟为10M,则M=5,N=2。奇分频则意味着M为奇数。

以M=5,N=2为例,我们希望得到的输出时钟时序如下:


其中clk_out为最终输出时钟,clk_out1和clk_out2为辅助时钟生成。

计数器counter由0技术至(M-1)。

clk_out1在在clk_in的上升延跳变,条件是counter==(N-1)或(M-1)。

clk_out2在在clk_in的下降延跳变,条件是counter==(N-1)或(M-1)。

之后clk_out = clk_out1 & clk_out2即可得到M分频的时钟。

verilog代码如下,其中WIDTH为(N的位宽-1):

[plain]  view plain  copy
  1. module time_adv_odd #(  
  2. parameter N = 2,  
  3.     WIDTH = 7  
  4.      )(  
  5.     input clk,  
  6.     input rst,  
  7.     output clk_out  
  8.     );  
  9.   
  10. reg [WIDTH:0]counter;  
  11. always @(posedge clk or posedge rst) begin  
  12.     if (rst) begin  
  13.         // reset  
  14.         counter <= 0;  
  15.     end  
  16.     else if (counter == (N << 1)) begin  
  17.         counter <= 0;  
  18.     end  
  19.     else begin  
  20.         counter <= counter + 1;  
  21.     end  
  22. end  
  23.   
  24. reg clk_out1;  
  25. always @(posedge clk or posedge rst) begin  
  26.     if (rst) begin  
  27.         // reset  
  28.         clk_out1 <= 0;  
  29.     end  
  30.     else if (counter == N-1) begin  
  31.         clk_out1 <= !clk_out1;  
  32.     end  
  33.     else if (counter == (N << 1)) begin  
  34.         clk_out1 <= !clk_out1;  
  35.     end  
  36. end  
  37.   
  38. reg clk_out2;  
  39. always @(negedge clk or posedge rst) begin  
  40.     if (rst) begin  
  41.         // reset  
  42.         clk_out2 <= 0;  
  43.     end  
  44.     else if (counter == N-1) begin  
  45.         clk_out2 <= !clk_out2;  
  46.     end  
  47.     else if (counter == (N << 1)) begin  
  48.         clk_out2 <= !clk_out2;  
  49.     end  
  50. end  
  51.   
  52. assign clk_out = clk_out1 & clk_out2;  
  53. endmodule  
testbench测试9分频即N=4,ISE仿真结果如下:



3.半分频模块设计

半分频即2.5分频等,设计最为复杂。首先得到分频系数M:

M = 时钟输入频率 / 时钟输出频率

如输入为50M,输入为20M则分频系数为2.5。此次设计未能完成占空比为50%的半分频。

以M=2.5为例,我们希望得到的输出时钟时序如下:


可以看出输出时钟的两个上升沿之间为2.5个输入时钟周期。

设计的关键在于信号维持半个周期的处理,因此引入了辅助信号clk_cnt,clk_vld。

clk_vld信号受到clk_out的驱动,检测到clk_out的上升沿时,信号翻转。

clk_cnt信号受到clk_in驱动,受clk_vld控制,当clk_vld==0时,clk_cnt = clk_in;当clk_vld==1时,clk_cnt = !clk_in。

counter信号受clk_cnt驱动,计数(M-0.5)时归零。

clk_out信号受clk_cnt驱动,当counter == (M-1.5)或counter == (M-0.5)时翻转。(此处在仿真时做了改变,见下方)

M=2.5时,时序分析如下:

第一步:reset之后,clk_vld==0,clk_cnt = clk_in,counter由0开始计数;

第二步:counter == 1时,clk_out在clk_cnt的上升沿处跳变为1,引起clk_vld->1,进而clk_cnt = !clk_in,这意味着clk_cnt立即由1归为0;

第三步:半个周期后,clk_cnt 在此迎来上升沿,此时counter == 2,clk_out在clk_cnt的上升沿处跳变为0,counter也归0;(实现了信号维持半个周期)

第四步:继续正常计数,counter == 1时,clk_out在clk_cnt的上升沿处跳变为1,引起clk_vld->0,进而clk_cnt = clk_in,这意味着clk_cnt立即由1归为0;

第五步:重复至第一步。


然而在有一次的电路仿真中,可能受到仿真工具时钟采样影响,调整为

当counter == (M-0.5)或counter == 0时翻转

实现了正确的时钟分频。因此该值可能需要根据工具和开发板调整,或者说这样的设计是不可靠的,当然了如果需要半分频时候最好还是通过pll实现吧。

理论上是当counter == (M-0.5)或counter == (M-1.5)时翻转没错,给出的代码和波形也是这样的

verilog代码如下,参数M实际为分频系数-0.5(即3.5->3),WIDTH为(M的位宽-1):

[plain]  view plain  copy
  1. module time_adv_half #(  
  2.     parameter M = 2,  
  3.         WIDTH = 7  
  4. )(  
  5.     input clk,  
  6.     input rst,  
  7.     output reg clk_out  
  8.     );  
  9.   
  10. wire clk_cnt;  
  11. assign clk_cnt = (clk_vld) ? !clk : clk;  
  12.   
  13. reg [WIDTH : 0]counter;  
  14. always @(posedge clk_cnt or posedge rst) begin  
  15.     if (rst) begin  
  16.         // reset  
  17.         counter <= 0;  
  18.     end  
  19.     else if (counter == M) begin  
  20.         counter <= 0;  
  21.     end  
  22.     else begin  
  23.         counter <= counter + 1;  
  24.     end  
  25. end  
  26.   
  27. reg clk_vld;  
  28. always @(posedge clk_out or posedge rst) begin  
  29.     if (rst) begin  
  30.         // reset  
  31.         clk_vld <= 0;  
  32.     end  
  33.     else begin  
  34.         clk_vld <= !clk_vld;  
  35.     end  
  36. end  
  37.   
  38. always @(posedge clk_cnt or posedge rst) begin  
  39.     if (rst) begin  
  40.         // reset  
  41.         clk_out <= 0;  
  42.     end  
  43.     else if (counter == M-1) begin  
  44.         clk_out <= !clk_out;  
  45.     end  
  46.     else if (counter == M) begin  
  47.         clk_out <= !clk_out;  
  48.     end  
  49. end  
  50.   
  51. endmodule  
M=3时候的仿真波形如下:


可以看出clk_out两个上升沿之间为3.5个输入时钟周期。


附:testbench

[plain]  view plain  copy
  1.  `timescale 1 ns / 1 ps  
  2. module TEST_gate;  
  3.     reg clk, rst;  
  4.     wire clk_out_even, clk_out_odd, clk_out_half;  
  5.       
  6.     initial begin    
  7.         clk = 1'b0;    
  8.         forever #10 clk = ~clk;    
  9.     end  
  10.       
  11.     initial begin    
  12.         rst = 1'b0;    
  13.         #2 rst = 1'b1;   
  14.         #9 rst = 1'b0;   
  15.     end  
  16.   
  17.     time_adv_even #(  
  18.        .N(4)  
  19.         ,.WIDTH(5)  
  20.        )u0  
  21.         (  
  22.         .clk        (clk)  
  23.         ,.rst       (rst)  
  24.         ,.clk_out   (clk_out_even)  
  25.         );  
  26.           
  27.         time_adv_odd #(  
  28.        .N(4)  
  29.         ,.WIDTH(5)  
  30.        )u1  
  31.         (  
  32.         .clk        (clk)  
  33.         ,.rst       (rst)  
  34.         ,.clk_out   (clk_out_odd)  
  35.         );  
  36.           
  37.         time_adv_half #(  
  38.        .M(3)  
  39.         ,.WIDTH(5)  
  40.        )u2  
  41.         (  
  42.         .clk        (clk)  
  43.         ,.rst       (rst)  
  44.         ,.clk_out   (clk_out_half)  
  45.         );  
  46. endmodule  
波形
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值