FPGA开发资料整理

发布时间 2023-09-27 05:40:49作者: 吴建明wujianming
FPGA开发资料整理
FPGA静态时序分析——IO口时序(Input Delay /output Delay) 
https://www.cnblogs.com/linjie-swust/archive/2012/03/01/FPGA.html
本文PDF版本下载:
https://files.cnblogs.com/linjie-swust/FPGA%E4%B8%ADIO%E6%97%B6%E5%BA%8F%E7%BA%A6%E6%9D%9F%E5%88%86%E6%9E%90.pdf
1.1  概述
  在高速系统中FPGA时序约束不止包括内部时钟约束,还应包括完整的IO时序约束和时序例外约束才能实现PCB板级的时序收敛。因此,FPGA时序约束中IO口时序约束也是一个重点。只有约束正确才能在高速情况下保证FPGA和外部器件通信正确。
1.2  FPGA整体概念
  由于IO口时序约束分析是针对于电路板整个系统进行时序分析,所以FPGA需要作为一个整体分析,其中包括FPGA的建立时间、保持时间以及传输延时。传统的建立时间、保持时间以及传输延时都是针对寄存器形式的分析。但是针对整个系统FPGA的建立时间保持时间可以简化。
 

   图1.1  FPGA整体时序图

  如图1.1所示,为分解的FPGA内部寄存器的性能参数:
  (1) Tdin为从FPGA的IO口到FPGA内部寄存器输入端的延时;
  (2) Tclk为从FPGA的IO口到FPGA内部寄存器时钟端的延时;
  (3) Tus/Th为FPGA内部寄存器的建立时间和保持时间;
  (4) Tco为FPGA内部寄存器传输时间;
  (5) Tout为从FPGA寄存器输出到IO口输出的延时;
  对于整个FPGA系统分析,可以重新定义这些参数:FPGA建立时间可以定义为:
  (1) FPGA建立时间:FTsu = Tdin + Tsu – Tclk;
  (2) FPGA保持时间:FTh = Th + Tclk;
  (3) FPGA数据传输时间:FTco = Tclk + Tco + Tout;
  由上分析当FPGA成为一个系统后即可进行IO时序分析了。FPGA模型变为如图1.2所示。
 

 图1.2  FPGA系统参数

1.3  输入最大最小延时
  外部器件发送数据到FPGA系统模型如图1.3所示。对FPGA的IO口进行输入最大最小延时约束是为了让FPGA设计工具能够尽可能的优化从输入端口到第一级寄存器之间的路径延迟,使其能够保证系统时钟可靠的采到从外部芯片到FPGA的信号。

 图1.3  FPGA数据输入模型

  输入延时即为从外部器件发出数据到FPGA输入端口的延时时间。其中包括时钟源到FPGA延时和到外部器件延时之差、经过外部器件的数据发送Tco,再加上PCB板上的走线延时。如图1.4所示,为外部器件和FPGA接口时序。

图1.4  外部器件和FPGA接口时序

1.         最大输入延时
  最大输入延时(input delay max)为当从数据发送时钟沿(lanuch edge)经过最大外部器件时钟偏斜(Tclk1),最大的器件数据输出延时(Tco),再加上最大的PCB走线延时(Tpcb),减去最小的FPGA时钟偏移(FTsu)的情况下还能保证时序满足的延时。这样才能保证FPGA的建立时间,准确采集到本次数据值,即为setup slack必须为正,如图1.1的所示,计算公式如下式所示:
    Setup slack =(Tclk + Tclk2(min))–(Tclk1(max) +Tco(max) +Tpcb(max) +FTsu)≥0
  推出如下公式:
    Tclk1(max) + Tco(max) + Tpcb(max) –Tclk2(min) ≤ Tclk + FTsu         
  由Altera官方数据手册得知:
    input delay max = Board Delay (max) – Board clock skew (min) + Tco(max)     
  结合本系统参数公式为:
    input delay max = Tpcb(max) – (Tclk2(min)–Tclk1(max)) + Tco(max)         
2.         最小输入延时
  最小输入延时(input delay min)为当从数据发送时钟沿(lanuch edge)经过最小外部器件时钟偏斜(Tclk1),最小器件数据输出延时(Tco),再加上最小PCB走线延时(Tpcb),此时的时间总延时值一定要大于FPGA的最大时钟延时和建立时间之和,这样才能不破坏FPGA上一次数据的保持时间,即为hold slack必须为正,如图1.1的所示,计算公式如下式所示:
    Hold slack = (Tclk1(min) + Tco(min) + Tpcb(min))–(FTh + Tclk2(max))≥ 0  
  推出如下公式:
    Tclk1(min) + Tco(min) + Tpcb(min) – Tclk2(max) ≥ FTh                               
  由Altera官方数据手册得知:
    input delay max = Board Delay (min) - Board clock skew (min) + Tco(min)        
  结合本系统参数公式为
    input delay max = Tpcb(min) – (Tclk2(max)–Tclk1(min)) + Tco(min)                  
  由公式4和公式8得知,进行输入最大最小延时的计算,我们需要估算4个值:
  (1) 外部器件输出数据通过PCB板到达FPGA端口的最大值和最小值Tpcb,PCB延时经验值为600mil/ns,1mm = 39.37mil;
  (2) 外部器件接收到时钟信号后输出数据延时的最大值和最小值Tco;
  (3) 时钟源到达外部器件的最大、最小时钟偏斜Tclk1;
  (4) 时钟源到达FPGA的最大、最小时钟偏斜Tclk2;
  当外部器件时钟为FPGA提供的时候,Tclk1和Tclk2即合成Tshew,如图1.5所示:

 图1.5  FPGA输出时钟模型

1.4  输出最大最小延时
  FPGA输出数据给外部器件模型如图1.6所示。对FPGA的IO口进行输出最大最小延时约束是为了让FPGA设计工具能够尽可能的优化从第一级寄存器到输出端口之间的路径延迟,使其能够保证让外部器件能准确的采集到FPGA的输出数据。

图1.6  FPGA输出延时模型

  输出延时即为从FPGA输出数据后到达外部器件的延时时间。其中包括时钟源到FPGA延时和到外部器件延时之差、PCB板上的走线延时以及外部器件的数据建立和保持时间。如所示,为FPGA和外部器件接口时序图。

图1.7  FPGA输出延时

