【FPGA】 基于FPGA分频,倍频设计实现


在FPGA程序设计中使用PLL是分频和倍频最方便的选择可以生成自己想要的频率脉冲,在分频和倍频选择上也可以使用计数器来完成实现

1、分频

1.分频系数方式

module pll #(
    parameter SYS_FREQ = 26'd50_000_000,
              OUT_FREQ = 20'd500_000
)
( 
    input				clk		,
    input				rst_n	

);								 
    //参数定义			 
                        
    //中间信号定义	
    reg                     clk_500k;	 
    wire [25:0]             coef    ;
    reg  [25:0]             cnt_500k;
    assign coef = (SYS_FREQ/OUT_FREQ) >>1;


always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cnt_500k <= 26'b1;
        clk_500k <= 1'b0;
    end 
    else if(cnt_500k < coef)begin 
        cnt_500k <= cnt_500k +26'd1;
    end 
    else if(cnt_500k == coef)begin
        clk_500k <= ~clk_500k;
        cnt_500k <= 26'b1;
    end
    else begin 
        cnt_500k <= cnt_500k;
    end 
end

在这里插入图片描述
这种方式分频需要给出模块时钟频率和分频得到的时钟频率,计算除分频系数使用计数器得到自己想要的时钟频率,这种当时分频得到的时钟缺点就是有些模块时钟的频率和得到的时钟频率计算除法会取整,误差太明显了,这种方式用来计算串口的波特率还是可以的,毕竟串口一次传输一字节的数据不会持续太久。

2.偶分频

2分频

module pll
( 
    input				clk		,
    input				rst_n	

);								 
    //参数定义			 
     parameter   num = 8'd2;                   
    //中间信号定义	
    wire [7:0]              num_r       ;
    reg                     clk_out     ;
    reg  [7:0]              cnt         ;
    
assign  num_r = num>>1;

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        clk_out <= 1'b0;
        cnt <= 8'd1;
    end 
    else if(cnt == num_r)begin
        clk_out <= ~clk_out;
        cnt <= 8'd1;
    end
    else if(cnt <= num_r)begin
        cnt <= cnt+8'd1;
    end
    else begin 
        clk_out <= clk_out;
        cnt <= cnt;
    end 
end


                        
endmodule

在这里插入图片描述

2.奇分频

7分频

module pll
( 
    input				clk		,
    input				rst_n	

);								 
    //参数定义			 
     parameter   num = 8'd7;                   
    //中间信号定义	
    wire [7:0]              num_r       ;
    reg                     clk_p       ;
    reg                     clk_n       ;
    wire                    clk_out     ;
    reg  [7:0]              cnt1        ;
    reg  [7:0]              cnt2        ;
    
assign  num_r = num>>1;

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        clk_p <= 1'b0;
        cnt1 <= 8'd1;
    end 
    else if(cnt1 <= num)begin
        cnt1 <= cnt1+8'd1;
    if(cnt1 == num_r || cnt1 == num)begin
        clk_p <= ~clk_p;
        if(cnt1 == num)
        cnt1 <= 8'd1;
        else
        ;
    end
    end
    else begin 
        clk_p <= clk_p;
        cnt1 <= cnt1;
    end 
end

always @(negedge clk )begin 
    if(!rst_n)begin
        clk_n <= 1'b0;
        cnt2 <= 8'd1;
    end 

    else if(cnt2 <= num)begin
     cnt2 <= cnt2+8'd1;
    if(cnt2 == num_r || cnt2 == num )begin
        clk_n <= ~clk_n;
        if(cnt2 == num)
        cnt2 <= 8'd1;
        else
        ;
    end
    end
    else begin 
        cnt2 <= cnt2;
        clk_n <= clk_n;
    end 
end

assign clk_out =  clk_p & clk_n;


                        
endmodule

在这里插入图片描述

2、倍频

