Verilog 時(shí)鐘分頻

2022-05-20 14:36 更新

關(guān)鍵詞:偶數(shù)分頻,奇數(shù)分頻,半整數(shù)分頻,小數(shù)分頻

初學(xué) Verilog 時(shí)許多模塊都是由計(jì)數(shù)器與分頻器組成的,例如 PWM 脈寬調(diào)制、頻率計(jì)等。分頻邏輯也往往通過計(jì)數(shù)邏輯完成。本節(jié)主要對(duì)偶數(shù)分頻、奇數(shù)分頻、半整數(shù)分頻以及小數(shù)分頻進(jìn)行簡(jiǎn)單的總結(jié)。

偶數(shù)分頻

采用觸發(fā)器反向輸出端連接到輸入端的方式,可構(gòu)成簡(jiǎn)單的 2 分頻電路。

以此為基礎(chǔ)進(jìn)行級(jí)聯(lián),可構(gòu)成 4 分頻,8 分頻電路。

電路實(shí)現(xiàn)如下圖所示,用 Verilog 描述時(shí)只需使用簡(jiǎn)單的取反邏輯即可。


如果偶數(shù)分頻系數(shù)過大,就需要對(duì)分頻系數(shù) N 循環(huán)計(jì)數(shù)進(jìn)行分頻。在計(jì)數(shù)周期達(dá)到分頻系數(shù)中間數(shù)值 N/2 時(shí)進(jìn)行時(shí)鐘翻轉(zhuǎn),可保證分頻后時(shí)鐘的占空比為 50%。因?yàn)槭桥紨?shù)分頻,也可以對(duì)分頻系數(shù)中間數(shù)值 N/2 進(jìn)行循環(huán)計(jì)數(shù)。

偶數(shù)分頻的 Verilog 描述舉例如下:

module even_divisor
  # (parameter DIV_CLK = 10 )
    (
    input               rstn ,
    input               clk,
    output              clk_div2,
    output              clk_div4,
    output              clk_div10
    );

   //2 分頻
   reg                  clk_div2_r ;
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         clk_div2_r     <= 'b0 ;
      end
      else begin
         clk_div2_r     <= ~clk_div2_r ;
      end
   end
   assign       clk_div2 = clk_div2_r ;

   //4 分頻
   reg                  clk_div4_r ;
   always @(posedge clk_div2 or negedge rstn) begin
      if (!rstn) begin
         clk_div4_r     <= 'b0 ;
      end
      else begin
         clk_div4_r     <= ~clk_div4_r ;
      end
   end
   assign clk_div4      = clk_div4_r ;

   //N/2 計(jì)數(shù)
   reg [3:0]            cnt ;
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         cnt    <= 'b0 ;
      end
      else if (cnt == (DIV_CLK/2)-1) begin
         cnt    <= 'b0 ;
      end
      else begin
         cnt    <= cnt + 1'b1 ;
      end
   end

   //輸出時(shí)鐘
   reg                  clk_div10_r ;
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         clk_div10_r <= 1'b0 ;
      end
      else if (cnt == (DIV_CLK/2)-1 ) begin
         clk_div10_r <= ~clk_div10_r ;
      end
   end
   assign clk_div10 = clk_div10_r ;
endmodule

testbench 中只需給入激勵(lì)時(shí)鐘等信號(hào)即可,這里不再列出。

仿真結(jié)果如下:


奇數(shù)分頻

奇數(shù)分頻如果不要求占空比為 50%,可按照偶數(shù)分頻的方法進(jìn)行分頻。即計(jì)數(shù)器對(duì)分頻系數(shù) N 進(jìn)行循環(huán)計(jì)算,然后根據(jù)計(jì)數(shù)值選擇一定的占空比輸出分頻時(shí)鐘。

如果奇數(shù)分頻輸出時(shí)鐘的高低電平只差一個(gè) cycle ,則可以利用源時(shí)鐘雙邊沿特性并采用"與操作"或"或操作"的方式將分頻時(shí)鐘占空比調(diào)整到 50%。

或操作調(diào)整占空比

采用"或操作"產(chǎn)生占空比為 50% 的 3 分頻時(shí)序圖如下所示。

利用源時(shí)鐘上升沿分頻出高電平為 1 個(gè) cycle、低電平為 2 個(gè) cycle 的 3 分頻時(shí)鐘。

