【问题标题】:How do VGA control signals work in Verilog/HDL?VGA 控制信号如何在 Verilog/HDL 中工作?
【发布时间】:2015-12-30 04:52:41
【问题描述】:

我是 FPGA 初学者,无法理解如何控制 VGA 信号与VGA交互,以及如何正确生成VGA控件 信号(使用 Verilog)以获得更复杂的规范:

  1. 看起来,水平和垂直同步信号中的低频部分 对应于从一行过渡到下一行,以及过渡 分别从右下角到左上角。但 VGA是由那些低信号“控制”的吗?做那些低信号 “告诉” VGA 切换到下一行还是跳回起点?

  2. 后廊和前廊是否满足设置时间和 保持时间?门廊的持续时间是否仅在 VGA 时序表中给出 所需的最小值(即我可以将门廊设置为比 时间表中的给定值?)

  3. 这是最让我困惑的:从两个连续的 水平和垂直同步信号,VGA到底是怎么知道的 (或者我知道)它在屏幕上显示的究竟是哪个point?如果计时 是唯一的因素,这是否意味着我必须非常注意 完美匹配 RPG 控制信号和水平同步和垂直同步信号?如果 答案是肯定的,那么我有更多的问题,我只能 以我的作业为例进行描述:

在这个作业中,我们使用 FPGA(Spartan 入门板)的内置 50MHz 时钟,VGA 的像素被指定为 800x600。帧速率指定为 72Hz。

VGA时序表给出了以下同步信号结构:

水平同步: | 0---后廊(104)---103 | 104---显示(800)---903 | 904---前廊(16)---919 | 920__脉冲宽度(120)__1039 |

垂直同步: | 0---后廊(23)---22 | 23---显示(600)---622 | 623---前廊(37)---659 | 660__脉宽(6)__665 |

这似乎意味着对于屏幕上一行中的每个像素,我花费 1 时钟周期(20ns)就可以了。但是,对于许多复杂的情况,我会 想要根据像素在屏幕上的位置来控制像素的颜色 也许还有很多附加条件,例如 当前位置与另一个位置,某些状态等。现在,如果像素的位置取决于水平和垂直像素计数器,并且颜色进一步取决于位置,我该如何及时匹配它们?另外,如果我的逻辑必须花费超过 20ns 来决定像素的颜色怎么办?这会使 VGA 屏幕上的图像完全崩溃吗?

实际上我已经完成了我的任务,但是我发现我的代码很乱 我完全不知道它为什么会起作用:

例如,部分作业要求我们展示一颗星 每 0.5 秒改变一次颜色。我的实现如下:

//----------------pixel counters----------------
always@(posedge CLK or posedge RESET) begin
    if(RESET) h_count <= 11'd 0;
    else if (h_count >= 11'd 1039) h_count <= 11'd 0;
    else h_count <= h_count + 11'd 1;
end

always@(posedge CLK or posedge RESET) begin
    if(RESET) v_count <= 10'd 0;
    else if (v_count >= 10'd 665) v_count <= 10'd 0;
    else if (h_count == 11'd 1039) v_count <= v_count + 10'd 1;
    else v_count <= v_count;
end

//----------------h- and v- sync----------------
always@(posedge CLK or posedge RESET) begin 
  if(RESET) VGA_HSYNC <= 1'b 0;
  else VGA_HSYNC <= (h_count >= 11'd 0) & (h_count <= 11'd 919);
end

always@(posedge CLK or posedge RESET) begin 
  if(RESET) VGA_VSYNC <= 1'b 0;
  else VGA_VSYNC <= (v_count >= 10'd 0) & (v_count <= 10'd 659);
end

//----------------a frame counter and a flag----------------
always@(posedge CLK or posedge RESET) begin
    if(RESET) frame_count <= 6'd 0;
    else if (frame_count >= 6'd 49) frame_count <= 6'd 0;
    else if(v_count == 10'd 665) frame_count <= frame_count + 6'd 1;
    else frame_count <= frame_count;
end

always@(posedge CLK or posedge RESET) begin
    if(RESET) color_flag <= 1'd 0;
    else if (frame_count == 6'd 49) color_flag <= ~(color_flag);
    else color_flag <= color_flag;
end

//----------------RGB control----------------
always@(posedge CLK or posedge RESET) begin
    if(RESET) VGA_RGB <=  3'b 000;
    else if(display) begin //display is high when counters in valid range
        casez({tree, star, snow})  //these are outputs from submodules that decides the "shapes" of objects on screen
            3'b ??1: VGA_RGB <= 3'b 111;  //white snow
            3'b ?10: VGA_RGB <= (color_flag) ? (3'b 110) : (3'b 111);
                //switching between yellow and white
            3'b 100: VGA_RGB <= 3'b 010;  //green tree
            default: VGA_RGB <= 3'b 001;  //blue background
    endcase
  end
  else VGA_RGB <= 3'b 000;  //for transitions
end

在我看来,我的 h_count 和 v_count 直接决定了我的 VGA_HSYNC 和 VGA_VSYNC。但是我的 VGA_RGB 至少取决于 color_flag,它进一步取决于 frame_count,它取决于 h_count 和 v_count。这不应该导致几个时钟周期的延迟吗?该代码是可合成的,并且确实产生了我想要显示的内容。但是我的 VGA_RGB 究竟是如何与 VGA_HSYNC 和 VGA_VSYNC 及时同步的???我是不是在想这个问题?还是我只是幸运?我错过了什么?

【问题讨论】:

  • 要部分回答您的问题,通常您希望有一些内存块(芯片上或芯片外)来存储您的像素数据。这样,您可以独立于 VGA 控制器对其进行操作(进行更改、更新等),并且可以根据您的需要/需要进行任何更改。

标签: verilog fpga system-verilog


【解决方案1】:

您的大部分问题都可以通过 VGA 是一种模拟标准来解释,该标准最初设计用于在模拟设备上运行。水平同步和垂直同步脉冲只是简单地触发它们各自的偏转线圈回到它们的起始位置,而前廊和后廊说明了光束在屏幕可见部分之外开始和结束的事实。

在准确性方面,它比以前更好了:在过去的几年里向模拟显示器发送一个定时错误的 VGA 信号实际上可能会损坏它。现在这一切都改变了,LCD 等的驱动电路能够以任意刷新率检测和显示各种分辨率。根据我的经验,尽管您拥有的余地比您想象的要小,并且非常依赖于显示设备的品牌和型号……他们中的许多人甚至在其用户手册中列出了略有不同的时间安排!如果您想确保您的电路能够在您的测试仪运行它的设备上工作,那么您应该尽可能准确地坚持“官方”解决方案之一。

就每像素时序而言,是的,800x600x72Hz 信号需要 50MHz 时钟,因此您有 20nS 的时间来获取像素数据(也就是说我不能 100% 确定您的同步和门廊时序是否正确,它们与我过去成功使用过的VGA Timings 不同)。如果 20nS 还不够,那么您将需要使用多个电路,例如一个用于奇数像素,另一个用于偶数像素。或者,您可以实现管道阶段,例如对于您在周期 X 输出的像素,您在周期 X-1 从 ROM 读取其值并计算在周期 X-2 读取的地址。我过去使用的另一个技巧是使用 2 行 RAM 对显示器进行双重缓冲,即在任何给定的行上,您都直接从一个缓冲区绘制,同时写入下一个缓冲区;这为您提供了更多时间来渲染每一行,但通常会增加渲染和显示之间单独时钟域的额外复杂性。

【讨论】:

  • 非常感谢您花时间回答我的问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-20
相关资源
最近更新 更多