數字電路奇偶分頻器設計


參考博文:https://www.cnblogs.com/mingmingruyue99/p/7202000.html

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):

 

module time_adv_even #(
parameter N = 2,
	WIDTH = 7
)
(
    input clk,
    input rst,
    output reg clk_out
    );

reg [WIDTH:0]counter;
always @(posedge clk or posedge rst) begin
	if (rst) begin
		// reset
		counter <= 0;
	end
	else if (counter == N-1) begin
		counter <= 0;
	end
	else begin
		counter <= counter + 1;
	end
end

always @(posedge clk or posedge rst) begin
	if (rst) begin
		// reset
		clk_out <= 0;
	end
	else if (counter == N-1) begin
		clk_out <= !clk_out;
	end
end

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):

 

module time_adv_odd #(
parameter N = 2,
	WIDTH = 7
	 )(
    input clk,
    input rst,
    output clk_out
    );

reg [WIDTH:0]counter;
always @(posedge clk or posedge rst) begin
	if (rst) begin
		// reset
		counter <= 0;
	end
	else if (counter == (N << 1)) begin
		counter <= 0;
	end
	else begin
		counter <= counter + 1;
	end
end

reg clk_out1;
always @(posedge clk or posedge rst) begin
	if (rst) begin
		// reset
		clk_out1 <= 0;
	end
	else if (counter == N-1) begin
		clk_out1 <= !clk_out1;
	end
	else if (counter == (N << 1)) begin
		clk_out1 <= !clk_out1;
	end
end

reg clk_out2;
always @(negedge clk or posedge rst) begin
	if (rst) begin
		// reset
		clk_out2 <= 0;
	end
	else if (counter == N-1) begin
		clk_out2 <= !clk_out2;
	end
	else if (counter == (N << 1)) begin
		clk_out2 <= !clk_out2;
	end
end

assign clk_out = clk_out1 & clk_out2;
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):

 

module time_adv_half #(
	parameter M = 2,
		WIDTH = 7
)(
    input clk,
    input rst,
    output reg clk_out
    );

wire clk_cnt;
assign clk_cnt = (clk_vld) ? !clk : clk;

reg [WIDTH : 0]counter;
always @(posedge clk_cnt or posedge rst) begin
	if (rst) begin
		// reset
		counter <= 0;
	end
	else if (counter == M) begin
		counter <= 0;
	end
	else begin
		counter <= counter + 1;
	end
end

reg clk_vld;
always @(posedge clk_out or posedge rst) begin
	if (rst) begin
		// reset
		clk_vld <= 0;
	end
	else begin
		clk_vld <= !clk_vld;
	end
end

always @(posedge clk_cnt or posedge rst) begin
	if (rst) begin
		// reset
		clk_out <= 0;
	end
	else if (counter == M-1) begin
		clk_out <= !clk_out;
	end
	else if (counter == M) begin
		clk_out <= !clk_out;
	end
end

endmodule

M=3時候的仿真波形如下:

 


可以看出clk_out兩個上升沿之間為3.5個輸入時鍾周期。

 

附:testbench

 

 `timescale 1 ns / 1 ps
module TEST_gate;
	reg clk, rst;
	wire clk_out_even, clk_out_odd, clk_out_half;
	
	initial begin  
		clk = 1'b0;  
		forever #10 clk = ~clk;  
	end
	
	initial begin  
		rst = 1'b0;  
		#2 rst = 1'b1; 
		#9 rst = 1'b0; 
	end

    time_adv_even #(
	   .N(4)
		,.WIDTH(5)
	   )u0
		(
    	.clk 		(clk)
    	,.rst 		(rst)
    	,.clk_out 	(clk_out_even)
    	);
		
		time_adv_odd #(
	   .N(4)
		,.WIDTH(5)
	   )u1
		(
    	.clk 		(clk)
    	,.rst 		(rst)
    	,.clk_out 	(clk_out_odd)
    	);
		
		time_adv_half #(
	   .M(3)
		,.WIDTH(5)
	   )u2
		(
    	.clk 		(clk)
    	,.rst 		(rst)
    	,.clk_out 	(clk_out_half)
    	);
endmodule

波形


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM