天天看點

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;

[email protected](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,然後将兩個信号進行或運算即可。如下圖所示的信号。

FPGA任意偶數、奇數、小數分頻器一、偶數分頻器二、奇數分頻三、任意小數分頻

奇數分頻

奇數分頻的代碼:

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;

[email protected](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


[email protected](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個時鐘輸出,則有:

FPGA任意偶數、奇數、小數分頻器一、偶數分頻器二、奇數分頻三、任意小數分頻

其中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個輸出時鐘):

FPGA任意偶數、奇數、小數分頻器一、偶數分頻器二、奇數分頻三、任意小數分頻

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;


[email protected](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;

[email protected](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