利用源時(shí)鐘下降沿分頻出高電平為 1 個(gè) cycle、低電平為 2 個(gè) cycle 的 3 分拼時(shí)鐘。

兩個(gè) 3 分頻時(shí)鐘應(yīng)該在計(jì)數(shù)器相同數(shù)值、不同邊沿下產(chǎn)生,相位差為半個(gè)時(shí)鐘周期。然后將 2 個(gè)時(shí)鐘進(jìn)行"或操作",便可以得到占空比為 50% 的 3 分頻時(shí)鐘。


同理,9 分頻時(shí),則需要在上升沿和下降沿分別產(chǎn)生 4 個(gè)高電平、5 個(gè)低電平的 9 分頻時(shí)鐘,然后再對(duì)兩個(gè)時(shí)鐘做"或操作"即可。Verilog 描述如下:

module odo_div_or
  #(parameter DIV_CLK = 9)
   (
    input               rstn ,
    input               clk,
    output              clk_div9
    );

   //計(jì)數(shù)器
   reg [3:0]            cnt ;
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         cnt    <= 'b0 ;
      end
      else if (cnt == DIV_CLK-1) begin
         cnt    <= 'b0 ;
      end
      else begin
         cnt    <= cnt + 1'b1 ;
      end
   end

   //在上升沿產(chǎn)生9分頻
   reg                  clkp_div9_r ;
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         clkp_div9_r <= 1'b0 ;
      end
      else if (cnt == (DIV_CLK>>1)-1 ) begin //計(jì)數(shù)4-8位低電平
        clkp_div9_r <= 0 ;
      end
      else if (cnt == DIV_CLK-1) begin //計(jì)數(shù) 0-3 為高電平
        clkp_div9_r <= 1 ;
      end
   end
 
   //在下降沿產(chǎn)生9分頻
   reg                  clkn_div9_r ;
   always @(negedge clk or negedge rstn) begin
      if (!rstn) begin
         clkn_div9_r <= 1'b0 ;
      end
      else if (cnt == (DIV_CLK>>1)-1 ) begin
        clkn_div9_r <= 0 ;
      end
      else if (cnt == DIV_CLK-1) begin
        clkn_div9_r <= 1 ;
      end
   end

   //或操作,往往使用基本邏輯單元庫
   // or (clk_div9, clkp_div9_r, clkn_div9_r) ;
   assign clk_div9 = clkp_div9_r | clkn_div9_r ;

endmodule

仿真結(jié)果如下:


與操作調(diào)整占空比

采用"與操作"產(chǎn)生占空比為 50% 的 3 分頻時(shí)序圖如下所示。

利用源時(shí)鐘上升沿分頻出高電平為 2 個(gè) cycle、低電平為 1 個(gè) cycle 的 3 分頻時(shí)鐘。

利用源時(shí)鐘下降沿分頻出高電平為 2 個(gè) cycle、低電平為 1 個(gè) cycle 的 3 分拼時(shí)鐘。

兩個(gè) 3 分頻時(shí)鐘應(yīng)該在計(jì)數(shù)器相同數(shù)值、不同邊沿下產(chǎn)生,相位差為半個(gè)時(shí)鐘周期。然后將 2 個(gè)時(shí)鐘進(jìn)行"與操作",便可以得到占空比為 50% 的 3 分頻時(shí)鐘。


同理,9 分頻時(shí),則需要在上升沿和下降沿分別產(chǎn)生 5 個(gè)高電平、4 個(gè)低電平的 9 分頻時(shí)鐘,然后再對(duì)兩個(gè)時(shí)鐘做"與操作"即可。Verilog 描述如下:

