通用分频器的实现

在数字电路设计中,分频器是最常用的电路之一。在FPGA中,一般有两种方法实现,一是采用芯片提供的PLL模块分频(Xilinx的DLL),二是利用计数器实现。在实际工程中,对时钟精度要求较高的,建议使用PLL,但有时FPGA提供的PLL个数有限,不能满足使用要求,这个时候,采用计数器实现。

在设计中,设计人员可能会遇到各种形式的分频要求,如偶数、奇数、半整数、小数和分数分频等,而且可能在占空比上对时钟有所要求。为了实现稳定,占空比均匀的通用分频器,做了点探究。

首先,对于基本原理进行简单介绍。这里设系统时钟(输入时钟)的频率为fi,系统所需的输出频率为fo ,可定义分频系数为D,则有

 

由上式可知,D可能是整数或者分数。因而,我们将分频可以划分为整数分频与分数分频(包括小数分频)。

当N1为0时,D为整数,分频方式为整数分频。当M为偶数时,50%占空比实现起来很容易,如图1左侧所示,只需设置一个计数器(0-(M-1),当计数至M/2-1时,翻转输出时钟即可。当M为奇数时,实现均匀分频相对于偶数分频稍微有点麻烦,如图1右侧所示,以3分频为例,给出了两种类似的实现方法,这里分别产生了2个中间信号,分别在输入时钟的上升沿和下降沿触发,然后通过or或and操作,产生50%占空比的时钟输出。

图1 分频时序图

当N1不为0时,D为分数,即分数分频。要想获得较为精确的分频,情况就更为复杂。这个时候,我们采用可变分频和多次平均的方法,即对输入时钟进行N1次M+1分频和N- N1次M分频,当N=10时,对应的是小数分频。在这里为了使分频较为均匀,一般采用一个简单的算法,以分频系数为7+9/13为例(见表1),对累加N1,当值大于分母N时,采用M+1次分频,同时累加值减去分母,在下一次再次累加N1,若小于分母N时,进行M次分频,然后值在下次再次累加N1,多次进行,即可得到均匀的分频系数表,参照这个表分频。

分频次数

累加值

分频系数

1

9

7

2

18

8

3

14

8

4

10

7

5

19

8

6

15

8

7

11

7

8

20

8

9

16

8

10

12

7

11

21

8

12

17

8

13

13

8

参考代码:

////////////////////////////////////////////////////////////////////////////////
// http://hacer.cc
// Design Name: 
// Module Name:  
// Create Date: 2016/ 
// Created  By: Jeff
// Modified By: Jeff
// Description:   
// Target Device: 
// Additional Comments:
// 
///////////////////////////////////////////////////////////////////////////
module  integer_div(
	clk       ,
	rst_n     ,
	clk_out
);

/*Define Related parameters */
	parameter	DIV_WIDTH  = 8 ;
	parameter	DIV_FACTOR = 16;

/*Define Input Signals*/ 
	input                 clk      ;
	input                 rst_n    ;

/*Define Output Signals*/
	output reg 			  clk_out  ;

/*Define Intermediate Signals*/
	reg [DIV_WIDTH-1:0]   cnt      ;


always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt <= 0;
	end
	else begin
		cnt <= cnt + 1;
		if(cnt == DIV_FACTOR-1)begin
			cnt <= 0;
		end
	end
end

always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		clk_out <= 0;
	end
	else begin
		if(cnt == DIV_FACTOR-1)begin
			clk_out <= ~ clk_out;
		end
	end
end

endmodule
////////////////////////////////////////////////////////////////////////////////
// http://hacer.cc
// Design Name: 
// Module Name:  
// Create Date: 2016/ 
// Created  By: Jeff
// Modified By: Jeff
// Description:   
// Target Device: 
// Additional Comments:
// 
///////////////////////////////////////////////////////////////////////////

module  fraction_div(
	clk       ,
	rst_n     ,
	clk_o  
);


// define D= j+N/M

/*Define Related parameters */
	parameter	J  = 8'd7 ;
	parameter	M  = 8'd13;
	parameter   N  = 8'd9 ;
	parameter 	n1 = 8'd3 ; //duty cycle (M frequency division)
	parameter 	n2 = 8'd4 ; //duty cycle (M+1 frequency division)

	
/*Define Input Signals*/ 
	input                 clk      ;
	input                 rst_n    ;

/*Define Output Signals*/
	output reg 			  clk_o    ;

/*Define Intermediate Signals*/
	reg	[7:0]		TEMP ;
	reg				EN   ;// EN=0 (M frequency division)  EN=1 (M+1 frequency division )  
	reg [7:0]	 cnt1,cnt2;
	reg [7:0] 	 cnt3,cnt4;


always @(posedge clk or negedge rst_n )begin
			if(!rst_n)begin
				EN    <= 1'b0;
				cnt3  <= 8'd0;
				cnt4  <= 8'd1;
				TEMP  <= N;	
			end
			else begin
					if(  TEMP < M  && cnt3 < J) begin   
						EN <= 1'b0;  
						cnt3 <= cnt3 + 8'd1;
					end	
					else begin 
					    if(cnt3 >= J && TEMP < M)begin 
							cnt3   <= 8'd1;
							TEMP   <= TEMP+N;
							if (TEMP+N >= M)begin
								EN <= 1'b1 ;
							end
							else begin
								EN <= 1'b0;
							end
					    end
						else begin	
					        if (TEMP >=M && cnt4 <(J+1) )begin
								EN   <= 1'b1;
								cnt4 <= cnt4 + 8'd1;
					        end
					        else begin 
								TEMP <= TEMP -M +N ;
								cnt4 <= 8'd1;
								if (TEMP -M +N < M)begin
									EN <= 1'b0;
								end
								else begin
									EN <=1'b1;
								end
							end
					    end
					end
			end	
end


//set clk_o
always @(posedge clk or negedge rst_n )begin
			if(!rst_n)begin
				cnt1  <= 8'd0 ;
				cnt2  <= 8'd1 ;
				clk_o <= 1'b0 ;
			end
			else begin
				if(EN == 1'b0 )begin 
					if(cnt1 < J-1 )begin
						cnt1 <= cnt1 + 8'd1;
					end
					else begin
						cnt1 <= 8'd1;
					end
					
					if(cnt1 < n1 )begin
						clk_o <= 1'b1;
					end
					else begin  
						clk_o <= 1'b0;
					end
				end
				
			    else begin
					if(cnt2 < J )begin
						cnt2 <= cnt2 + 8'd1;
					end
					else begin
						cnt2 <= 8'd0;
					end
								 
					if(cnt2 < n2)begin
						clk_o <= 1'b1;
					end
					else begin
					 	if( cnt2 ==J )begin
							clk_o <= 1'b1;
						end
						else begin 
							clk_o <= 1'b0;
						end
					end
				end
			end
end

endmodule

此时,在写一个顶层文件调用上述整数分频和小数分频,即可实现较为均匀准确的频率输出。仿真与实测结果较好