1.         最大输出延时
  由Altera官方数据手册得知:
    Output delay max = Board Delay (max) – Board clock skew (min) + Tsu       
  由公式得知,最大输出延时(output delay max)为当从FPGA数据发出后经过最大的PCB延时、最小的FPGA和器件时钟偏斜,再加上外部器件的建立时间。约束最大输出延时,是为了约束IO口输出,从而使外部器件的数据建立时间,即为setup slack必须为正,计算公式如下式所示:
    Setup slack =(Tclk + Tclk2(min))–(Tclk1(max) +FTco(max) +Tpcb(max) +Tsu)≥0
  推导出如下公式:
    FTco(max) + Tpcb(max) –(Tclk2(min) – Tclk1(max))+Tsu ≤Tclk                 
  再次推导,得到如下公式:
    FTco(max) + Output delay max ≤Tclk                     
  由此可见,约束输出最大延时,即为通知编译器FPGA的FTco最大值为多少,根据这个值做出正确的综合结果。
2.   输出最小延时
  由Altera官方数据手册得知:
    Output delay min = Board Delay (min) – Board clock skew (max) –Th        
  由公式得知,最小输出延时(output delay min)为当从FPGA数据发出后经过最小的PCB延时、最大的FPGA和器件时钟偏斜,再减去外部器件的建立时间。约束最小输出延时,是为了约束IO口输出,从而使IO口输出有个最小延时值,防止输出过快,破坏了外部器件上一个时钟的数据保持时间,导致hlod slack为负值,不能正确的锁存到数据,最小输出延时的推导计算公式如下式所示:
    Hold slack = (Tclk1(min) + FTco(min) + Tpcb(min))–(Th + Tclk2(max))≥ 0 
  推导出如下公式:
    FTco(min) + Tpcb(min) – (Tclk2(max) – Tclk1(min))– Th ≥ 0    
  再次推导,得出如下公式:
    FTco(min) + Output delay min ≥ 0                    
  由公式得知,约束输出最大延时,即为通知编译器FPGA的FTco最小值为多少,根据这个值做出正确的综合结果。
  由公式10和公式14得知,进行输出最大最小延时的计算,我们需要估算4个值:
  (1) FPGA输出数据通过PCB板到达外部器件输入端口的最大值和最小值Tpcb,PCB延时经验值为600mil/ns,1mm = 39.37mil;
  (2) 时钟源到达外部器件的最大、最小时钟偏斜Tclk2;
  (3) 时钟源到达FPGA的最大、最小时钟偏斜Tclk1;
  (4) 外部器件的建立时间Tsu和保持时间Th;
  当外部器件时钟为FPGA提供的时候,Tclk1和Tclk2即合成Tshew,如图1.8所示:

图1.8  FPGA提供时钟模型

1.5  使用范围
  通过作者使用总结情况,IO口时序约束主要使用在以下情况:
1.         数据交换频率较高
  由于IO时序约束一般计算值都是在几纳秒,当FPGA和外部数据交换频率较低,如FPGA操作640*480的TFT液晶进行刷屏,数据传输频率仅仅24Mhz,一个数据时钟都有41.666ns,完全不用约束都能满足时序要求。但是当操作SDRAM运行到120M时候,由于一个数据变换周期才8ns,因此IO口的少量延时都会影响到SDRAM数据,因此这种情况下需要对输入输出进行完整的IO口时序约束,并且分析正确,才能消除数据传输不稳定过的情况。
2.         代码已经比较优化
  当数据交换频率较高,但是时序约束还是不满足时序要求的时候,我们都需要对代码进行分析,好的时序都是设计出来的,不是约束出来的。如程序清单 1.1所示,首先hcount_r 和vcount_r 都为10位计数器,这样的代码TFT的三色输出的端口就会有很大的延时,因为dat_act的胶合逻辑太多,输出路径太长导致。这种情况下应该不是首先做时序约束,应该修改代码,尽量做到寄存器直接输出。只有当代码比较优化的情况,再做时序约束这样才能得到较好的结果。
                  程序清单 1.1  示例程序
