Hi,
I'm an FPGA beginner and have trouble understanding how VGA control
signals and VGA interact, and how to correctly generate VGA control
signals (with Verilog) for more complicated specifications:
1. Seemingly, the low portions in horizontal- and vertical- sync signals
correspond to transitioning from one row to the next, and transitioning
from the bottom-right corner to the upper-left corner, respectively. But
is the VGA "controlled" by those low signals? Do those low signals
"tell" the VGA to switch to next row or jump back to the starting point?
2. Are the back porch and front porch there to satisfy setup time and
hold time? Are the durations of porches given in VGA timing table only
required minima (i.e. can I setup porches to be much longer than the
given values in the table?)
3. This is what confuses me the most: From the two continuous
horizontal- and vertical- sync signals, how on earth does the VGA know
(or do I know) EXACTLY which point on screen it is displaying? If timing
is the only factor, does that mean I must pay a lot of attention to
match RPG control signals and h-sync and v-sync signals perfectly? If
the answer is yes, then I have even more problems which I can only
describe using my assignment as an example:
In this assignment we use a built-in 50MHz clock and the pixels of the
VGA is specified to be 800x600. The framerate is specified to be 72Hz.
The VGA timing table gives the following sync signal structures:
h-sync:| 0---back-porch(104)---103 | 104---row display(800)---903 |
904---front-porch(16)---919 | 920__pulse width(120)__1039 |
v-sync:| 0---back-porch(23)---22 | 23---row display(600)---622 |
623---front-porch(37)---659 | 660__pulse width(6)__665 |
This seems to mean that for each pixel in a row on screen I spend 1
clock cycle (20ns) on it. However, for many complicated cases, I would
want to control the color of a pixel depending on its location on screen
and perhaps a lot of additional conditions such as the relation of
current position with another location, certain states, and whatnot.
Now, if the location of the pixel depends on horizontal and vertical
pixel counters, and the color depends further on the location, how can I
match them in time? Also, what if my logic has to spend more than 20ns
to decide the color of a pixel? Will that completely crash the image on
the VGA screen?
Actually I've somehow completed my assignment, but I find my code messy
and I totally have no idea why it worked:
For example, a portion of the assignment required us to show a star that
changes its color every 0.5sec. My implementation looks like:
1 | //----------------pixel counters----------------
|
2 | always@(posedge CLK or posedge RESET) begin
|
3 | if(RESET) h_count <= 11'd 0;
|
4 | else if (h_count >= 11'd 1039) h_count <= 11'd 0;
|
5 | else h_count <= h_count + 11'd 1;
|
6 | end
|
7 |
|
8 | always@(posedge CLK or posedge RESET) begin
|
9 | if(RESET) v_count <= 10'd 0;
|
10 | else if (v_count >= 10'd 665) v_count <= 10'd 0;
|
11 | else if (h_count == 11'd 1039) v_count <= v_count + 10'd 1;
|
12 | else v_count <= v_count;
|
13 | end
|
14 |
|
15 | //----------------h- and v- sync----------------
|
16 | always@(posedge CLK or posedge RESET) begin
|
17 | if(RESET) VGA_HSYNC <= 1'b 0;
|
18 | else VGA_HSYNC <= (h_count >= 11'd 0) & (h_count <= 11'd 919);
|
19 | end
|
20 |
|
21 | always@(posedge CLK or posedge RESET) begin
|
22 | if(RESET) VGA_VSYNC <= 1'b 0;
|
23 | else VGA_VSYNC <= (v_count >= 10'd 0) & (v_count <= 10'd 659);
|
24 | end
|
25 |
|
26 | //----------------a frame counter and a flag----------------
|
27 | always@(posedge CLK or posedge RESET) begin
|
28 | if(RESET) frame_count <= 6'd 0;
|
29 | else if (frame_count >= 6'd 49) frame_count <= 6'd 0;
|
30 | else if(v_count == 10'd 665) frame_count <= frame_count + 6'd 1;
|
31 | else frame_count <= frame_count;
|
32 | end
|
33 |
|
34 | always@(posedge CLK or posedge RESET) begin
|
35 | if(RESET) color_flag <= 1'd 0;
|
36 | else if (frame_count == 6'd 49) color_flag <= ~(color_flag);
|
37 | else color_flag <= color_flag;
|
38 | end
|
39 |
|
40 | //----------------RGB control----------------
|
41 | always@(posedge CLK or posedge RESET) begin
|
42 | if(RESET) VGA_RGB <= 3'b 000;
|
43 | else if(display) begin //display is high when counters in valid range
|
44 | casez({tree, star, snow}) //these are outputs from submodules that decides the "shapes" of objects on screen
|
45 | 3'b ??1: VGA_RGB <= 3'b 111; //white snow
|
46 | 3'b ?10: VGA_RGB <= (color_flag) ? (3'b 110) : (3'b 111);
|
47 | //switching between yellow and white
|
48 | 3'b 100: VGA_RGB <= 3'b 010; //green tree
|
49 | default: VGA_RGB <= 3'b 001; //blue background
|
50 | endcase
|
51 | end
|
52 | else VGA_RGB <= 3'b 000; //for transitions
|
53 | end
|
It seems to me that my h_count and v_count directly decides my VGA_HSYNC
and VGA_VSYNC. But my VGA_RGB depends at least on color_flag, which
further depends on frame_count, which depends on h_count and v_count.
Shouldn't that cause delay of a few clock cycles? The code was
synthesized and did produced what I wanted to display. So how on earth
did my VGA_RGB sync with VGA_HSYNC and VGA_VSYNC in time??? Do I
overthink this issue? Or was I just lucky? what did I miss?