FPGA任意偶数、奇数、小数分频器

一、偶数分频器

 

偶数分频器原理不在介绍,直接给出verilog代码。


module even_div
#(
parameter		DIV		=	4,
parameter		WIDTH	=	8

)(
	input					clk,
	input					en,
	input					rst_n,
	
	output	reg				locked,
	output	reg				clk_out
);

reg	[WIDTH-1:0]		div_reg	=	DIV;

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		locked	<=	1'b0;
		clk_out	<=	1'b0;
		div_reg	<=	0;
	end
	else begin
		if(!en)begin
			locked	<=	1'b0;
			clk_out	<=	1'b0;
			div_reg	<=	0;
		end
		else begin
			//clk_out locked.
			locked	<=	1'b1;
			
			//divide counter
			if(div_reg < (DIV-1'b1))begin
				div_reg	<=	div_reg + 1'b1;
			end
			else begin
				div_reg	<=	0;
			end
			
			//According value in Divide Counter, clk_out is output 
			if(div_reg<(DIV>>1))begin
				clk_out	<=	1'b1;
			end
			else begin
				clk_out	<=	1'b0;
			end
		end	
	end
end

endmodule

二、奇数分频

如图所示,任意奇数分频器的关键在于clk_a和clk_b的实现,若能实现clk_a和clk_b,然后将两个信号进行或运算即可。clk_a和clk_b相差半个时钟周期,然后将两个信号相或即可。如下图所示的信号。

奇数分频

奇数分频的代码:

module odd_div
#(
	parameter		DIV		=	5,
	parameter		WIDTH	=	8
)
(
	input			clk,
	input			en,
	input			rst_n,
					
	output			clk_out,
	output			clk_locked
);


reg		[WIDTH-1:0]	cnt_a;

reg					clk_a;
reg					clk_b;

reg					clk_lock_a;

assign				clk_out		=	clk_a | clk_b;
assign				clk_locked	=	clk_lock_a;

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		clk_a		<=	1'b0;
		clk_lock_a	<=	1'b0;
		cnt_a		<=	0;
	end
	else begin
		if(!en)begin
			clk_a		<=	1'b0;
			clk_lock_a	<=	1'b0;
			cnt_a		<=	0;
		end
		else begin
			if(cnt_a < ((DIV-1)/2))begin
				clk_a	<=	1'b1;
			end
			else begin
				clk_a	<=	1'b0;
			end
			
			if(cnt_a < (DIV-1))
				cnt_a	<=	cnt_a + 1'b1;
			else	begin
				cnt_a	<=	0;
				clk_lock_a	<=	1'b1;
			end
		end
	end
end


always@(negedge clk)begin
	clk_b	<=	clk_a;
end


endmodule

三、任意小数分频

事实上我们不能单纯地利用FPGA实现非常精确的小数分频。所谓小数分频,我们是建立在统计学之上的。例如:5.3分频(clk_div5_3),并不是真正意义上的5.3分频,而是在一段很长的时间内满足5.3分频即可。比如在53个时钟上对应有10个时钟输出即可。我们可以这么理解:

5.3分频在5分频和6分频之间,并且在53个时钟周期上满足10个时钟输出,则有:

                                                                              \left\{ \begin{array}{l} n + m = 10\\ 5n + 6m = 53 \end{array} \right.\

其中n是5分频后的时钟个数,m是6分频后的时钟个数,总数为10;又因为一共有53个输入时钟,所以“clk_div5的个数乘5”加“clk_div6的个数乘6”的和为53。解这个方程得:n=7,m=3.也就是说我们7个clk_div5和3个clk_div6组合到一起就是统计学上的5.3分频。

同理,4.3分频,6.7分频,6.18分频也是如此。下图给出4.3分频的仿真图(输入时钟周期为20ns,刻度2为860ns,即43个时钟,期间一共有10个输出时钟):

4.3分频仿真图

4.3分频,例化了上述的偶数分频、奇数分频模块(注意参数传递的注释)。代码如下:

module decimal_div
#(
	parameter 		CNT_TOTAL	=	43,
	parameter		CNT_DIV		=	10,
	
	parameter		CNT_PREP	=	CNT_TOTAL / CNT_DIV,
	parameter		CNT_POSTP	=	CNT_PREP + 1,
	
	parameter		NUM_POST	=	CNT_TOTAL - CNT_PREP*CNT_DIV,
	parameter		NUM_PRE		=	CNT_DIV - NUM_POST,
	
	parameter		WIDTH		=	8
	
)(
	input			clk_in,
	input			en,
	input			rst_n,
	
	output	reg		locked,
	output			clk_out
);

reg		[WIDTH-1:0]	cnt_pre		=	0;//
reg		[WIDTH-1:0]	cnt_post	=	0;//
reg					cnt_clk_div	=	0;
reg					sm_en		=	1'b0;
reg					clk_out_r;


always@(posedge clk_in or negedge rst_n)begin
	if(!rst_n)begin
		locked	<=	1'b0;
		clk_out_r	<=	1'b0;
	end
	else begin
		if(!en)begin
			locked	<=	1'b0;
			clk_out_r	<=	1'b0;
		end
		else begin
			sm_en	<=	1'b1;
		end
	end
end


/*******************************
State Machine
********************************/
reg		[4:0]	state	=	4'h0;

localparam		s_0		=	4'd0;//3 div
localparam		s_1		=	4'd1;//3 div
localparam		s_2		=	4'd2;//4 div

reg				even_clk_en;
reg				odd_clk_en;
reg				switch;

wire			clk_odd;
wire			clk_even;

assign			clk_out		=	switch? clk_odd  : clk_even;

always@(negedge clk_in)begin
	case(state)
		//ideal
		s_0:begin
			if(sm_en==1'b0)begin
				state	<=	s_0;
				locked	<=	1'b0;
			end
			else begin
				locked	<=	1'b0;
				state	<=	s_1;
				
				if(CNT_PREP[0]==1'b1)
					switch	<=	1'b1;
				else
					switch	<=	1'b0;
			end
		end
		
		//div = 3
		s_1:begin
			if(cnt_pre < (NUM_PRE*CNT_PREP - 1))begin
				cnt_pre		<=	cnt_pre + 1'b1;
			end
			else begin
				cnt_pre		<=	0;
				state		<=	s_2;
				switch		<=	switch^1'b1;
			end
		end
		
		//div = 4;
		s_2:begin
			if(cnt_post < (NUM_POST*CNT_POSTP - 1))begin
				cnt_post	<=	cnt_post + 1'b1;
			end
			else begin
				cnt_post	<=	0;
				state		<=	s_1;
				switch		<=	switch^1'b1;
				locked		<=	1'b1;
			end
		end
		
		default:begin
			state	<=	s_0;
		end
	endcase
end

odd_div #(
	//decimal X.Y
	.DIV	(CNT_POSTP),//X is even, DIV=CNT_POSTP;if not DIV=CNT_PREP.
	.WIDTH	(8)
)
u_odd(
	.clk		(clk_in),
	.en			(switch),
	.rst_n		(1),
	
	.clk_out	(clk_odd),
	.clk_locked	()
);

even_div #(
	//decimal X.Y
	.DIV	(CNT_PREP),//X is odd, DIV=CNT_POSTP;if not DIV=CNT_PREP.
	.WIDTH	(8)
)
u_even(
	.clk		(clk_in),
	.en			(~switch),
	.rst_n		(1),
	
	.locked		(),
	.clk_out	(clk_even)
);

endmodule


 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值