module odo_div_and
   #( parameter DIV_CLK = 9 )
   (
    input               rstn ,
    input               clk,
    output              clk_div9
    );

   //計(jì)數(shù)器
   reg [3:0]            cnt ;
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         cnt    <= 'b0 ;
      end
      else if (cnt == DIV_CLK-1) begin
         cnt    <= 'b0 ;
      end
      else begin
         cnt    <= cnt + 1'b1 ;
      end
   end

   //在上升沿產(chǎn)生9分頻
   reg                  clkp_div9_r ;
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         clkp_div9_r <= 1'b0 ;
      end
      else if (cnt == (DIV_CLK>>1) ) begin //計(jì)數(shù)5-8位低電平
        clkp_div9_r <= 0 ;
      end
      else if (cnt == DIV_CLK-1) begin //計(jì)數(shù) 0-4 為高電平
        clkp_div9_r <= 1 ;
      end
   end

   //在下降沿產(chǎn)生9分頻
   reg                  clkn_div9_r ;
   always @(negedge clk or negedge rstn) begin
      if (!rstn) begin
         clkn_div9_r <= 1'b0 ;
      end
      else if (cnt == (DIV_CLK>>1) ) begin
        clkn_div9_r <= 0 ;
      end
      else if (cnt == DIV_CLK-1) begin
        clkn_div9_r <= 1 ;
      end
   end

   //與操作,往往使用基本邏輯單元庫
   //and (clk_div9, clkp_div9_r, clkn_div9_r) ;
   assign clk_div9 = clkp_div9_r & clkn_div9_r ;

endmodule

仿真結(jié)果如下:


半整數(shù)分頻

利用時(shí)鐘的雙邊沿邏輯,可以對(duì)時(shí)鐘進(jìn)行半整數(shù)的分頻。但是無論怎么調(diào)整,半整數(shù)分頻的占空比不可能是 50%。半整數(shù)分頻的方法有很多,這里只介紹一種和奇數(shù)分頻調(diào)整占空比類似的方法。

  1. 例如進(jìn)行 3.5 倍分頻時(shí),計(jì)數(shù)器循環(huán)計(jì)數(shù)到 7,分別產(chǎn)生由 4 個(gè)和 3 個(gè)源時(shí)鐘周期組成的 2 個(gè)分頻時(shí)鐘。從 7 個(gè)源時(shí)鐘產(chǎn)生了 2 個(gè)分頻時(shí)鐘的角度來看,該過程完成了 3.5 倍的分頻,但是每個(gè)分頻時(shí)鐘并不是嚴(yán)格的 3.5 倍分頻。
  2. 下面對(duì)周期不均勻的分頻時(shí)鐘進(jìn)行調(diào)整。一次循環(huán)計(jì)數(shù)中,在源時(shí)鐘下降沿分別產(chǎn)生由 4 個(gè)和 3 個(gè)源時(shí)鐘周期組成的 2 個(gè)分頻時(shí)鐘。相對(duì)于第一次產(chǎn)生的 2 個(gè)周期不均勻的時(shí)鐘,本次產(chǎn)生的 2 個(gè)時(shí)鐘相位一個(gè)延遲半個(gè)源時(shí)鐘周期,一個(gè)提前半個(gè)源時(shí)鐘周期。
  3. 將兩次產(chǎn)生的時(shí)鐘進(jìn)行"或操作",便可以得到周期均勻的 3.5 倍分頻時(shí)鐘。分頻波形示意圖如下所示。


3.5 倍時(shí)鐘分頻的 Verilog 描述如下:

module half_divisor(
    input               rstn ,
    input               clk,
    output              clk_div3p5
    );

   //計(jì)數(shù)器
   parameter            MUL2_DIV_CLK = 7 ;
   reg [3:0]            cnt ;
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         cnt    <= 'b0 ;
      end
      else if (cnt == MUL2_DIV_CLK-1) begin //計(jì)數(shù)2倍分頻比
         cnt    <= 'b0 ;
      end
      else begin
         cnt    <= cnt + 1'b1 ;
      end
   end

   reg                  clk_ave_r ;
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         clk_ave_r <= 1'b0 ;
      end
      //first cycle: 4 source clk cycle
      else if (cnt == 0) begin
         clk_ave_r <= 1 ;
      end
      //2nd cycle: 3 source clk cycle
      else if (cnt == (MUL2_DIV_CLK/2)+1) begin
         clk_ave_r <= 1 ;
      end
      else begin
         clk_ave_r <= 0 ;
      end
   end

   //adjust
   reg                  clk_adjust_r ;
   always @(negedge clk or negedge rstn) begin
      if (!rstn) begin
         clk_adjust_r <= 1'b0 ;
      end
      //本次時(shí)鐘只為調(diào)整一致的占空比
      else if (cnt == 1) begin
         clk_adjust_r <= 1 ;
      end
      //本次時(shí)鐘只為調(diào)整一致的精確分頻比
      else if (cnt == (MUL2_DIV_CLK/2)+1 ) begin
         clk_adjust_r <= 1 ;
      end
      else begin
         clk_adjust_r <= 0 ;
      end
   end

   assign clk_div3p5 = clk_adjust_r | clk_ave_r ;

