在FPGA上基于原语生成时钟

阅读关于FPGA的数据表,您可以找到有关其工作频率的信号……但是,



不,故事始于2015年,那时我熟悉了FPGA。在我的第一个简单作品中,我从计数器中形成了我需要的时钟,并从中获得了所有逻辑(自然,只要我需要比提供给FPGA的时钟(例如UART和SPI)慢的时钟)。自然地,他们为此追逐了我,但是我有一个简单的借口“但是行得通!”,而且一切真的行之有效。从那以后,这种想法浮现在脑海:“我从哪里可以得到定时信号?”



切碎来源的选择不多。可以从某个基于PLL或MMCM的ClockWizard中获取,或者从计数器中或者直接从支路中形成(可以说是单端)。如果我们采用FPGA原语生成的时钟信号怎么办?



作为本文的一部分,我决定考虑三个选项:一个多路复用器(MUXF7),一个真值表(LUT1)以及将FPGA支路自身短路。



对于多路复用器,输出被馈送到控制信号,输入信号被拉至0和1。



图片


对于LUT,我们将输出短路至输入,并设置反相真值表。提供“ 1”时,输出零;提供“ 0”时,输出一。



图片


对于GPIO,那里的一切都很简单,将输出信号分配为与输入信号的逆:

分配s2 =〜s1;


实验的目的:以三种方式生成频率并对其进行测量。

我们将以计数器为代价来测量频率。将有4个计数器:每个选项三个,一个基本计数器,相对于所有基本计数器。我们将通过ChipScope观看这些计数器。



这是整个模块代码:
module gen_clk(
    input clk_base,
    input s1, //gpio
    output s2 //gpio
    );

//  - 
assign s2 = ~s1;
wire clk_gpio = s1;
reg [31:0] cnt_gpio = 0;
 (* MARK_DEBUG="true" *) reg [31:0] cnt_gpio_buf = 0;