1 assign dat_act  =    ((hcount_r >= hdat_begin) && (hcount_r < hdat_end))                
2            && ((vcount_r >= vdat_begin) && (vcount_r < vdat_end));
3 assign tft_r    =    (dat_act) ? {rgb16_dat[15:11], 3'b111} : 8'h00;
4 assign tft_g    =    (dat_act) ? {rgb16_dat[10:5],  3'b111} : 8'h00; 
5 assign tft_b    =    (dat_act) ? {rgb16_dat[4:0],   3'b111} : 8'h00;
1.6  总结
  本文档主要是对FPGA的IO口时序约束进行相应的分析,并未做实际的使用分析,在后续文档中将会结合软件,以及实际案例对IO口时序约束进行详细的使用介绍。最后附上一个Altera官方的IO时序约束分析例子,如图1.9所示。

 图1.9  Altera官方例程

 
FPGA中亚稳态——让你无处可逃 
https://www.cnblogs.com/linjie-swust/archive/2012/01/07/YWT.html
1. 应用背景
1.1         亚稳态发生原因
      在FPGA系统中,如果数据传输中不满足触发器的Tsu和Th不满足,或者复位过程中复位信号的释放相对于有效时钟沿的恢复时间(recovery time)不满足,就可能产生亚稳态,此时触发器输出端Q在有效时钟沿之后比较长的一段时间处于不确定的状态,在这段时间里Q端在0和1之间处于振荡状态,而不是等于数据输入端D的值。这段时间称为决断时间(resolution time)。经过resolution time之后Q端将稳定到0或1上,但是稳定到0或者1,是随机的,与输入没有必然的关系。
1.2         亚稳态发生场合
      只要系统中有异步元件,亚稳态就是无法避免的,亚稳态主要发生在异步信号检测、跨时钟域信号传输以及复位电路等常用设计中。
1.3         亚稳态危害
      由于产生亚稳态后,寄存器Q端输出在稳定下来之前可能是毛刺、振荡、固定的某一电压值。在信号传输中产生亚稳态就会导致与其相连其他数字部件将其作出不同的判断,有的判断到“1”有的判断到“0”,有的也进入了亚稳态,数字部件就会逻辑混乱。在复位电路中产生亚稳态可能会导致复位失败。怎么降低亚稳态发生的概率成了FPGA设计需要重视的一个注意事项。
 
2. 理论分析
2.1         信号传输中的亚稳态
     在同步系统中,输入信号总是系统时钟同步,能够达到寄存器的时序要求,所以亚稳态不会发生。亚稳态问题通常发生在一些跨时钟域信号传输以及异步信号采集上。
它们发生的原因如下:
(1)在跨时钟域信号传输时,由于源寄存器时钟和目的寄存器时钟相移未知,所以源寄存器数据发出数据,数据可能在任何时间到达异步时钟域的目的寄存器,所以无法保证满足目的寄存器Tsu和Th的要求;
(2)在异步信号采集中,由于异步信号可以在任意时间点到达目的寄存器,所以也无法保证满足目的寄存器Tsu和Th的要求;
当数据在目的寄存器Tsu-Th时间窗口发生变化,也即当数据的建立时间或者保持时间不满足时,就可能发生亚稳态现象。如图3.1所示。

  图3.1  亚稳态产生示意图

     由图可知,当产生亚稳态后Tco时间后会有Tmet(决断时间)的振荡时间段,当振荡结束回到稳定状态时为“0”或者“1”,这个是随机的。因此,会对后续电路判断造成影响。
2.2         复位电路的亚稳态
2.2.1    异步复位电路
在复位电路设计中,复位信号基本都是异步的,常用异步复位电路Verilog描述如下:
always @(posedge clk or negedge rst_n)
begin
       if(!rst_n) a <= 1’b0;
       else         a <= b;
end
综合出来复位电路模型如图3.2所示:

 图3.2  异步复位电路模型

      如图3.3所示,为复位电路复位时序图。如果异步复位信号的撤销时间在Trecovery(恢复时间)和Tremoval(移除时间)之内,那势必造成亚稳态的产生,输出在时钟边沿的Tco后会产生振荡,振荡时间为Tmet(决断时间),最终稳定到“0”或者“1”,就会可能造成复位失败。

 图3.3  异步复位时序

2.2.2    同步复位电路的亚稳态
     在复位电路中,由于复位信号是异步的,因此,有些设计采用同步复位电路进行复位,并且绝大多数资料对于同步复位电路都认为不会发生亚稳态,其实不然,同步电路也会发生亚稳态,只是几率小于异步复位电路。
如下面verilog代码对同步复位电路的描述。
always @(posedge clk)
begin
       if(!rst_n) a <= 1’b0;
       else         a <= b;
end
综合出硬件电路如图3.4所示。

 图3.4  同步复位电路

      在此,我们不讨论同步复位的消耗资源问题,只讨论同步复位的亚稳态产生情况。
      当输入端Din为高电平,而且复位信号的撤销时间在clk的Tsu和Th内时候,亚稳态就随之产生了。如图3.5时序所示,当复位撤销时间在clk的Tsu和Th内,输入数据为“1”,通过和输入数据相与后的数据也在clk的Tsu和Th内,因此,势必会造成类似异步信号采集的亚稳态情况。

 图3.5  同步复位电路时序图

2.3         亚稳态产生概率以及串扰概率
      在实际的FPGA电路设计中,常常人们想的是怎么减少亚稳态对系统的影响,很少有人考虑怎么才能减少亚稳态发生几率,以及亚稳态串扰的概率问题。
2.3.1    亚稳态发生概率
      由上面分析得知,系统亚稳态发生的都是由于clk的Tsu和Th不满足,又或者是复位信号的移除和恢复时间不满足。常用FPGA器件的Tsu+Th约等于1ns,复位移除和恢复时间相加约等于1ns。
      当异步信号不是一组数据,或者信号量较少,那就需要对异步信号进行同步处理,例如对一个异步脉冲信号进行采集,只要脉冲信号变化发生在时钟Tsu和Th窗口内,那就很可能会产生亚稳态,亚稳态产生的概率大概为:
                                              概率 = (建立时间 + 保持时间)/ 采集时钟周期                                                                            (公式3-1)
      由公式3-1可以看出,随着clk频率的增加,亚稳态发生的几率是增加的。
      例如,为系统采用100M时钟对一个外部信号进行采集,采集时钟周期为10ns,那采集产生亚稳态的概率为:1ns/10ns = 10%
      同理采用300M时钟对一个外部信号进行采集,那产生亚稳态的概率为:1ns/3.3ns = 30%
      如果采用三相相位差为120°的时钟对一个外部信号进行采集,那产生亚稳态的概率接近90%
     所以在异步信号采集过程中,要想减少亚稳态发生的概率:
  (1) 降低系统工作时钟,增大系统周期,亚稳态概率就会减小;
  (2) 采用工艺更好的FPGA,也就是Tsu和Th时间较小的FPGA器件;
2.3.2    亚稳态的串扰概率
     使用异步信号进行使用的时候,好的设计都会对异步信号进行同步处理,同步一般采用多级D触发器级联处理,如图3.6所示,采用三级D触发器对异步信号进行同步处理。

 图3.6  三级寄存器同步

      这种模型大部分资料都说的是第一级寄存器产生亚稳态后,第二级寄存器稳定输出概率为90%,第三极寄存器稳定输出的概率为99%,如果亚稳态跟随电路一直传递下去,那就会另自我修护能力较弱的系统直接崩溃。接下来我们分析这种串扰的概率问题。
     如图3.7所示为一个正常第一级寄存器发生了亚稳态,第二级、第三极寄存器消除亚稳态时序模型。

图3.7 三级寄存器消除亚稳态

     由上图可以看出,当第一个寄存器发生亚稳态后,经过Tmet的振荡稳定后,第二级寄存器能采集到一个稳定的值。但是为什么第二级寄存器还是可能会产生亚稳态呢?
     由于振荡时间Tmet是受到很多因素影响的,所以Tmet时间又长有短,所以当Tmet时间长到大于一个采集周期后,那第二级寄存器就会采集到亚稳态。如图3.8所示。

图3.8  二级寄存器亚稳态

      由上图可知,第二级也是一个亚稳态,所以在这种情况下,亚稳态产生了串扰,从第一级寄存器传到了第二级寄存器,同样也可能从第二级寄存器串扰到第三级寄存器。这样会让设计逻辑判断出错,产生亚稳态传输,可能导致系统死机奔溃。
2.3.3    亚稳态振荡时间Tmet
      亚稳态震荡时间Tmet关系到后级寄存器的采集稳定问题,Tmet影响因素包括:器件的生产工艺、温度、环境以及寄存器采集到亚稳态离稳定态的时刻等。甚至某些特定条件,如干扰、辐射等都会造成Tmet增长。
3. 应用分析
有亚稳态产生,我们就要对亚稳态进行消除,常用对亚稳态消除有三种方式:
(1)       对异步信号进行同步处理;
(2)       采用FIFO对跨时钟域数据通信进行缓冲设计;
(3)       对复位电路采用异步复位、同步释放方式处理。
3.1.1    对异步信号进行同步提取边沿
在异步通信或者跨时钟域通信过程中,最常用的就是对异步信号进行同步提取边沿处理。对一个异步信号进行提取上升沿通常采用程序清单 4.1所示。
程序清单 4.1 双极寄存器提取边沿
input      sig_nsyn;
wire        sig_nsyn_p;
reg[1:0]   sig_nsyn_r;
always @(posedge clk or negedge rst_n)
begin
       if(!rst_n) sig_nsyn_r <= 2’d0;
       else         sig_nsyn_r <= { sig_nsyn_r [0], sig_nsyn };
end
 
assign     sig_nsyn_p = sig_nsyn_r[0] & ~sig_nsyn_r[1];
       这种边沿提取方式对于一个稳定的系统是不合适的,例如:当第一级寄存器采集到亚稳态,那势必造成sig_nsyn_p输出亚稳态,这样就会对采用sig_nsyn_p的信号进行判断的电路造成影响,甚至判断出错误的值。
根据3.3.1小节的亚稳态产生概率,如果在100M时种下那第一级寄存器产生亚稳态的概率约为10%,随着系统采集频率升高,那产生亚稳态的概率也会随之上升。因此,在进行异步信号跨频提取边沿时候,一般采用多进行一级寄存器消除亚稳态,可能在系统稳定性要求高的情况下,采用更多级寄存器来消除亚稳态,如程序清单 4.2所示,即为采用4级寄存器消除亚稳态,相应的边沿信号产生的时间就晚了两个时钟周期。
程序清单 4.2 多级寄存器提取边沿信号
input      sig_nsyn;
wire        sig_nsyn_p;
reg[3:0]   sig_nsyn_r;
always @(posedge clk or negedge rst_n)
begin
       if(!rst_n) sig_nsyn_r <= 2’d0;
       else         sig_nsyn_r <= { sig_nsyn_r [2::0], sig_nsyn };
end
 
assign     sig_nsyn_p = sig_nsyn_r[2] & ~sig_nsyn_r[3];
3.1.2    FIFO进行异步跨频数据处理
当数据流从一个时钟域到另一个时钟域的时候,绝大多数情况下都采用FIFO来作为中间缓冲,采用双时钟对数据缓冲,就可以避免亚稳态的发生。
3.1.3    异步复位,同步释放
对于复位情况下的亚稳态,常常是由于恢复时间和移除时钟不满足造成的,因此,最常用的处理方式是采用异步复位、同步释放。常用电路模型如所示。采用第二级寄存器输出作为全局复位信号输出。
程序清单 4.3  异步复位处理
wire        sys_rst_n;
reg [1:0]  rst_r;
always @(posedge clk or negedge rst_n)
begin
       if(!rst_n) rst_r <= 2’d0;
       else         rst_r <= {rst_r[0], 1’b1};
end
assign     sys_rst_n = rst_r[1];
通过上面三种方式处理异步信号、异步数据、以及异步复位可有效的提高系统的稳定性。减少亚稳态的产生。
 

FPGA STA(静态时序分析) 

https://www.cnblogs.com/zfyouxi/p/5183903.html
1 FPGA设计过程中所遇到的路径有输入到触发器,触发器到触发器,触发器到输出,例如以下图所看到的:

这些路径与输入延时输出延时,建立和保持时序有关。

2. 应用背景
  静态时序分析简称STA,它是一种穷尽的分析方法。它依照同步电路设计的要求。依据电路网表的拓扑结构,计算并检查电路中每个DFF(触发器)的建立和保持时间以及其它基于路径的时延要求是否满足。
STA作为FPGA设计的主要验证手段之中的一个,不须要设计者编写測试向量,由软件自己主动完毕分析,验证时间大大缩短,測试覆盖率可达100%。
  静态时序分析的前提就是设计者先提出要求,然后时序分析工具才会依据特定的时序模型进行分析,给出正确是时序报告。
  进行静态时序分析。主要目的就是为了提高系统工作主频以及添加系统的稳定性。
对非常多数字电路设计来说,提高工作频率非常重要,由于高工作频率意味着高处理能力。通过附加约束能够控制逻辑的综合、映射、布局和布线,以减小逻辑和布线延时。从而提高工作频率。
3. 理论分析
3.1         静态时序分析的理论基础知识
  在进行正确的时序分析前。我们必须具备主要的静态时序的基本知识点,不然看着编译器给出的时序分析报告宛如天书。如图3.1所看到的,为libero软件给出的寄存器到寄存器模型的时序分析报告的截取。接下来我们会弄清楚每一个栏目的数据变量的含义。以及计算方法。

  图3.1  libero静态时序分析报告

3.1.1    固定參数launch edge、latch edge、Tsu、Th、Tco概念
1.         launch edge
 
  时序分析起点(launch edge):第一级寄存器数据变化的时钟边沿,也是静态时序分析的起点。
2.         latch edge
  时序分析终点(latch edge):数据锁存的时钟边沿,也是静态时序分析的终点。
3.         Clock Setup Time (Tsu)
  建立时间(Tsu):是指在时钟沿到来之前数据从不稳定到稳定所需的时间,假设建立的时间不满足要求那么数据将不能在这个时钟上升沿被稳定的打入触发器。如图3.2所看到的:

  图3.2  建立时间图解

4.         Clock Hold Time (Th)
  保持时间(Th):是指数据稳定后保持的时间。假设保持时间不满足要求那么数据相同也不能被稳定的打入触发器。保持时间示意图如图3.3所看到的:

图3.3  保持时间图解

5.         Clock-to-Output Delay(tco)
  数据输出延时(Tco):这个时间指的是当时钟有效沿变化后,数据从输入端到输出端的最小时间间隔。
3.1.2    Clock skew
  时钟偏斜(clock skew):是指一个时钟源到达两个不同寄存器时钟端的时间偏移。如图3.4所看到的:

图3.4  时钟偏斜

  时钟偏斜计算公式例如以下:
                                              Tskew = Tclk2 - Tclk1                (公式3-1)
3.1.3    Data Arrival Time
  数据到达时间(Data Arrival Time):输入数据在有效时钟沿后到达所须要的时间。
主要分为三部分:时钟到达寄存器时间(Tclk1),寄存器输出延时(Tco)和传输数据延时(Tdata),如图3.5所看到的

图3.5  数据到达时间

  数据到达时间计算公式例如以下:
                Data Arrival Time = Launch edge + Tclk1 +Tco + Tdata            (公式3-2)
3.1.4    Clock Arrival Time
  时钟到达时间(Clock Arrival Time):时钟从latch边沿到达锁存寄存器时钟输入端所消耗的时间为时钟到达时间,如图3.6所看到的

 图3.6  时钟到达时间

时钟到达时间计算公式例如以下:
                Clock Arrival Time = Lacth edge + Tclk2              (公式3-3)
3.1.5    Data Required Time(setup/hold)
  数据需求时间(Data Required Time):在时钟锁存的建立时间和保持时间之间数据必须稳定,从源时钟起点达到这样的稳定状态须要的时间即为数据需求时间。如图3.7所看到的:

图3.7  数据需求时间

  (建立)数据需求时间计算公式例如以下:
               Data Required Time = Clock Arrival Time - Tsu            (公式3-4)
  (保持)数据需求时间计算公式例如以下:
                      Data Required Time = Clock Arrival Time + Th               (公式3-5) 
3.1.6    Setup slack
  建立时间余量(setup slack):当数据需求时间大于数据到达时间时,就说时间有余量,Slack是表示设计是否满足时序的一个称谓。

  图3.8  建立时间余量

  如图3.8所看到的,建立时间余量的计算公式例如以下:
                  Setup slack = Data Required Time - Data Arrival Time            (公式3-6)
  由公式可知。正的slack表示数据需求时间大于数据到达时间,满足时序(时序的余量)。负的slack表示数据需求时间小于数据到达时间,不满足时序(时序的欠缺量)。
3.1.7    时钟最小周期
  时钟最小周期:系统时钟能执行的最高频率。
  1.  当数据需求时间大于数据到达时间时,时钟具有余量;
  2.    当数据需求时间小于数据到达时间时,不满足时序要求,寄存器经历亚稳态或者不能正确获得数据。
  3.    当数据需求时间等于数据到达时间时。这是最小时钟执行频率。刚好满足时序。
  从以上三点能够得出最小时钟周期为数据到达时间等于数据需求时间,的运算公式例如以下:
            Data Required Time = Data Arrival Time                (公式3-7)        
  由上式推出例如以下公式:
 Tmin + Latch edge + Tclk2 - Tsu = Launch edge + Tclk1 + Tco + Tdata
  终于推出最小时钟周期为:
            Tmin = Tco + Tdata + Tsu - Tskew                  (公式3-8)
4. 应用分析
4.1         设置时钟主频约束
  全部的静态时序分析都是在有约束的情况下编译器才给出分析报告,所以进行时序分析的第一步就是设置约束。
  Libero软件设置时钟约束的途径三种,单时钟约束,多时钟约束和在Designer里面进行约束。
4.1.1    单时钟约束
  有时我们系统全部模块都採用同一个时钟,这样的方式最为简单,直接在Synplify主界面上有个设置时钟约束的。如图4.1中红框所看到的:

图4.1  单时钟设置

  设置完毕后,编译。通过Synplify时钟报告看初步时钟执行频率是否能达到要求,时钟报告如图4.2所看到的,设定100Mhz,能执行102.7Mhz。满足时序。

图4.2  时序报告

4.2         多时钟约束
  当系统内部模块採用了多个时钟时。那就须要进行多时钟约束了。
首先须要打开设置界面。在Synplify中选择:File->New->Constraint File建立SDC文件,选择时钟约束如图4.3所看到的:

图4.3  多时钟约束

  对时钟进行例如以下约束后保存SDC文件,约束如图4.4所看到的 

图4.4  多时钟约束完毕

4.3         Designer SmartTime时钟约束
  时钟约束除了在Synplify中能够约束外。还能够在Designer SmartTime中设置时钟约束,打开Designer Constraint,选择Clock进行针对每一个使用时钟的设置,如图4.5所看到的:

 图4.5  Designer时序约束

4.4         时序报告分析
4.4.1    Synplify时序报告
  当约束了时序后,须要观察时序报告,看时钟是否能达到我们须要的时钟,首先观察Synplify综合报告。以多时钟约束为样例,从Synplify得到的时序报告如图4.6所看到的:

 图4.6  多时钟约束时序报告

由上图可知时序都满足约束,未出现违规。能够在以下的报告中查看最差路径,如图4.7所看到的是clk2的最差路径。

 图4.7  最差路径

4.4.2    Designer SmartTime时序分析报告
  当设计经过Synplify综合给出网表文件后,还须要Designer进行布局布线,通过布局布线优化后的时序会有变化,因此,还须要分析布局布线后的时序,打开Designer->Timing Analyzer查阅总体时序分析报告如图4.8所看到的:

 图4.8  布局布线后时序报告

  由Synplify综合后的报告和Designer进行布局布线后的报告能够看出。布局布线后优化了一些时序。特别是clk2时钟,通过布局布线后优化到了184Mhz,全然满足时序。
4.4.3    具体时序报告图
  通过Synplify综合后的和Designer进行布局布线都仅仅是看到了一个大体的时序报告。当我们须要分析时序时候必须观察细致的时序报告,在SmartTime中提供这样的报告功能,以clk2分析为例,在Timing Analyzer找到例如以下区域。

 图4.9  时序报告选择

  如图4.9所看到的,选择寄存器到寄存器进行分析时钟主频。

 图4.10  寄存器到寄存器分析

  如图4.10所看到的。时序报告中给出了数据延时。时序余量,数据到达时间,数据需求时间。数据建立时间,以及最小周期和时钟偏斜等信息,有了上一节的时序分析基础知识,我们全然能看懂这些数据代表的意义。这样对我们时序分析就知己知彼,进一步双击当中一条路径,还会给出这条路径的硬件电路图,如图4.11所看到的。有了这些具体的时序报告。对设计进行调整更加清晰。 

 图4.11  硬件路径

1.1  概述
  在快速系统中FPGA时序约束不止包含内部时钟约束,还应包含完整的IO时序约束和时序例外约束才干实现PCB板级的时序收敛。因此。FPGA时序约束中IO口时序约束也是一个重点。
仅仅有约束正确才干在快速情况下保证FPGA和外部器件通信正确。
1.2  FPGA总体概念
  因为IO口时序约束分析是针对于电路板整个系统进行时序分析,所以FPGA须要作为一个总体分析,当中包含FPGA的建立时间、保持时间以及传输延时。传统的建立时间、保持时间以及传输延时都是针对寄存器形式的分析。
可是针对整个系统FPGA的建立时间保持时间能够简化。

  图1.1  FPGA总体时序图
  如图1.1所看到的,为分解的FPGA内部寄存器的性能參数:
  (1) Tdin为从FPGA的IO口到FPGA内部寄存器输入端的延时;
  (2) Tclk为从FPGA的IO口到FPGA内部寄存器时钟端的延时;
  (3) Tus/Th为FPGA内部寄存器的建立时间和保持时间;
  (4) Tco为FPGA内部寄存器传输时间;
  (5) Tout为从FPGA寄存器输出到IO口输出的延时。
  对于整个FPGA系统分析,能够又一次定义这些參数:FPGA建立时间能够定义为:
  (1) FPGA建立时间:FTsu = Tdin + Tsu – Tclk;
  (2) FPGA保持时间:FTh = Th + Tclk。
  (3) FPGA传输数据时间:FTco = Tclk + Tco + Tout;
  由上分析当FPGA成为一个系统后就可以进行IO时序分析了。FPGA模型变为如图1.2所看到的。

 图1.2  FPGA系统參数

1.3  输入最大最小延时
  外部器件发送数据到FPGA系统模型如图1.3所看到的。
对FPGA的IO口进行输入最大最小延时约束是为了让FPGA设计工具可以尽可能的优化从输入port到第一级寄存器之间的路径延迟,使其可以保证系统时钟可靠的採到从外部芯片到FPGA的信号。

 图1.3  FPGA数据输入模型

  输入延时即为从外部器件发出数据到FPGA输入port的延时时间。
当中包含时钟源到FPGA延时和到外部器件延时之差、经过外部器件的数据发送Tco。再加上PCB板上的走线延时。如图1.4所看到的,为外部器件和FPGA接口时序。

图1.4  外部器件和FPGA接口时序

1.         最大输入延时
  最大输入延时(input delay max)为当从数据发送时钟沿(lanuch edge)经过最大外部器件时钟偏斜(Tclk1),最大的器件数据输出延时(Tco),再加上最大的PCB走线延时(Tpcb)。减去最小的FPGA时钟偏移(FTsu)的情况下还能保证时序满足的延时。这样才干保证FPGA的建立时间,准确採集到本次数据值,即为setup slack必须为正。如图1.1的所看到的。计算公式例如以下式所看到的:
    Setup slack =(Tclk + Tclk2(min))–(Tclk1(max) +Tco(max) +Tpcb(max) +FTsu)≥0
  推出例如以下公式:
    Tclk1(max) + Tco(max) + Tpcb(max) –Tclk2(min) ≤ Tclk + FTsu         
  由Altera官方数据手冊得知:
    input delay max = Board Delay (max) – Board clock skew (min) + Tco(max)     
  结合本系统參数公式为:
    input delay max = Tpcb(max) – (Tclk2(min)–Tclk1(max)) + Tco(max)         
2.         最小输入延时
  最小输入延时(input delay min)为当从数据发送时钟沿(lanuch edge)经过最小外部器件时钟偏斜(Tclk1),最小器件数据输出延时(Tco),再加上最小PCB走线延时(Tpcb),此时的时间总延时值一定要大于FPGA的最大时钟延时和建立时间之和。这样才干不破坏FPGA上一次数据的保持时间。即为hold slack必须为正,如图1.1的所看到的,计算公式例如以下式所看到的:
    Hold slack = (Tclk1(min) + Tco(min) + Tpcb(min))–(FTh + Tclk2(max))≥ 0  
  推出例如以下公式:
    Tclk1(min) + Tco(min) + Tpcb(min) – Tclk2(max) ≥ FTh                               
  由Altera官方数据手冊得知:
    input delay max = Board Delay (min) - Board clock skew (min) + Tco(min)        
  结合本系统參数公式为
    input delay max = Tpcb(min) – (Tclk2(max)–Tclk1(min)) + Tco(min)                  
  由公式4和公式8得知。进行输入最大最小延时的计算,我们须要估算4个值:
  (1) 外部器件输出数据通过PCB板到达FPGAport的最大值和最小值Tpcb,PCB延时经验值为600mil/ns。1mm = 39.37mil;
  (2) 外部器件接收到时钟信号后输出数据延时的最大值和最小值Tco。
  (3) 时钟源到达外部器件的最大、最小时钟偏斜Tclk1;
  (4) 时钟源到达FPGA的最大、最小时钟偏斜Tclk2;
  当外部器件时钟为FPGA提供的时候。Tclk1和Tclk2即合成Tshew,如图1.5所看到的:

 图1.5  FPGA输出时钟模型

1.4  输出最大最小延时
  FPGA输出数据给外部器件模型如图1.6所看到的。对FPGA的IO口进行输出最大最小延时约束是为了让FPGA设计工具可以尽可能的优化从第一级寄存器到输出port之间的路径延迟。使其可以保证让外部器件能准确的採集到FPGA的输出数据。

 图1.6  FPGA输出延时模型

  输出延时即为从FPGA输出数据后到达外部器件的延时时间。
当中包含时钟源到FPGA延时和到外部器件延时之差、PCB板上的走线延时以及外部器件的数据建立和保持时间。
如所看到的,为FPGA和外部器件接口时序图。

图1.7  FPGA输出延时

1.         最大输出延时
  由Altera官方数据手冊得知:
    Output delay max = Board Delay (max) – Board clock skew (min) + Tsu       
  由公式得知。最大输出延时(output delay max)为当从FPGA数据发出后经过最大的PCB延时、最小的FPGA和器件时钟偏斜,再加上外部器件的建立时间。约束最大输出延时,是为了约束IO口输出,从而使外部器件的数据建立时间。即为setup slack必须为正,计算公式例如以下式所看到的:
    Setup slack =(Tclk + Tclk2(min))–(Tclk1(max) +FTco(max) +Tpcb(max) +Tsu)≥0
  推导出例如以下公式:
    FTco(max) + Tpcb(max) –(Tclk2(min) – Tclk1(max))+Tsu ≤Tclk                 
  再次推导,得到例如以下公式:
    FTco(max) + Output delay max ≤Tclk                     
  由此可见,约束输出最大延时。即为通知编译器FPGA的FTco最大值为多少。依据这个值做出正确的综合结果。
2.   输出最小延时
  由Altera官方数据手冊得知:
    Output delay min = Board Delay (min) – Board clock skew (max) –Th        
  由公式得知,最小输出延时(output delay min)为当从FPGA数据发出后经过最小的PCB延时、最大的FPGA和器件时钟偏斜,再减去外部器件的建立时间。约束最小输出延时,是为了约束IO口输出。从而使IO口输出有个最小延时值,防止输出过快,破坏了外部器件上一个时钟的数据保持时间。导致hlod slack为负值。不能正确的锁存到数据。最小输出延时的推导计算公式例如以下式所看到的:
    Hold slack = (Tclk1(min) + FTco(min) + Tpcb(min))–(Th + Tclk2(max))≥ 0 
  推导出例如以下公式:
    FTco(min) + Tpcb(min) – (Tclk2(max) – Tclk1(min))– Th ≥ 0    
  再次推导,得出例如以下公式:
    FTco(min) + Output delay min ≥ 0                    
  由公式得知,约束输出最大延时,即为通知编译器FPGA的FTco最小值为多少。依据这个值做出正确的综合结果。
  由公式10和公式14得知,进行输出最大最小延时的计算,我们须要估算4个值:
  (1) FPGA输出数据通过PCB板到达外部器件输入port的最大值和最小值Tpcb,PCB延时经验值为600mil/ns,1mm = 39.37mil。
  (2) 时钟源到达外部器件的最大、最小时钟偏斜Tclk2;
  (3) 时钟源到达FPGA的最大、最小时钟偏斜Tclk1;
  (4) 外部器件的建立时间Tsu和保持时间Th;
  当外部器件时钟为FPGA提供的时候,Tclk1和Tclk2即合成Tshew。如图1.8所看到的:

 图1.8  FPGA提供时钟模型

1.5  使用范围
  通过作者使用总结情况,IO口时序约束主要使用在下面情况:
1.         数据交换频率较高
  因为IO时序约束一般计算值都是在几纳秒。当FPGA和外部数据交换频率较低,如FPGA操作640*480的TFT液晶进行刷屏,传输数据频率只24Mhz,一个数据时钟都有41.666ns,全然不用约束都能满足时序要求。
可是当操作SDRAM执行到120M时候,因为一个数据变换周期才8ns。因此IO口的少量延时都会影响到SDRAM数据。因此这样的情况下须要对输入输出进行完整的IO口时序约束。而且分析正确,才干消除传输数据不稳定过的情况。
2.         代码已经比較优化
  当数据交换频率较高。可是时序约束还是不满足时序要求的时候。我们都须要对代码进行分析,好的时序都是设计出来的,不是约束出来的。如程序清单 1.1所看到的。首先hcount_r 和vcount_r 都为10位计数器,这种代码TFT的三色输出的port就会有非常大的延时。由于dat_act的胶合逻辑太多。输出路径太长导致。
这种情况下应该不是首先做时序约束,应该改动代码,尽量做到寄存器直接输出。
仅仅有当代码比較优化的情况,再做时序约束这样才干得到较好的结果。
                  程序清单 1.1  演示样例程序
 
1 assign dat_act  =    ((hcount_r >= hdat_begin) && (hcount_r < hdat_end))                
2            && ((vcount_r >= vdat_begin) && (vcount_r < vdat_end));
3 assign tft_r    =    (dat_act) ? {rgb16_dat[15:11], 3'b111} : 8'h00;
4 assign tft_g    =    (dat_act) ?
 {rgb16_dat[10:5],  3'b111} : 8'h00; 
5 assign tft_b    =    (dat_act) ? {rgb16_dat[4:0],   3'b111} : 8'h00;
1.6  总结
  本文档主要是对FPGA的IO口时序约束进行对应的分析,并未做实际的使用分析,在兴许文档中将会结合软件,以及实际案例对IO口时序约束进行具体的使用介绍。最后附上一个Altera官方的IO时序约束分析样例。如图1.9所看到的。

 图1.9  Altera官方例程

基于 FPGA 的图像边缘检测
https://www.cnblogs.com/aslmer/p/5779079.html
本文主要内容是实现图像的边缘检测功能
目录
  1. mif文件的制作
  2. 调用 ip 核生成rom以及在 questasim 仿真注意问题
  3. 灰度处理
  4. 均值滤波:重点是3*3 像素阵列的生成
  5. sobel边缘检测
  6. 图片的显示   
  7. 结果展示                                                                                                                                                                                                       

mif文件的制作
受资源限制,将图片像素定为 160 * 120,将图片数据制成 mif 文件,对 rom ip 核进行初始化。mif文件的制作方法网上有好多办法,因此就不再叙述了,重点说mif文件的格式。 
1、mif文件的格式为:
 
 1 WIDTH=16 ;    //数据位宽
2 DEPTH=19200 ;   // rom 深度即图片像素点的个数
3 ADDRESS_RADIX=UNS ;   //地址数据格式
4 DATA_RADIX=BIN ;   //数据格式
5 CONTENT
6 BEGIN
7 0:1010110011010000 ;     // 地址 :数据 ;注意格式要和上面定义的保持统一
8 1:1010110011010000 ;
9 2:1010010010110000 ;
10 ......
11 19198:1110011011111001 ;
12 19199:1110011011011000 ;
13 END;
 
 

调用ip 核生成 rom 以及在 questasim 仿真注意问题
这部分内容已经在上篇博文中详细描述过,详情请见http://www.cnblogs.com/aslmer/p/5780107.html
 

 
灰度处理
任何颜色都由红、绿、蓝三原色组成,假如原来某点的颜色为( R,G,B )那么,我们可以通过下面几种方法,将其转换为灰度:
  • 浮点算法:Gray=0.299R+0.587G+0.114B
  • 平均值法:Gray=(R+G+B)/3;
  • 仅取单色(如绿色):Gray=G;
将计算出来的Gray值同时赋值给 RGB 三个通道即RGB为(Gray,Gray,Gray),此时显示的就是灰度图。通过观察调色板就能看明了。 通过观察可知,当RGB三个通道的值相同时即为灰色,Gray的值越大,颜色越接近白色,反之越接近黑色(这是我自己的理解,不严谨错误之处请大神指正)。
这是在线调色板网址,可以进去自己研究一下。
https://tool.chinaz.com/tools/cj
中国传统色彩

 #FFFFFF

 http://tool.chinaz.com/tools/selectcolor.aspx

 

 --------------------------------------------------------------------------------------------------------------------

此次我采用是浮点算法来实现灰度图的,我的图片数据是RGB565 格式 ,
难点: 如何进行浮点运算。
思路:先将数据放大,然后再缩小。
例如:
Gray=0.299R+0.587G+0.114B转化为 Gray=(77R+150G+29B)>>8 即可,这里有一个技巧,若 a 为 16 位即 a [15:0],那么 a>>8 与 a [15:8]是一样的。
核心代码如下:
 
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
       red_r1   <= 0 ; 
       green_r1 <= 0 ;
       blue_r1  <= 0 ;
    end
    else begin
       red_r1   <= red   * 77 ;        //放大后的值
       green_r1 <= green * 150;
       blue_r1  <= blue  * 29 ;
    end
end
 
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        Gray <= 0;    // 三个数之和
    end
    else begin
        Gray <= red_r1 + green_r1 + blue_r1;       
    end
end
 
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
       post_data_in <= 0;  //输出的灰度数据
    end
    else begin
       post_data_in <= { Gray[13:9], Gray[13:8], Gray[13:9] };//将Gray值赋值给RGB三个通道
    end
end
 

均值滤波
均值滤波的原理
http://blog.csdn.net/hhygcy/article/details/4325304 (此处引用 hhygcy 的文章)
难点:如何生成 3*3 的像素阵列。
我们可以利用 ip 核生成移位寄存器 ,方法与 ip 核 生成 rom 一样,详情见目录 2 因此不再赘述 。

 仿真波形如下 row_1 , row_2 , row_3 是指图像的第一、二、三行的数据,Per_href 是行有效信号(受VGA时序的启发,从 rom 中读取数据时设计了行有效和场有效的控制信号,事半功倍,有了利于仿真查错和数据的控制)。从 3 开始就出现了3*3 的像素阵列,这时候就可以求取周围 8 个像素点的平均值,进行均值滤波。

下面这个图是我自己画的 FPGA 如何将矩阵数据处理成并行的像素点,可以结合下面的代码好好理解,这也是精华所在。

正方形红框框起来的是第一个完整的 3*3 矩阵,长方形红框框起来的是并行的像素点,在此基础上就可以求得平均值,进行均值滤波。
从下图也能看到 3*3 矩阵从左往右滑动。
第一个3*3 阵列。
0  1  2   -- >  p11 p12 p13
3  4  5   -- >  p21 p22 p23
6  7  8   -- >  p31 p32 p33

 核心代码如下:

 
reg [5:0]p_11,p_12,p_13;  // 3 * 3 卷积核中的像素点
reg [5:0]p_21,p_22,p_23;
reg [5:0]p_31,p_32,p_33;
reg [8:0]mean_value_add1,mean_value_add2,mean_value_add3;//每一行之和
 
 
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        {p_11,p_12,p_13} <= {5'b0,5'b0,5'b0}   ;
        {p_21,p_22,p_23} <= {15'b0,15'b0,15'b0};
        {p_31,p_32,p_33} <= {15'b0,15'b0,15'b0};
    end
    else  begin
     if(per_href_ff0==1&&flag_do==1)begin
        {p_11,p_12,p_13}<={p_12,p_13,row_1};
        {p_21,p_22,p_23}<={p_22,p_23,row_2};
        {p_31,p_32,p_33}<={p_32,p_33,row_3};
     end
     else begin
         {p_11,p_12,p_13}<={5'b0,5'b0,5'b0};
         {p_21,p_22,p_23}<={5'b0,5'b0,5'b0}
         {p_31,p_32,p_33}<={5'b0,5'b0,5'b0}
     end
   end
end
 
 
 
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        mean_value_add1<=0;
        mean_value_add2<=0;
        mean_value_add3<=0;
    end
    else if(per_href_ff1)begin
        mean_value_add1<=p_11+p_12+p_13;
        mean_value_add2<=p_21+   0   +p_23;
        mean_value_add3<=p_31+p_32+p_33;
    end
end
 
wire [8:0]mean_value;//8位数之和
wire [5:0]fin_y_data; //平均数,除以8,相当于左移三位。
 
assign mean_value=mean_value_add1+mean_value_add2+mean_value_add3;
assign fin_y_data=mean_value[8:3];
 
 

 
sobel 边缘检测 
边缘检测的原理
该算子包含两组 3x3 的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。A代表原始图像的 3*3 像素阵列,Gx及Gy分别代表经横向及纵向边缘检测的图像,其公式如下:

 图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小。

 如果梯度G大于某一阀值则认为该点(x,y)为边缘点。

-------------------------------------------------------------------------------------------------------------------
用的是 边缘检测算法。
难点:(1)掌握了 3*3 像素阵列,Gx 与 Gy 就很好计算了 (注意问题:为了避免计算过程中出现负值,所以将正负值分开单独计算,具体见代码)
        (2)G的计算需要开平方,如何进行开平方运算
Quartus 提供了开平方 ip 核,因此我们直接调用就好了 。

 代码:

reg [8:0] p_x_data ,p_y_data ;  // x 和 y 的正值之和
reg [8:0] n_x_data ,n_y_data ; // x 和 y 的负值之和
reg [8:0] gx_data  ,gy_data  ; //最终结果
 
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
       p_x_data <=0;
       n_x_data <=0;
       gx_data   <=0;
    end
    else if(per_href_ff1==1) begin
        p_x_data <= p_13 + (p_23<<1) + p_33 ;
        n_x_data <= p_11 + (p_12<<1 )+ p_13 ;
        gx_data   <= (p_x_data >=n_x_data)? p_x_data - n_x_data : n_x_data - p_x_data ;
    end
    else begin
         p_x_data<=0;
         n_x_data<=0;
         gx_data <=0;
    end 
end
 
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
       p_y_data <=0;
       n_y_data <=0;
       gy_data   <=0;
    end
    else if(per_href_ff1==1) begin
        p_y_data <= p_11 + (p_12<<1) + p_13 ;
        n_y_data <= p_31 + (p_32<<1) + p_33 ;
        gy_data   <= (p_y_data >=n_y_data)? p_y_data - n_y_data : n_y_data - p_y_data ;
    end
    else begin
        p_y_data <=0;
        n_y_data <=0;
        gy_data   <=0;
   end
end
 
//求平方和,调用ip核开平方
reg [16:0] gxy; // Gx 与 Gy 的平方和
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        gxy<=0;
    end
    else begin
        gxy<= gy_data* gy_data + gx_data* gx_data ;
    end
end
 
wire [8:0] squart_out ;
altsquart  u1_altsquart (     //例化开平方的ip核
    .radical (gxy),
    .q       (squart_out),  //输出的结果
    .remainder()
                       );
 
//与阈值进行比较
reg [15:0] post_y_data_r;
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        post_y_data_r<=16'h00;
    end
    else if(squart_out>=threshold)
         post_y_data_r<=16'h00  ;
    else
         post_y_data_r<=16'hffff  ;
   
end
 
图片的显示
本来是想用 VGA 来显示图片的,由于条件的限制没能实现,最终只能将处理完的数据输出保存在 .txt 文件中,然后借助好友写的网页进行显示。
难点:(1) 如何将数据流输出保存到 .txt 文件中。
        (2) 网页的使用及注意事项
在testbench里加入下面所示代码即可将图片数据保存到 .txt 文本
代码如下:
 
     integer w_file; 
     initial
     w_file = $fopen("data_out_3.txt");   //保存数据的文件名
 
     always @(posedge clk or negedge rst_n) 
     begin 
      if(flag_write==1&&post_href==1)//根据自己的需求定义
        $fdisplay(w_file,"%b",post_y_data);  
      end     
 
------------------------------------------------------------------------------------------------
网页的界面如下,将参数设置好以后就可以显示图片。
下载链接  https://files.cnblogs.com/files/aslmer/aggregrate.zip

 注意:由于此网站是量身定做的,所以只能显示数据格式为RGB565的16位二进制的数才能正确显示,注意不能有分号,正确格式示例如下,必须严格遵守

 

 
 结果展示

小结:均值滤波处理后的图片有明显的黑边,产生这一现象的原因就是生成 3*3 像素矩阵和取像素值时数据有损失造成的,但是这也是可以优化的,后续我会继续努力不断完善。本次只是简单对一幅图像进行边缘检测,我的后续目标是实现图片的实时处理,这又需要学习很多东西了,SDRAM、摄像头驱动等等等,越学习越发现自己知道的实在是太少了,永远在路上,学无止境。希望我的分享能够帮助一些和我一样热爱 FPGA 图像处理的朋友。