endmodule

仿真結(jié)果如下:


小數(shù)分頻

基本原理

不規(guī)整的小數(shù)分頻不能做到分頻后的每個(gè)時(shí)鐘周期都是源時(shí)鐘周期的小數(shù)分頻倍,更不能做到分頻后的時(shí)鐘占空比均為 50%,因?yàn)?nbsp;Verilog 不能對(duì)時(shí)鐘進(jìn)行小數(shù)計(jì)數(shù)。和半整數(shù)分頻中第一次分頻時(shí)引入的"平均頻率"概念類似,小數(shù)分頻也是基于可變分頻和多次平均的方法實(shí)現(xiàn)的。

例如進(jìn)行 7.6 倍分頻,則保證源時(shí)鐘 76 個(gè)周期的時(shí)間等于分頻時(shí)鐘 10 個(gè)周期的時(shí)間即可。此時(shí)需要在 76 個(gè)源時(shí)鐘周期內(nèi)進(jìn)行 6 次 8 分頻,4 次 7 分頻。再例如進(jìn)行 5.76 分頻,需要在 576 個(gè)源時(shí)鐘周期內(nèi)進(jìn)行 76 次 6 分頻,24 次 5 分頻。

下面闡述下這些分頻參數(shù)的計(jì)算過程。

當(dāng)進(jìn)行 7 分頻時(shí),可以理解為 70 個(gè)源時(shí)鐘周期內(nèi)進(jìn)行 10 次 7 分頻。在 76 個(gè)源時(shí)鐘周期內(nèi)仍然進(jìn)行 10 次分頻,相當(dāng)于將多余的 6 個(gè)源時(shí)鐘周期增加、分配到 70 個(gè)源時(shí)鐘周期內(nèi),即完成了 7.6 倍分頻操作。分頻過程中必然有 6 個(gè)分頻時(shí)鐘是 8 分頻得到的,剩下的 4 個(gè)分頻時(shí)鐘則仍然會(huì)保持原有的 7 分頻狀態(tài)。

很多地方給出了計(jì)算這些分頻參數(shù)的兩元一次方程組,如下所示。其原理和上述分析一致,建議掌握上述計(jì)算過程。

7N + 8M = 76
N  + M   = 10 

其中 7 為整數(shù)分頻,N 整數(shù)分頻的次數(shù);8 與 M 為整數(shù)分頻加一后的分頻系數(shù)及其分頻次數(shù)。

平均原理

以 7.6 倍分頻為例,7 分頻和 8 分頻的實(shí)現(xiàn)順序一般有以下 4 種:

  1. 先進(jìn)行 4 次 7 分頻,再進(jìn)行 6 次 8 分頻;
  2. 先進(jìn)行 6 次 8 分頻,再進(jìn)行 4 次 7 分頻;
  3. 將 4 次 7 分頻平均的插入到 6 次 8 分頻中;
  4. 將 6 次 8 分頻平均的插入到 4 次 7 分頻中。

前兩種方法時(shí)鐘頻率不均勻,相位抖動(dòng)較大,所以一般會(huì)采用后兩種平均插入的方法進(jìn)行小數(shù)分頻操作。

平均插入可以通過分頻次數(shù)差累計(jì)的方法實(shí)現(xiàn),7.6 分頻的實(shí)現(xiàn)過程如下:

  1. 第一次分頻次數(shù)差值為 76-10*7 = 6 < 10,第一次進(jìn)行 7 分頻。
  2. 第二次差值累加結(jié)果為 6+6=12 > 10,第二次使用 8 分頻,同時(shí)差值修改為 12-10=2。
  3. 第三次差值累加結(jié)果為 2+6=8 < 10,第三次使用 7 分頻。
  4. 第四次差值累加結(jié)果為 8+6=14 > 10,第四次使用 8 分頻,差值修改為 14-10=4。

以此類推,完成將 6 次 8 分頻平均插入到 4 次 7 分頻的過程。

下表展示了平均插入法的分頻過程。

