christ0127

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

在学习FPGA的过程中,最简单最基本的实验应该就是分频器了,
同时分频器也是FPGA设计中使用频率非常高的基本设计之一,
尽管在芯片厂家提供的IDE中集成了锁相环IP
altera 的PLLXilinx ISE的DLL或者vivado中的clock来进行时钟的分频,倍频以及相移。
但是对于时钟要求不高的逻辑,通过语言进行时钟的分频相移显得十分方便,
这种方法可以节省芯片内部的锁相环资源,再者,通过语言设计进行时钟分频,可以锻炼我们对verilog的熟练和理解程度。

  • 偶数倍分频:实现起来比较简单,这里略过;

  • 奇数倍分频

    如果不要求占空比为50%的话,也比较容易实现,
    如进行三分频,通过待分频时钟上升沿触发计数器进行模三计数,
    当计数器计数到邻近值进行两次翻转,比如可以在计数器计数到1时,
    输出时钟进行翻转,计数到2时再次进行翻转。
    即在计数值在邻近的1和2进行了两次翻转。
    这样实现的三分频占空比为1/3或者2/3。

    对于实现占空比为50%的N倍奇数分频,我们可以分解为两个通道:

    • 上升沿触发进行模N计数,计数选定到某一个值进行输出时钟翻转,
      然后经过(N-1)/2再次进行翻转得到一个占空比为非50%奇数N分频时钟
    • 下降沿触发进行模N计数,到和上升沿触发输出时钟翻转选定值相同值时,
      进行输出时钟时钟翻转,同样经过(N-1)/2时,
      输出时钟再次翻转生成占空比非50%的奇数N分频时钟

    将这两个占空比非50%的N分频时钟或运算,得到占空比为50%的奇数n分频时钟

    具体例子:5分频等占空比,可以通过待分频时钟下降沿和上升沿触发0~4计数,

    • 对于待分频时钟的上升沿,当计数器cnt1计数到1时,
      clk_p翻转;当计数器计数到3(1 + (5 - 1) / 2 = 3)时,clk_p再次反转;
    • 对于待分频时钟的下降沿,当计数器cnt2计数到1时,
      clk_n翻转;当计数器计数到3(1 + (5 - 1) / 2 = 3)时,clk_n再次反转;
    • 然后下降沿产生的5分频时钟和上升沿产生的5分频时钟进行运算,
      即可得到占空比为50%的N分频时钟。

    这种方法可以实现任意的奇数分频。

下面给出5分频的具体代码:

`timescale 1ns/1ps 

module CLK_DIV5(
    input   clk_i,
    input   rst_n,
    output  clk_o
    );
 
    reg [2:0] cnt1,cnt2;
    reg clk_p,clk_n;
           
//*********************
//MAIN CORE
//*********************        
always @(posedge clk_i,negedge rst_n)
    if(!rst_n) begin
        cnt1 <= 3'b0;
        clk_p <= 1'b0;
    end 
    else begin
        if(cnt1 == 3'b100) begin
            cnt1 <= 3'b0;
            clk_p <= clk_p;
        end
        else begin
            cnt1 <= cnt1 + 1'b1;
            if(cnt1 == 3'b1 || cnt1 == 3'b11)
                clk_p <= ~clk_p;
        end
    end

always @(negedge clk_i,negedge rst_n)
    if(!rst_n) begin
        cnt2 <= 3'b0;
        clk_n <= 1'b0;
    end 
    else begin
        if(cnt2 == 3'b100) begin
            cnt2 <= 3'b0;
            clk_n <= clk_n;
        end
        else begin
            cnt2 <= cnt2 + 1'b1;
            if(cnt2 == 3'b1 || cnt2 == 3'b11)
                clk_n <= ~clk_n;
        end
    end
    
    assign clk_o = clk_p | clk_n;
endmodule

测试激励模块:

`timescale 1ns/1ps 

module TB_TOP;

    reg   rst_n  ;
    reg   clk    ;

   CLK_DIV5 U_CLK_DIV5(
        .clk_i(clk),
        .rst_n(rst_n),
        .clk_o(clk_o)
    );
    
//*********************
//MAIN CORE
//*********************        
    initial begin 
        rst_n  =1'b1;
        clk    =1'b0;
        
        #5
        rst_n  = 1'b0;
        #5
        rst_n  = 1'b1;
 
        #500
        $finish;     
    end 
    
    always #1 clk = ~clk;
  
endmodule

modelsim仿真图:

posted on 2016-05-18 16:36  christ0127  阅读(9863)  评论(0编辑  收藏  举报