编写一个计数器以最小误差逼近分数

问题描述 投票:0回答:1

我正在用 Verilog 编写 VGA 控制器。我有一个 100 MHz 时钟,我想在 16670 毫秒的时间内启用信号 VPIXEL 480 次。

显然,我不能每 16670ms/480 ~= 34729.166ms 启用 VPIXEL 或 34729.166...100MHz 时钟的计数。

解决问题的最佳方法是什么,从长远来看,误差最小?

我不想使用新时钟。

verilog hdl vga
1个回答
1
投票

这是一个非常老的问题,我知道这个问题的第一个例子是公历的设计。

如果您要求从长远来看减少误差,那可能是因为您尝试使用整数除法阈值的计数器,即每 34729 个时钟一个脉冲,然后您注意到脉冲将开始太早出现。

由于分母是常数,您可以编写一个计数器,您可以跟踪该值,而无需任何除法电路仅更新分数的分子。

// Code just typed here to illustrate the idea, not tested
// may have even syntax errors
module fractional_counter #(
  parameter N=16670*1000*100,
  parameter D=480
) (
  input logic clk,
  input logic rst,
  output logic pls
);

localparam NB=$clog2(N+D);
logic [NB-1:0] current_num;

always @(posedge clk) begin
  if(rst) begin
    current_num = 0;
  end
  else begin
    
    if(current_num >= N - D) begin
      // (current_num+D)/D >= N/D
      // a cycle is complete
      current_num <= (current_num + D - N);
      pls <= 1;
    end
    else begin
      // Increase the counter
      // current_num / D + 1 = (current_num + D) / D
      current_num <= current_num + D;
      pls <= 0;
    end
  end
end
endmodule

您可以通过简化因子来减少一些位,例如将

N
D
除以
160
,另外,你 16670 非常怀疑只是
50000/3
的另一个近似值,在这种情况下,也许你也必须将其作为分数。

© www.soinside.com 2019 - 2024. All rights reserved.