always@(posedge clk_gpio)
begin 
    if(cnt_gpio[2:0]==3'd0) cnt_gpio_buf<=cnt_gpio; 
    cnt_gpio <= cnt_gpio + 1'b1;
end

//  
wire clk_mux;
MUXF7 MUXF7_inst
(
    .O(clk_mux),
    .I0(1'b1),
    .I1(1'b0),
    .S(clk_mux)
);
reg [31:0] cnt_mux = 0;
 (* MARK_DEBUG="true" *) reg [31:0] cnt_mux_buf = 0;
always@(posedge clk_mux)
begin 
    if(cnt_mux[2:0]==3'd0) cnt_mux_buf<=cnt_mux; 
    cnt_mux <= cnt_mux + 1'b1;
end
//   
wire clk_lut;
LUT1#(
    .INIT(2'b01)
)
LUT1_inst(
    .O(clk_lut),
    .I0(clk_lut)
);
reg [31:0] cnt_lut = 0;
 (* MARK_DEBUG="true" *) reg [31:0] cnt_lut_buf = 0;
always@(posedge clk_lut)
begin 
    if(cnt_lut[2:0]==3'd0) cnt_lut_buf<=cnt_lut; 
    cnt_lut <= cnt_lut + 1'b1;
end
//         
 (* MARK_DEBUG="true" *) reg [31:0] cnt_base = 'd0;        
always@(posedge clk_base)
begin
    cnt_base <= cnt_base + 1'b1;
end    
   
endmodule




这是该项目的示意图。图元被圈出,箭头表示将输入ChipScope进行频率分析的信号:



图片




实践部分,我



可以使用三个委员会:



  1. KC705评估套件



    图片


  2. ML507评估套件



    图片


  3. 中国Spartan-6 XC6SLX16板



    图片


    展望未来
    , , .





所以现在实际结果



Kintex-7:



自从专为该项目创建以来,该项目并不是一次全部编写的,而是分阶段进行的。首先,我连接了一个LUT,为调试添加了信号并开始观察。



基本计数器的时钟频率为200 MHz,因此计算战利品生成的时钟频率并不困难,即掠夺计数器的增量计数器是基本计数器的增量同时多少倍,是其频率的多少倍。在这种情况下:战利品产生的频率为381.55 MHz。



图片


现在,我们将向项目添加一个多路复用器,并以一个战利品为类比,为该战利品和战利品计算频率(毕竟,某些东西必须改变)。



图片


乍一看是柜台发出的嘎嘎声。这会影响多路复用器的巨大频率,但总的来说,很明显计数器在增加,这意味着也可以对其进行计数。最终:



  • 多路复用器频率:5953.89 MHz
  • 赃物频率(已更改):379.98 MHz


好了,最后,让我们从GPIO对到项目中添加一个闭环。KC705板具有SMA连接器J13和J14。在这里,我用大约10厘米长的导体将它们闭合,结果是:



  • GPIO频率:90.59 MHz
  • 多路复用器频率:12994.13 MHz
  • 赃物频率:380.18 MHz


为了进行实验,让我们用一根更长的导线代替,我的导线长度是原来的两倍。结果,频率下降到85.29 MHz。



在实验的这一阶段,可以注意到,FPGA中原语的操作频率是不同的。在只有一个战利品的情况下,合成器选择了最快的战利品并在其周围建立了电路,然后在添加多路复用器时,合成器试图找到该战利品和多路复用器都尽可能快地工作的超级位置,而这些其他元素和频率已经较慢了。当添加外部引脚时,晶体上的整个项目基本上都移到了这些分支上,并且由于某种原因,该项目开始在附近的元件上合成,在那个地方,战利品和多路复用器的频率显着增加,但不要忘记在项目所有这些情况下连接了深度为1024的ChipScope和从64到128的数据总线(它随项目而变化)。现在,让我们继续下一块板。



Virtex-5:



我并没有像上一块板那样一直走下去,我立即添加了生成披风的所有3个选项,并在ChipScope中查看发生了什么。



图片


该图显示了两个标签X和O.以及它们在列中的值,数字的格式为无符号十进制。值得注意的是,基数计数器现在以100 MHz计数。结果是:



  • GPIO频率:96.34 MHz
  • 多路复用器频率:614.41 MHz
  • 赃物频率:5761.1 MHz


可以看出,在这块板上,赃物的速度比多路复用器快,并且引脚的频率比在第一块板上的频率高,这可能是因为我不是用10 cm的导体而是用跳线连接了这两个引脚,结果是通信线变短了,频率也更高了。



现在是中国董事会的最后选择。



Spartan-6:



ChipScope中有两个基本计数器,实际上,它是同一计数器,只是不想重新配置ChipScope。在此项目中,基本计数器的时钟频率为50 MHz。



图片


就此板而言,一切都变得更加复杂。首先,该项目不希望以以前版本中的任何形式进行合成。其次,最后,我不得不扔掉LUT,我试图用五向替换LUT,但是它也不起作用。通常,结果如下:



  • GPIO频率:51.77 MHz
  • 多路复用器频率:3490504 MHz
  • 抢劫频率:收集失败


事实证明,该评估板执行的结果令人非常不满意,这不仅是因为无法将战利品用作大块,而且还因为多路复用器的频率非常高。至于在腿上产生的切丝,使用约25-30 cm的导体,末端用导线封闭,那里可能形成寄生电容和电感,这对切丝的产生有影响。



结论



通常,我们设法在各种基元上生成时钟信号,并且还设法(以Kintex-7为例)看到基元根据其位置而具有不同的延迟。我要代表我自己补充一点,我不认为所进行的实验是完全正确的,例如,未计算计数器的位宽,未考虑来自不同时钟域的信号传输(尽管我使信号在缓冲区中停留了几个时钟),理想情况下应删除ChipScope本身,并找到另一种方法分析产生的频率。



遇到的问题:
Vivado ISE , . :



  • set_property ALLOW_COMBINATORIAL_LOOPS TRUE [get_nets -of_objects [get_cells gen_clk_inst/LUT1_inst]]
  • NET «s1» CLOCK_DEDICATED_ROUTE = FALSE;





All Articles