FPGA知識ポイント---任意の周波数分割回路設計

学習する前に、デューティサイクルを理解してください。
デューティサイクル:理想的なパルスシーケンス(方形波など)の場合、正のパルスの持続時間とパルスの周期の比率は、方形波のデューティサイクルと呼ばれます。

周波数分割も

偶数の乗算と除算は、おなじみの除算であり、カウンタで直接実現できる最も単純な除算カウンタである必要があります。たとえば、周波数がNの倍数と偶数で除算される場合、カウンターは分周するクロックによってトリガーできます。カウンターが0からN / 2-1までカウントすると、出力クロックが反転し、カウンターがリセットされます。次のクロックはゼロからカウントを開始します。このサイクルでは、任意の周波数分割を達成できます

奇数の周波数分割

奇数の乗算と除算はフォーラムでよく尋ねられます。実際、奇数の乗算と除算には2つの実装方法があります。1つ目は
、カウンターで実現できます。たとえば、3で除算し、除算するクロックの立ち上がりエッジでカウンターをトリガーします。モジュロ3カウントでは、カウンターが隣接する値までカウントすると2回反転します。たとえば、カウンターが1にカウントすると出力クロックが反転し、カウンターが2に達すると再び反転します。つまり、隣接する1と2でカウント値が2回反転します。このようにして実現された3ウェイ周波数のデューティ比は1/3または2/3です。デューティサイクルが50%の3周波数クロックを実現する場合は、分周するクロックの立ち下がりエッジでカウントをトリガーし、立ち上がりエッジと同じ方法で3カウントしてから、立ち下がりエッジで生成された3周波数クロックと立ち上がりエッジをカウントできます。生成されたクロックは、位相OR演算を実行して、デューティサイクルが50%の3周波数クロックを取得します。この方法は、奇数の周波数分割を実現できます。
一般に分類される方法は、50%のデューティサイクルでN倍の奇数の周波数分割を実現するために、立ち上がりエッジトリガーがモジュロNカウントに対して実行され、カウントが特定の値に選択され、出力クロックが反転され、次に(N- 1)/ 2が再び反転され、50%でない奇数のn周波数クロックが取得されます。同時に、負のエッジでトリガーされるモジュロNカウントが実行されます。値が立ち上がりエッジでトリガーされる出力クロックフリップの選択した値と同じ場合、出力クロッククロックフリップが実行されます。(N-1)/ 2も渡されると、出力クロックが再度フリップしてアカウントが生成されます空の比率が50%以外の奇数n分周クロック。50%以外のデューティサイクルを持つ2つのnで除算されたクロックはORされて、50%のデューティサイクルで奇数番号のn分割クロックが得られます。
別の方法:クロックを奇数倍のnで除算するには、最初にn / 2(小数で、(n-1)/2+0.5に等しい)で除算し、次に2で除算します。50%のデューティサイクルで奇数の周波数分割を取得します。

分数周波数

最初に、入力クロックでの操作が必要なn + 0.5での除算方法について説明します。基本的な設計アイデア:n + 0.5の周波数分割では、最初にnを法としてカウントします。カウントがn-1に達すると、出力クロックは「1」に割り当てられ、カウント0に戻ると、0に割り当てられます。したがって、次のことができます。カウント値がn-1の場合、出力クロックは1であることが知られています。したがって、カウント値n-1が入力クロックサイクルの半分の間維持される限り、n + 0.5分周クロックが実現されるため、n-1を半分に保ちます。 1クロックサイクルは困難です。カウンタはクロックの立ち上がりエッジでカウントするため、カウントがn-1のときにカウントトリガクロックが反転し、クロックの立ち下がりエッジが立ち上がりエッジになることがわかります。つまり、カウント値がn-1の場合、クロックの立ち下がりエッジは立ち上がりエッジになり、カウント値n-1は半クロックサイクルだけ維持されます。クロックが立ち下がりエッジを立ち上がりエッジにフリップするため、カウント値は0になります。したがって、n + 0.5分周クロック周期が生成されるたびに、トリガークロックを1回フリップする必要があります。設計のアイデアは次のとおりです
ここに画像の説明を挿入
。以下は、任意の正の整数の周波数分割コードです。