建议还是使用pll,信号的改变是根据时钟的上升沿或下降沿产生的,将一个周期的时钟分为两个周期就相当于变化四次,但是一个周期时钟就上升沿或下降沿我不知到怎么去倍频,网上也有使用组合逻辑异或去倍频,我也试过,这种方式它产生变化后会马上返回之前的状态,保持不到一个时钟的四分之一,反正我没成功,要么就是用timescale 设置精度单位,但这种写法太不实际了也不建议,还是用pll,不然设计pll来干什么的麻,还有就是最近使用国产FPGA,用了高云、易灵思平台,因该还要接触复旦微,发现这些频台的的pll 都有误差,国产的平台都挺麻烦的,可能是自己使用不熟,还有就是易灵思的软件运行太慢,容易未响应,但易灵思FAE、工程师还可以的刚晚上11.了还打电话回我问题。

3、tb程序

`timescale 1ns/1ns
                
module pll_tb();
//激励信号定义 
reg				tb_clk  	;
reg				tb_rst_n	;

                                      
//时钟周期参数定义					        
    parameter		CLOCK_CYCLE = 20;    
                                          
pll u_pll(			      
.clk			(tb_clk			),			      
.rst_n		    (tb_rst_n		)		      			      
);
//产生时钟							       		
initial 		tb_clk = 1'b0;		       		
always #(CLOCK_CYCLE/2) tb_clk = ~tb_clk;  		
                                                
//产生激励							       		
initial  begin						       		
    tb_rst_n = 1'b1;																
    #(CLOCK_CYCLE*2);				            
    tb_rst_n = 1'b0;							
    #(CLOCK_CYCLE*20);				            
    tb_rst_n = 1'b1;							
                                                
                                                
                                                
end 									       	
endmodule 	
### FPGA倍频实现方法与原理 #### 使用时钟分频器和计数器实现倍频 一种常见的倍频实现方式是利用简单的时钟分频器加计数器来完成。这种方法的核心在于通过对输入时钟信号进行计数操作,从而生成更高频率的输出时钟信号[^1]。 以下是基于Verilog语言的一个基本倍频实现示例代码: ```verilog module doubler_clk ( input wire clk_in, output reg clk_out ); reg [1:0] counter; always @(posedge clk_in or negedge clk_in) begin if (counter == 2'b10) begin counter <= 2'b00; clk_out <= ~clk_out; // Toggle the clock output on every second edge. end else begin counter <= counter + 1'b1; end end endmodule ``` 上述代码展示了如何通过计数器翻转输出时钟信号的状态以实现两倍于输入时钟频率的效果。 #### 利用PLL(Phase-Locked Loop)实现倍频 另一种更为精确且广泛使用的倍频技术是借助FPGA内部集成的锁相环(PLL)。PLL是一种能够稳定地跟踪并调整输出信号相对于参考信号之间关系的电子电路。它不仅可以用来倍频还可以用于分频以及调节相位等多种用途[^3]。 Cyclone IV 和 Cyclone 10 LP 系列器件最多可以提供四个这样的PLL模块(某些型号可能只有两个),这些模块允许设计师根据需求配置不同的倍率因子来获得所需的高频时钟源。 下面是一段简化版使用Altera Quartus工具设置PLL参数的例子: ```tcl set_instance_parameter_value pll_inst {areset} {0} set_instance_parameter_value pll_inst {fbmult} {8} ;# Feedback Multiplier Value set_instance_parameter_value pll_inst {inclk0_input_frequency} {50000000} set_instance_parameter_value pll_inst {operation_mode} {"NORMAL"} ... ``` 在此脚本片段里设置了反馈乘法系数为8意味着如果原始输入时钟为50MHz那么理论上可以获得高达400MHz的新时钟信号。 #### 锁相环的具体工作流程概述 当深入探讨PLL的实际工作机制时会发现其中涉及到了复杂的模拟与数字混合运算过程。例如,在鉴相环节部分采用了特定算法减少计算量的同时保持精度;具体来说就是将原本需要大量资源消耗的大规模乘法替换成了仅需少量额外逻辑门就能完成的小型化符号判断及异或操作[^4]。 最终经过一系列优化后的方案既满足了性能指标又兼顾到实际应用环境下的成本考量因素。 ### 结论 综上所述,无论是采用基础组合逻辑还是调用高级IP核的方式都可以很好地解决FPGAs上的倍频问题。对于初学者而言掌握前者较为容易理解同时也具备一定的灵活性;而对于追求极致效能或者面对更复杂应用场景则推荐后者即充分利用现代开发平台所提供的强大功能组件如PLL等来进行高效的设计实践[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值