2014-11-22 65 views
-1

我正在尝试在VHDL中创建一个VGA驱动程序。如何修复此代码中的时钟保持?

我打算用640x480 @ 60 Hz,所以我需要25 MHz和31.5 KHz的时钟。过程由50 MHz时钟驱动,并产生25 MHz时钟。在25 MHz时钟的每个节拍上,h_counter通过过程h_sync递增,当它达到某个值(H_FRONT + H_SYNC - 1)时,divider_v过程被触发并在短时间内将clock_v设置为1。

Quartus II的时序分析失败,并出现一个警告:不能实现最小设置并保持沿着1条路径的要求时钟编制报告中的时钟保持部分指出v_counter的MSB是罪魁祸首,最小松弛时间为-0.050ns。第二低的松弛时间是0.218ns,这很好。

我试图使用长状态1为clock_v与简短的0状态和最小松弛时间增加到-0.019纳秒,这仍然是不可接受的。

据我所知,保持时钟问题意味着输入在被正确处理之前被改变,所以我试图让1和0出现大致相同的时间段。令我惊讶的是,超过40条路径变成了红色,同样的错误。

注释掉v_clock流程解决了这个问题。

为什么MSB的松弛时间比其他位高很多?我能做些什么来解决这个问题?

这里是我的代码:

  • 来源::v_counter[9]
  • 为:v_counter[9]
  • 从时钟:clock
  • 时钟出现故障路径的

    library ieee; 
    use ieee.std_logic_1164.all; 
    
    library Famikon; 
    use Famikon.Types.all; 
    use Famikon.VgaNames.all; 
    
    
    entity VgaDriver is 
        port (
         -- inputs 
         clock_50: in STD_LOGIC; -- 50 MHz 
         reset: in bit; -- '1' resets 
         r, g, b: in screen_pixel; -- bit_vector subtype 
    
         -- outputs 
         vga_x, vga_y: out hw_coord; -- integer subtype 
         vga_drawing: out bit; 
         hw_r, hw_g, hw_b: out hw_pixel; -- bit_vector subtype 
         vga_hsync, vga_vsync: out bit; 
         vga_blank, vga_clock: out bit 
        ); 
    end entity; 
    
    
    architecture Arch of VgaDriver is 
        signal clock_h, clock_v: std_logic; 
        signal h_counter, v_counter: vga_counter; -- integer subtype 
        signal h_coord, v_coord: hw_coord; -- integer subtype 
        signal h_active, v_active: bit; 
    begin 
    
        -- some irrelevant code -- 
    
        h_active <= '1' when (h_counter >= H_BLANK) else '0'; 
        v_active <= '1' when (v_counter >= V_BLANK) else '0'; 
    
    
        divider_h: process (clock_50) begin 
         if (rising_edge(clock_50)) then 
          clock_h <= not clock_h; 
         end if; 
        end process; 
    
    
        divider_v: process (h_counter) begin 
         if (h_counter /= H_FRONT + H_SYNC - 1) then 
          clock_v <= '0'; 
         else 
          clock_v <= '1'; 
         end if; 
        end process; 
    
    
        h_clock: process (clock_h, reset) begin 
         if (rising_edge(clock_h)) then 
          if (reset = '1') then 
           h_counter <= 0; 
          elsif (h_counter = H_TOTAL - 1) then 
           h_counter <= 0; 
          else 
           h_counter <= h_counter + 1; 
          end if; 
         end if; 
        end process; 
    
    
        v_clock: process (clock_v, reset) begin 
         if (rising_edge(clock_v)) then 
          if (reset = '1') then 
           v_counter <= 0; 
          elsif (v_counter = V_TOTAL - 1) then 
           v_counter <= 0; 
          else 
           v_counter <= v_counter + 1; 
          end if; 
         end if; 
        end process; 
    
    
    end architecture; 
    

    详细:clock

  • 要求的保持关系:0.000纳秒
  • 所需最短时间P2P:0.618纳秒
  • 实际Shortes P2P时间:0.568纳秒
  • 最小时差:-0.050纳秒

v_counterbit_vector(9 downto 0)。当我使用定位于此路径上的设计时,Quartus指向v_clock过程的第一行(其中一个与rising_edge(clock_v)一致)。

还有一个关于波纹时钟警告,其中提到的所有h_counter位,clock_h和三个门控时钟:Equal0Equal0~1Equal0~0

+0