module div_clk(
	input	clk,
	input	rst_n,
	output	o_clk
);

	parameter	WIDTH = 3;
	parameter	N	  = 6;
	
	reg [WIDTH-1:0]	cnt_p;
	reg				clk_p;
	reg				clk_n;
	
	assign	o_clk = (N==1)?clk : (N[0])?(clk_p | clk_n) : clk_p;//其中N==1是判断不分频,N[0]是判断是奇数还是偶数,若为1则是奇数分频,若是偶数则是偶数分频。
	
	always @(posedge clk or negedge rst_n) begin
		if(!rst_n)
			cnt_p <= {
    
    WIDTH{
    
    1'b0}};
		else if(cnt_p == (N-1))
			cnt_p <= {
    
    WIDTH{
    
    1'b0}};
		else
			cnt_p <= cnt_p + 1'b1;
	end
	
	always @(posedge clk or negedge rst_n) begin
		if(rst_n == 1'b0)
			clk_p <= 1;//此处设置为0也是可以的,这个没有硬性的要求,不管是取0还是取1结果都是正确的。
		else if(cnt_p < (N>>1))/*N整体向右移动一位,最高位补零,其实就是N/2,不过在计算奇数的时候有很明显的优越性*/
			clk_p <= 1;
		else
			clk_p <= 0;
	end
	
	always @(negedge clk or negedge rst_n) begin
		if(rst_n == 1'b0)
			clk_n <= 1;
		else 
			clk_n <= clk_n;
	end

endmodule

以下は、コードの奇数、偶数、および小数の除算です

module divf #
(    parameter Div_num = 12 ,    // 分频数
     parameter state=0        //半分频为0,奇数分频为1,偶数分频为2
)
(
input                 clr,
input                 clk,
output                Div_clk
);
reg [24:0]  count;

case(state)
1:   begin  //ji_shu
          reg         pos_clk;
          reg         neg_clk;

          always@(posedge clk or negedge clr)
          if(!clr)                     count<=0;
          else if(count==0 & pos_clk)  count<=Div_num/2-1;
          else if(count==0)            count<=Div_num/2;
          else                         count<=count-1;

          always@(posedge clk or negedge clr)
          if(!clr)                     pos_clk<=0;
          else if(count==0)            pos_clk<=~pos_clk;
          else                         pos_clk<=pos_clk;

          always@(negedge clk or negedge clr)
          if(!clr)                     neg_clk<=0;
          else                         neg_clk<=pos_clk;

          assign Div_clk = pos_clk & neg_clk;
     end

2:   begin  //ou_shu
          reg          Div_clk1;

          always@(posedge clk or negedge clr)
          if(!clr)                     count<=0;
          else if(count==0)            count<=Div_num/2-1;
          else                         count<=count-1;

          always@(posedge clk or negedge clr)
          if(!clr)                     Div_clk1<=0;
          else if(count==0)            Div_clk1<=~Div_clk1;

          assign Div_clk = Div_clk1;
     end


0:   begin   //ban_fen_pin
          reg         count_div;
          reg         count_div2;
          wire        clk_half;

          assign  clk_half = clk^count_div2;
          always@(posedge clk_half or negedge clr)   //模Div_num 计数
          if(!clr)                       count<=0;
          else if(count== Div_num-1)      count<=0;
          else                         count<=count+1;

          always@(posedge clk_half or negedge clr)   //模Div_num 计数
          if(!clr)                       count_div<=0;
          else if(count== Div_num-1)      count_div<=1;
          else                         count_div<=0;

          always@(posedge count_div or negedge clr)   //对count_div二分频
          if(!clr)                       count_div2<=0;
          else                         count_div2<=~count_div2;

          assign Div_clk = count_div;
     end
endcase

endmodule

おすすめ

転載: blog.csdn.net/gemengxia/article/details/108483696