分頻次數(shù) 差值累加 差值修改 分頻周期
1 6 6 7
2 6+6=12 2 8
3 2+6=8 8 7
4 8+6=14 4 8
5 4+6=10 0 8
6 6 6 7
7 6+6=12 2 8
8 2+6=8 8 7
9 8+6=14 4 8
10 4+6=10 0 8

設(shè)計(jì)仿真

基于上述小數(shù)分頻實(shí)現(xiàn)方法的 Verilog 描述如下:

module frac_divisor
  #(
   parameter            SOURCE_NUM = 76 , //cycles in source clock
   parameter            DEST_NUM   = 10  //cycles in destination clock
   )
   (
    input               rstn ,
    input               clk,
    output              clk_frac
    );
 
   //7分頻參數(shù)、8分頻參數(shù)、次數(shù)差值
   parameter    SOURCE_DIV = SOURCE_NUM/DEST_NUM ;
   parameter    DEST_DIV   = SOURCE_DIV + 1;
   parameter    DIFF_ACC   = SOURCE_NUM - SOURCE_DIV*DEST_NUM ;


   reg [3:0]            cnt_end_r ;  //可變分頻周期
   reg [3:0]            main_cnt ;   //主計(jì)數(shù)器
   reg                  clk_frac_r ; //時(shí)鐘輸出,高電平周期數(shù)為1
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         main_cnt    <= 'b0 ;
         clk_frac_r  <= 1'b0 ;
      end
      else if (main_cnt == cnt_end_r) begin
         main_cnt    <= 'b0 ;
         clk_frac_r  <= 1'b1 ;
      end
      else begin
         main_cnt    <= main_cnt + 1'b1 ;
         clk_frac_r  <= 1'b0 ;
      end
   end
   //輸出時(shí)鐘
   assign       clk_frac        = clk_frac_r ;
   //差值累加器使能控制
   wire         diff_cnt_en     = main_cnt == cnt_end_r ;

   //差值累加器邏輯
   reg [4:0]            diff_cnt_r ;
   wire [4:0]           diff_cnt = diff_cnt_r >= DEST_NUM ?
                                   diff_cnt_r -10 + DIFF_ACC :
                                   diff_cnt_r + DIFF_ACC ;                                
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         diff_cnt_r <= 0 ;
      end
      else if (diff_cnt_en) begin
         diff_cnt_r <= diff_cnt ;
      end
   end

   //分頻周期變量的控制邏輯
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         cnt_end_r      <= SOURCE_DIV-1 ;
      end
      //差值累加器溢出時(shí),修改分頻周期
      else if (diff_cnt >= 10) begin
         cnt_end_r      <= DEST_DIV-1 ;
      end
      else begin
         cnt_end_r      <= SOURCE_DIV-1 ;
      end
   end

endmodule

仿真結(jié)果如下:


分頻小結(jié)

偶數(shù)分頻不使用時(shí)鐘雙邊沿邏輯即可完成占空比為 50% 的時(shí)鐘分頻,是最理想的分頻狀況。

奇數(shù)分頻如果要產(chǎn)生 50% 占空比的分頻時(shí)鐘,則需要使用時(shí)鐘的雙邊沿邏輯。如果不要求占空比的話,實(shí)現(xiàn)方法和偶數(shù)分頻類似。

半整數(shù)分頻屬于特殊的小數(shù)分頻,可以用雙邊沿邏輯進(jìn)行設(shè)計(jì)。通過一定邏輯將兩個(gè)雙邊沿時(shí)鐘信號(hào)整合為最后的一路輸出時(shí)鐘時(shí),建議不要使用選擇邏輯。因?yàn)槿菀壮霈F(xiàn)毛刺現(xiàn)象,電路中又會(huì)增加一定的不確定性。例如下面描述是不建議的。

assign clk_div3p5 = (cnt == 1 || cnt ==2) ? clk_ave_r
                                          : clk_adjust_r ;

小數(shù)分頻的基本思想是,輸出時(shí)鐘在一段時(shí)間內(nèi)的平均頻率達(dá)到分頻要求即可。但是考慮到相位抖動(dòng),還需要對(duì)分頻系數(shù)變化的分頻邏輯進(jìn)行平均操作。

點(diǎn)擊這里下載源碼


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)