与您的问题并不完全相关,但实际上,您需要'640x480 @ 60Hz'的25.175 MHz时钟[来源](http://tinyvga.com/vga-timing/[email protected])。我建议你使用内部的PLL来产生这个时钟(如果你有任何可用的话)。 – HeyYO 2014-11-23 00:05:32

+0

VGA的时间容限是根据显示器的水平和垂直速率定义的。我在一个月前检查了几个关于另一个VGA问题的规格,25 MHz似乎让您在我检查的显示器的容差范围内。 – user1155120 2014-11-23 02:24:56

回答

3

如果您提供了失败路径的起点和终点,它将有所帮助。看起来主要问题是您生成不同的时钟,并且跨域时序问题或不完整的约束建立不同域之间的关系。据推测reset来自clock_50域,它不应该直接在其他两个域使用。更强大的解决方案将使用同步启用的单个时钟来获得与clock_vclock_h相同的效果。

当生成时钟是必要的时,您不应该尝试在FPGA架构中构建它们,而是使用板载PLL/DLL来管理它们。域之间的偏差可以更好地控制,定时分析器可以更好地处理这种情况。每个域都需要有自己的复位信号,它与自己的时钟同步。

注册v_activeh_active也可能是一个好主意,以便将比较逻辑从它们输入的内容中分离出来。另外,您正在使用同步重置,因此无需将它们放入敏感列表中。

+0

这是从'v_counter [9]'到'v_counter [9]'的路径,我在这个问题中增加了更多细节。 'reset'连接到硬件开关。我最初尝试在'h_clock'过程中增加'v_counter',但是引入了锁存器('v_counter'如果它没有增加,它必须保存它的值)。 “register v_active and h_active”是什么意思? – gronostaj 2014-11-23 11:36:19

+0

您没有正确设计您的设计。代码中没有名为'clock'的时钟。您只是使用默认名称。按照我的建议切换到单个时钟,并生成同步控制信号,以所需速率脉冲模拟'clock_v'和'clock_h'。将这些控制台关闭。您也不应该将外部世界的异步信号引入同步逻辑,而不同步它们。这适用于重置以及任何其他信号。通过一对FF发送重置。 – 2014-11-23 17:23:49

+0

使用>和<布尔比较生成进行链比相等比较慢。 '* _active'信号由组合逻辑驱动,它会将延迟添加到任何连接它们的地方。尽可能通过插入寄存器来隔离这些延迟通常是一个好主意。在现代设备上,在50MHz频率上这不是必要条件,但这是最佳实践,并且在更高速度下变得更重要。 – 2014-11-23 17:30:46

2

因为你不包括你的Famikon库包,有人不得不查找VGA时间。 (您的代码示例不是Minimal, Complete, and Verifiable example)。

詹宁斯一些东西让你的设计,分析了添加这些:

package Types is 
    subtype screen_pixel is bit_vector (3 downto 0); 
    subtype hw_coord  is natural range 0 to 1023; 
    subtype hw_pixel  is bit_vector (3 downto 0); 
    subtype vga_counter is natural range 0 to 1023; 
end package; 
package VgaNames is 
    constant H_FRONT: natural range 0 to 1023 := 16; 
    constant H_SYNC: natural range 0 to 1023 := 96; 
    constant H_BACK: natural range 0 to 1023 := 48; 
    constant H_BLANK: natural range 0 to 1023 := H_FRONT + H_SYNC + H_BACK; 
    constant H_VISIBLE: natural range 0 to 1023 := 640; 
    constant H_TOTAL: natural range 0 to 1023 := H_BLANK + H_VISIBLE; 

    constant V_FRONT: natural range 0 to 1023 := 10; 
    constant V_SYNC: natural range 0 to 1023 := 2; 
    constant V_BACK: natural range 0 to 1023 := 33; 
    constant V_BLANK: natural range 0 to 1023 := V_FRONT + V_SYNC + V_BACK; 
    constant V_VISIBLE: natural range 0 to 1023 := 480; 
    constant V_TOTAL: natural range 0 to 1023 := V_BLANK + V_VISIBLE; 
end package; 

你也注意到,首先上市的消隐间隔:

h_active <= '1' when (h_counter >= H_BLANK) else '0'; 
v_active <= '1' when (v_counter >= V_BLANK) else '0'; 

你要么会做偏移算术运算vga_x和vga_y或使用单独的计数器。这可以通过在h_counter和v_counter两处启动显示器的非消隐部分为0来解决。

但是,这不负责vcount [9]设置时间问题。

还有其他问题。

divider_v: process (h_counter) begin 
    if (h_counter /= H_FRONT + H_SYNC - 1) then 
     clock_v <= '0'; 
    else 
     clock_v <= '1'; 
    end if; 
end process; 

这看起来像它是负责涟漪时钟。你试图通过组合逻辑来产生clock_v。出于某些有效的原因,您不应这样做 - h_counter位和门用来识别比较之间可能存在非对称延迟,即使使用LUT也存在多级组合逻辑,并且路由延迟可能不匹配。你的clock_v是否工作取决于布局的变幻莫测,并且它想要被注册(可能与clock_h)。

对于回答者来说,知道供应商是谁的目标设备以及实际的警告和错误消息是非常有帮助的。你可能会发现固定clock_v已经足够了,但它可能不是,在这种情况下,我会想像Kevin表示它缺乏适当地限制你的设计。

有一种老式VHDL VGA时序发生器,最近出现在堆栈Exchange问​​题上(请参阅VHDL VGA sync circuit)。它来自作者的companion website上可用的代码清单压缩下载中Pong P. Chu的书“FPGA原型化VHDL实例,XILINX SPARTAN-3版本”的第12章,文件名list_ch12_01_vga_sync.vhd。 正如Brian Drummond指出,对于那些不愿意使用编辑器搜索或打印输出的人来说,阅读起来很难,因此将横向和纵向计数器分布在三个过程语句中(原始设计规范的视图对于某些口味而言过于单调,并且似乎过多流程)。

Brian还有一个附加答案,它提供了一个组合过程的例子,并显示了垂直计数器在水平计数器中的嵌套。它还显示从“0000000000”(0)开始的非消隐水平和垂直间隔。您可能会注意到,Brian还对与h_active和v_active保持未注册的等效信号进行了评论。